Author: Dipl.-Ing. Wilfried Klaas
Board: Arduino Uno, Arduino Leonardo, ATTiny45/85
Gerade im Rennbootsektor wird gerne mit einer Pistolenfernsteuerung und Brushless-Flugreglern gearbeitet. Leider haben viele Regler dann das Problem den Nullpunkt der Pistolensteuerung (der ja in der Mitte liegt) nicht oder nicht richtig erkennen zu können. Bei teureren Sendern kann man das manchmal in der Software korrigieren. Den günstigeren Sendern fehlt meisten eine solche Funktion.
Weiterhin ist es sehr ärgerlich, daß viele Servos zwar mit z.B. 50° angegeben werden, diese aber an der eigenen Anlage dann doch nicht schaffen. Das 2. Programm erweitert den Weg des Servos. Hierbei ist jedoch Vorsicht geboten, denn schnell kann der Servo an die mechanischen Grenzen stossen…
Beide Programme werden per Jumper umgeschaltet.
Hier mal eine kurze Tabelle mit den Auswirkungen der Servo-Funktion.
GT-2 von Conrad
Servo | ohne Modul | mit Modul |
---|---|---|
HK16178 | 90° | 135° |
Graupner C 508 | 95° | 150° |
Blue Bird BMS 706-MG | 90° | - |
MP Tiger Digi 4 | 95° | 140° |
GT-3
Servo | ohne Modul | mit Modul |
---|---|---|
TGY 9018MG | 90° | 160° |
Spektrum DX3S mit SR3000
Servo | ohne Modul | mit Modul |
---|---|---|
HK16178 | 70° | 135° |
Graupner C 508 | 85° | 125° |
Blue Bird BMS 706-MG | 75° | 115° |
MP Tiger Digi 4 | 80° | 120° |
Servo | ohne Modul | mit Modul |
---|---|---|
Conrad S-811MG | 70° | 120° |
Acmos AS-12 | 90° | 150° |
Die angegebenen Werte sind natürlich ohne Gewähr. Sie unterscheiden sich auch von RC Anlage zu RC Anlage.
Aber wir können ja programieren. Also flux ein kleines Programm geschrieben, was den eingeschränkten Bereich des Abzugsknüppel auf den erweiterten Bereich des Reglers abbildet. Nebenbei habe ich auch gleich ein 2. Programm untergebracht, welches den Servoweg vergrößert. Der Teil ist aber mit Vorsicht zu behandeln. Denn nicht jeder Servo verträgt ein Signal von 700..2200us.
Manche Servos können dadurch mechanisch an ihre Grenzen stossen. Also das ganze ist auf eigene Gefahr.
Die Software selber macht nur minimal Gebrauch von ext. Bibliotheken und passt sogar in eine Tiny45.
Wir benutzen selber auch keinen Timer oder Interrupt. Der Servo muss aber alle 20ms ein Signal bekommen. Das machen wir dadurch, daß wir einfach das Empfängersignal als Zeitbasis verwenden. Dabei machen wir folgende Annahmen.
Das Empfängersignal kommt alle 20ms und ist max. 2ms lang. (Ein Servoimpuls) Diesen werten wir mit der pulsIn (poll in der RCReceiver Bibliothek) Funktion aus. Danach berechnen wir den aktuellen Servowert. Dann setzen wir den Servopin auf 1, warten mit der delayMicroseconds() die angegebene Zeit und setzen dann den Pin wieder auf 0. Weil gerade das Setzen des Pin Zeitkritisch ist, verwende ich direkte Portzugriffe und schalte beim Servo den Interrupt aus. (PORTB …)
Das ganze läuft bei mir auf einem ATTiny 85 mit internen 16MHz.
Und wie immer, bei Fragen, einfach fragen.
UPDATE 18.11.2013: Hier jetzt die getestetet Version, die auch an meine Betatester raus gegangen ist.
Platinen, mit oder ohne programmierte Controller, Bausätze und evt. auch fertige Module gibt's bei mir zum Selbstkostenpreis. Das ganze sieht so aus:
Anleitung rev 1 Anleitung zur rev 2
#include <makros.h> #include <RCReceive.h> /* FESC_Small.ino - Version 0.1.0 Copyright (c) 2013 Wilfried Klaas. All right reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* Steuerung eines Flug ESC mittels Car Fernsteuerng für den ATTiny x5. Der Empfänger wird vom Pin 2 gelesen, der Ausgang ist auf PB0 was in Arduino Pin 0 entspricht. Die Nullpunkte ist auf 1500us festgelegt. Es gibt 2 Modi, die über einen Jumper zwischen 3 und 4 (Pin 2/3 am Controller) angewählt werden können. Mode 1: FlugESC an CarRc Bei Vorwärtsfahrt (1,5ms-2ms) wird das Motorsignal gedehnt, also in den Bereich 1ms-2ms gebracht, und an den Regler geschickt. Bei Rückwärtsfahrt wird immer ein 1ms breites Signal an den Regler geschickt. Ebenso als Failsafe bei Empfängersignalverlust. Zus. blinkt dann auch noch die LED. Mode 2: Servowegerweiterung Das Empfängersignal (1ms-2ms) wird, ähnlich wie das Motorsignal, gedehnt, also in den Bereich 0,5ms-2,5ms gebracht, und an den Servo geschickt. Failsafe bei Empfängersignalverlust ist hier 1,5ms. Zus. blinkt dann auch hier die LED. */ // Definitionen // Empfängeranschluss const byte PIN_RC = 2; // Servoausgänge const byte SERVO0 = 0; const byte SERVO1 = 1; // freie Ein/Ausgänge const byte AUX1 = 3; const byte AUX2 = 4; // Ein paar schöne Makros. #ifndef between #define between(a,x,y) ((a >=x) && (a <= y)) #endif #define AUXOn(aux) \ PORTB |= _BV(aux) // A: digitalWrite(aux, 1) #define AUXOff(aux) \ PORTB &= ~_BV(aux) // A: digitalWrite(aux, 0) #define LEDOn() \ PORTB |= _BV(AUX1) // A: digitalWrite(LED, 1) #define LEDOff() \ PORTB &= ~_BV(AUX1) // A: digitalWrite(LED, 0) #define ServoOn() \ PORTB |= _BV(SERVO0) // A: digitalWrite(SERVO0, 1) #define ServoOff() \ PORTB &= ~_BV(SERVO0) // A: digitalWrite(SERVO0, 0) #define Blink() \ if ((millis() % blinkconst) > (blinkconst / 2)) { \ LEDOn(); \ } \ else { \ LEDOff(); \ } \ // ---------------------------------------- // Hier geht's los // ---------------------------------------- boolean servomode = false; word blinkconst = 1000; RCReceive rcReceiver; void setup() { // Einstellung der Ports // 0 und 1 sind Ausgänge für Servos // 2,3 und 4 sind die Eingänge DDRB = _BV(AUX1) | _BV(SERVO0) | _BV(SERVO1); PORTB |= _BV(AUX2); // Arduinoersatz /* A: pinMode(SERVO0, OUTPUT); pinMode(SERVO1, OUTPUT); pinMode(AUX1, OUTPUT); pinMode(AUX2, INPUT_PULLUP); */ delay(500); // Testen, ob Servo- oder FlugMode AUXOff(AUX1); // A: digitalWRite(AUX1, 0) servomode = ((PINB & _BV(AUX2)) == 0); // A: servomode = (digitalRead(AUX2) == 0); blinkconst = servomode ? 500 : 1000; rcReceiver.attach(PIN_RC); delay(500); } // ---------------------------------------- // Hauptprogramm // ---------------------------------------- word value = 0; byte valueCount = 0; void loop() { // Aktuellen RC-Wert lesen rcReceiver.poll(); if (!rcReceiver.hasError() && rcReceiver.hasNP()) { LEDOff(); doWork(); } else if (rcReceiver.hasError()) { // Fehlerbehandlung failsafe oder sowas... Blink(); servomode ? value = 1500 : value = 1000; cli(); ServoOn(); delayMicroseconds(value); ServoOff(); sei(); } } inline void doWork() { value = rcReceiver.getMsValue(); // value = pulseIn(PIN_RC, HIGH, 25000); // Timeout 25ms if (servomode) { // Servo Modus // alle gültigen Signale werden verarbeitet if (between(value, 900, 2100)) { value = constrain(value, 1000, 2000); // value = ((value - 1000) * 2) + 500; // Im Arduino könnte man auch schreiben value = map(value, 1000, 2000, 700, 2300); } else { // Failsafe value = 1500; } } else { // FlugEsc Modus // Nur die Vorwärtsfahrt (> 1500 us) wird berücksichtigt. if (between(value, 1500, 2200)) { value = constrain(value, 1500, 2000); value = ((value - 1500) * 2) + 1000; // Im Arduino könnte man auch schreiben // A: value = map(value, 1000, 2000, 500, 2500); } else { // Failsafe value = 1000; } } cli(); ServoOn(); delayMicroseconds(value); ServoOff(); sei(); }
Ein großer Arduino war mir für dieses Miniprojekt wirklich zu groß, also hab ich das ganze Projekt nicht für einen normalen Arduino gemacht sondern für einen ATTiny85. Das ist eine der kleinstes AT Controllerversionen. Der Chip hat nur 8 Pins, davon kann man 5 (ohne Reset und ISP Möglichkeit 6) frei programmieren. Leider kann man auf dem kleinen nicht die normale Servo Bibliothek verwenden, da im Chip kein 16-Bit Timer vorhanden ist.
Aber wie kriegen wir nun dsa Programm in den Chip?
Das ist jetzt etwas tricky. Wir brauchen dazu
So hier mal die neue Schaltung und das Platinenlayout.
flightesc_rev1.pdf
Platinen, Bausätze gibt's bei mir auf Anfrage. Fertiggeräte gibt es wegen der WEEE leider nicht.
Zum Programmieren gibt es dann einen kleinen Trick.(Quelle: Programming an ATtiny w/ Arduino 1.0)
Zunächst stellt man das richtige Board ein, also bei uns einen Dem ATtiny85 (internal 16 MHz PLL; 2.7 V BOD).
Allerdings gibt's den nicht. Es gibt nur die 4.7V BOD Variante. Leider startet der COntroller dann auf unserem Board nciht, weil durch die Verpolungsschutzdiode nur 4,4V am Controller anliegen. Deswegen muss man den Typ selber in die boards.txt eintragen. Zu finden ist die Datei im hardware/attiny/boards.txt.
Den Text einfach zur vorhandenen Datei hinzufügen…
attiny85at162p.name=Dem ATtiny85 (internal 16 MHz PLL; 2.7 V BOD) attiny85at162p.bootloader.low_fuses=0xC1 attiny85at162p.bootloader.high_fuses=0xD5 attiny85at162p.bootloader.extended_fuses=0xFF attiny85at162p.upload.maximum_size=8192 attiny85at162p.build.mcu=attiny85 attiny85at162p.build.f_cpu=16000000L attiny85at162p.build.core=arduino:arduino attiny85at162p.build.variant=tiny8
Für die Arduino 1.5.x Umgebung lautet der Pfad hardeware/attiny/avr/boardts.txt
attiny.menu.clock.internal162=16 MHz BOD 2,7(internal) attiny.menu.clock.internal162.bootloader.low_fuses=0xc1 attiny.menu.clock.internal162.bootloader.high_fuses=0xd5 attiny.menu.clock.internal162.bootloader.extended_fuses=0xff attiny.menu.clock.internal162.build.f_cpu=16000000L
Dann wählt man den richtigen Programmer. (Man kann übrigens auch einen normalen Arduino als Programmer programmieren…)
Jetzt muss man zunächst einen Bootloader programmieren.
Ja, auch wenn tatsächlich keiner eingebrannt wird, weil wir keinen brauchen. Aber dadurch werden im Chip die richtigen Einstellungen gemacht. (Nennt man Fuses…)
Und jetzt kann man ganz normal das Programm mit der IDE programmieren.
Das ganze Projekt kann man dann direkt in die Leitung zum ESC stecken.
Viel Spass damit.
Willie