DIY Lost-Plane-Finder für S-Bus

MarenB

Runter kommen sie immer!
#1
Hallo miteinander,

nachdem neulich mein AP meinte, meinen Teksumo im Gebüsch versenken zu müssen und wir eine Weile suchen durften, hat mir ein "Wiesenkollege" (*wink* @ m2m) spontan einen kleinen Piezo-Piepser in die Hand gedrückt.

Jetzt nutze ich in dem Flieger einen FrSky X6R Empfänger, dessen Servo-Ausgänge leider alle schon belegt sind. Es blieb also nur der S-Bus, der ja glücklicherweise noch 10 weitere Kanäle bereit hält :)

Gerade eben ist deshalb also ein Programm für einen ATtiny13 entstanden, das den S-Bus über eine SW-Uart auslesen und abhängig vom Wert des Kanal 12 oder dem Failsafe-Bit den Piepser im 2Hz-Intervall ansteuern soll.
Der kleine Tiny sollte sich fast auf die Rückseite des Piepsers kleben lassen, so dass das ganze Ensemble schön klein wird.
Es könnte daher vielleicht sinnvoll sein, die Pin-Zuordnungen noch etwas zu verändern, so dass man vielleicht ganz ohne Drahtbrücken auskommen kann, in dem man die Beinchen vom µC direkt an die des Piepsers lötet. Habe bloß die Komponenten gerade nicht hier, um das zu testen...

Das Programm ist an sich noch ungetestet, ich werde das hier ggf. weiter updaten. Auch wäre es möglich, auf andere Kanäle als den 12. zu reagieren. Ich habe den Kanal im Hinblick auf den L9R ausgewählt, der ja nur 12 empfängt.

Arduino-Jünger mögen beim Anblick des Codes evtl. irritiert sein :) - das ist Bascom. Es gibt davon eine kostenlose Testversion die alles bietet, was der kleine Tiny kann. Wer möchte, kann also gerne (auch ohne die Vollversion zu kaufen) an dem Programm rumbasteln, Bugs eliminieren, weitere Funktionen implementieren, auf einen anderen Kanal umschreiben, etc.

Wenn sich herausstellt, dass es so läuft wie gehofft, stelle ich gerne eine fertige Hex-Datei ein, die dann jeder flashen können sollte, der im Besitz eines ISP-Interfaces ist - auch ganz ohne Bascom.

Bedenken habe ich im Augenblick eigentlich nur im Hinblick auf das Zusammenspiel von Software UART und internem RC-Oszillator. Letzterer ist durchaus temperaturempfindlich, weshalb es mEn hier Probleme geben könnte. Falls das nicht zuverlässig laufen sollte, würde ich wohl doch auf einen billigen HK 6A ESC als Plattform wechseln, darauf läuft mein S-Bus-Decoder schon problemlos als Lichtschalter. Aber dazu später mehr.

Nu erstmal der Code:

Habe den alten, nicht laufenden Kram hier oben entfernt. Die aktuelle Version gibt es weiter unten.
 
Zuletzt bearbeitet:

MarenB

Runter kommen sie immer!
#3
Inzwischen habe ich einige Stunden lang getestet, programmiert, und gebastelt - das klappt so leider nicht.

Der ATtiny13 wollte definitv den Datenstrom nicht lesen. Da ein ATmega8 auf meinem Testboard das aber problemlos tut, hatte ich den ungenauen internen Taktgeber im Verdacht. Ich hatte noch einen ATtiny85 hier und der lässt sich per externem Quarz takten. Sollte gehen, dachte ich, jedoch - Pustekuchen! Der will auch nicht.
Ich lese gerade mit dem ATtiny85 auf einer software serial den Datenstrom vom X8R aus und gebe ihn im gleichen Format auf einem anderen Pin aus, an welchem wiederum der erwähnte ATmega8 hängt. Der wiederum übersetzt das eingehende in einen PC-tauglichen seriellen Datenstrom und gibt ihn an der HW seriell aus. Da kommt aber leider nur Blödsinn an.
Ich habe Quarze mit 10Mhz und 16Mhz ausprobiert, dem VCC-Pin einen Abblockkondensator (100nF) gegönnt, es hilft alles nichts.
Da das ganze nur schön gewesen wäre, wenn man den tiny direkt auf den Piepser hätte löten können, ohne eine größere Anzahn externer Bauteile zu benötigen, stampfe ich diesen Versuch ein und schwenke auf den HK6A ESC um. Der bringt mir dann gleich noch zwei weitere Kanäle für andere Spielereien und hat ebenfalls eine überschaubare Größe.
Sorry!
 

pete1990

Erfahrener Benutzer
#4
Bei einem der Tiny's gabs mal so ein Ding, dass das Clock-Divide-by-8 Fuse Standardmäßig aktiv ist. Ich meine mich zu errinern das dies beim Attiny13 der Fall war. Das könntest du mal prüfen.

Grüße,
Peter
 

MarenB

Runter kommen sie immer!
#5
Aaargh. Jupp, das stimmt! Sogar bei beiden tinys...
Allerdings...ich hab direkt zu Anfang des Programms einen 5x500ms Test-Piepser eingebaut - und das passt, der ist nicht 8x langsamer als erwartet :/
Egal, ich schalte das Ding mal aus, vielleicht klappt's ja dann. *grummel* gerade alles weggeräumt...

Nachtrag:

Danke, Peter!!!!! Dein Tipp war goldrichtig. Der Tiny13 taktet zwar wohl trotz allem zu ungenau, der 85er macht's jetzt aber ganz passabel.

Ich habe noch einen Ausgang für eine LED hinzugefügt, die kann Aufschluss darüber geben, ob S-Bus-Signale empfangen werden oder nicht.

Getestet habe ich sowohl X8R als auch L9R. Kanal 12 auf etwas mehr als die Hälfte oder Verlust des Signals vom Sender und schon hört sich das Flugzeug an wie die Müllabfuhr im Rückwärtsgang ;)

Folgend der letzte Code:

Code:
'Dieses Programm für den Atmel ATtiny85 liest den RC-Kanal Nr. 12 aus einem Futaba S-Bus-Protokoll aus (auch FrSky)
'und aktiviert abhängig vom Kanalwert oder dem Failsafe-Bit einen Intervall-Piepser (f~1Hz)
'damit ein verloren gegangenes Modell leichter gefunden werden kann.

'Es wird ein externes Quarz mit 16MHz als Taktgeber verwendet.
'Als Piepser dient hier ein Piezo-Signalgeber mit Dauerton, das Intervall wird vom ATtiny erzeugt.

'Anschlussbelegung des ATtiny85:
'Pins 2&3: 16Mhz Quarz + Kondensatoren gegen Masse
'Pin 5: Signalgeber (+)
'Pin 4: Signalgeber (GND) & S-Bus (GND) & LED (Kathode)
'Pin 6: Status-LED Anode über Vorwiederstand (zeigt S-Bus-Empfang an)
'Pin 7: S-bus(data)
'Pin 8: S-Bus (+5V)

'Das Programm ist frei verfügbar und darf verändert und weitergegeben werden.
'by MarenB, 10.10.2014


'*************
'Programmstart
'*************

$regfile = "attiny85.dat"
$crystal = 16000000                                         '16Mhz Quarz
$hwstack = 40
$swstack = 16
$framesize = 32


'Software UART für S-Bus-Empfang konfigurieren
Open "COMB.2:100000,8,E,2, inverted" For Input As #1        'Serielle Software-RX konfigurieren für S-BUS

'Timer für Intervall-Buzzer konfigurieren
Config Timer0 = Timer , Prescale = 1024
On Timer0 Timerisr
Start Timer0
Enable Timer0

'Ausgänge konfigurieren
Buzzer Alias Portb.0                                        'Ausgang für Buzzer definieren
Config Buzzer = Output                                      'als Ausgang
Dim Buzzeron As Byte                                        'Soll Buzzer piepsen oder nicht

Led Alias Portb.1
Config Led = Output

'Hilfsvariable definieren
Dim I As Byte                                               'Zaehlervariable
Dim Z As Byte                                               'Zählervariable für Intervall-Buzzer

'Variablen für S-Bus-Frame definieren
Dim Framebyte As Byte                                       'Jeder S-Bus-Frame beginnt mit einem festen Startbyte und endet mit festem Endbyte
Dim Databyte(2) As Byte                                     'Gesamtes Frame besteht aus Startbyte + 23 Datenbytes + Endbyte, hier werden 2 benötigt
Dim Lastdatabyte As Byte                                    'das 23. Datenbyte, hier liegen Framelost- & Failsafe-Signal
Dim Bitmask As Byte                                         'Hilfvaribale für Zwischenoperationen
Dim Channel As Integer                                      'Es werden 18 Kanäle übertragen

For I = 0 To 5
Buzzer = 1
Led = 1
Waitms 200
Buzzer = 0
Led = 0
Waitms 200
Next

'********************************
'*** BEGINN DER HAUPTSCHLEIFE ***
'********************************

Do


'*** Einlesen eines S-Bus-Frames ***
Disable Interrupts
 Einlesen:                                                  'Sprungmarke

 Led = 0

 Do
  Inputbin #1 , Framebyte                                   'Ein Byte von der SW-UART abholen
 Loop Until Framebyte = 15                                  'Solange wiederholen bis das Start-Byte (0x0F) erkannt wurde

 Led = 1

 For I = 1 To 15
     Inputbin #1 , Framebyte                                'Die ersten 15 nicht benötigten Datenbytes abholen, Framebyte-Variable missbrauchen
 Next

 Inputbin #1 , Databyte(1) , 2                              'die zwei entscheidenden Datenbytes abholen

 For I = 1 To 6                                             'sowie die übrigen 6 Bytes abholen, nur das letzte ist noch interessant
     Inputbin #1 , Lastdatabyte
 Next

 Inputbin #1 , Framebyte                                    'Das allerletzte Byte im Frame = hoffentlich das Endbyte empfangen

 If Framebyte > 0 Then Goto Einlesen                        'Falls beim Einlesen ein Fehler passiert ist, wiederholen! Wenn alles gut, dann weiter..

Enable Interrupts


 '*** Auswertung von Kanal 12 ***
 Channel = Databyte(2) And &B00001111                       'S-Bus Datenbytes zerlegen und zu Kanal 12 neu zusammensetzen
 Shift Channel , Left , 7
 Shift Databyte(1) , Right , 1
 Channel = Channel + Databyte(1)

 '*** Jetzt kommt die Reaktion auf die Kanalwerte ***
 If Channel > 1200 Then                                     'Falls > 1200
  Buzzeron = 1                                              'Piepser aktivieren
 Elseif Lastdatabyte.3 = 1 Then                             'Falls Failsafe aktiv
  Buzzeron = 1                                              'ebenfalls Piepser aktivieren
 Else
  Buzzeron = 0                                              'Sonst Piepser aus
 End If

Loop


'*** Interrupt Sprungmarke ***
Timerisr:
If Buzzeron = 1 Then
   If Z < 30 Then                                           'Timerinterrupt erfolgt mit ca. 60Hz
    Incr Z                                                  'deshalb auf ca. 1 Hz umskalieren
   Else
    Toggle Buzzer                                           'Ausgang von aus auf ein oder umgekehrt
    Z = 0                                                   'und Zähler zurücksetzen
   End If
 Else
  Buzzer = 0                                                'falls Piepser nicht aktiv, Ausgang defintiv aus
  Z = 0                                                     'und Zähler schon mal zurücksetzen
End If

Return

End
Und hier das fertige Hex-File zum flashen:
Anhang anzeigen LostPlaneFinder_S-Bus_ATtiny85_16Mhz.zip

Nach dem Flashen sind die Fuses auf

Extended 0xFF
High 0xDF
Low 0xFF

zu setzen.
 
Zuletzt bearbeitet:
#7
Hallo MarenB,
tolles Ding :D

Aber ich hätte da ne Frage:
Wenn ich den Kanal 12 auf sagen wir mal 16 ändern wollte, wo müsste ich was verändern ?


Und wenn ich schon frage, käme mir nun auch noch folgende Idee:
Wenn doch der Tiny85 SBUS dekodieren kann, wäre es dann nicht möglich,
das SBUS Signal als CPPM Stream auf einen Pin zu bekommen ?
Meine Idee wäre:
Servo Verlängerung mittig durch, Tiny85 und Vogelfutter zwischen, Schlumpfschlauch drumm ... SBUS2CPPM :p
So als SBUS to CPPM Dekoder für z.B. FlightController wie ArduPilot oder den Open Flight Stab ?
Natürlich mit Inverter (z.B. Transistor & 2x Widerstand), wegen der Geschwindigkeit ...

Gibt zwar schon sowas (Arduino ProMini / ProMicro), aber kleiner und leichter wäre evtl. besser :D
 

MarenB

Runter kommen sie immer!
#8
Hey,
Inverter brauchst du nicht, da der S.Bus über eine Software-Serielle Schnittstelle gelesen wird.
Beides wäre einfach möglich, den Piepser auf K16 zu legen und CPPM auszugeben, gerne auch beides gleichzeitig.
Ich suche mal meine S.Bus Decodiertabelle raus....
 
#9
öööhm ... sorry aber meine Programmierkentnisse sind schon seeeeeeeeehr bescheiden :p

Wenn Du das etwas leichter erklären könntest :D

Tante Edith sacht:
Wenn Du da nen Tester brauchst, Lötkolben läuft schon :p
 
Zuletzt bearbeitet:

MarenB

Runter kommen sie immer!
#10
Sooo, ich hatte ja noch was versprochen...

Wer die anghängte Zip-Datei öffnet, findet darin eine Excel-Datei, mit der sich der Binärdatenstrom des S.Bus analysieren lässt.
Im Ergebnis werden die Werte der Proportional-Kanäle 1-16 und die Zustände von Kanal 17 & 18, sowie die Flags für "Frame lost" und "Failsafe" ausgegeben.

Die farblichen Markierungen der Zellen geben dabei ganz gut wieder, wie man die Bytes des eingehenden Datenstromes in unterschiedlich große Pakete zerlegen und den Kanälen zuordnen muss.

Für Kanal 16 bedeutet das z.B.:

Man kopiere das komplette Datenbyte 22 in eine Word-Variable namens "Kanal16" und schiebe dann dort alle Bits drei Stellen nach links. Anschließend nehme man die oberen drei Bits des Datenbyte 21, packe sie in eine 1-Byte große Zwischenvariable "Temp", schiebe sie dort 5 Stellen nach rechts und addiere dann "Temp" zu "Kanal16". Fertig.

Anhang anzeigen S.Bus-Decoder.xls.zip
 
#11
Hey MarenB,
vielen Dank für die Tabelle.... Sehr interessant.:popcorn:
Ich hab schon lange nach so etwas gesucht.
Hast du Erfahrung mit dem sbus? :confused:
Ich wollte schon lange mal damit anfangen, Sensoren selber zu bauen.
Das müsste ja dann rückwärts mit deiner Tabelle auch möglich sein, oder?

Grüße Steven
 
#14
< Totengräber
Sehr interessanter Beitrag , vielen Dank.
Ich werde das mal mit einem Mega32 für alle Kanäle und LCD umschreiben.
Ziel : DSRL auslösen.

lg Rainer
 

MarenB

Runter kommen sie immer!
#15
Hi Rainer,

Wenn du Arduino kannst, ist das evtl schneller, weil es fertige LIBs gibt. Ich kann es nicht ausreichend gut, hab mich damals auf Bascom eingelassen...
Basierend auf dem Code habe ich auch schon einige 3-Kanal Wandler für Servos gebaut, um meine FPV-Canopies mit Pan/Tilt mit nur einem 3-adrigen Kabel anschließen zu können. Funktioniert prima :)

Viele Grüße
Maren
 

nichtgedacht

Erfahrener Benutzer
#16
Ich werde das mal mit einem Mega32 für alle Kanäle und LCD umschreiben.
Ziel : DSRL auslösen.
Moin,

am schnellsten kann man S-Bus mit Bitschieben und Verodern decodieren.
Die folgende Function verwende ich in meinem Selbstbau-Copter.

Sie wird per Interrupt als Callback Function aufgerufen, wenn 25 Bytes empfangen wurden und startet selber den
Empfang der nächsten 25 Bytes. Dieser Mechanismus wird beim STM32 von der HAL Library zur Verfügung gestellt.
Der Kern ist aber universell verwendbar und zeigt wie die Kanalwerte aus den Bytes gewonnen werden.
Das << 1 in jeder Zeile dient nur dazu die Werte nochmal mit 2 zu multiplizieren. S-Bus kann nur 2048 verschiedene
Werte, während SRXL16 (Multiplex) aka UDI16 (Jeti) 4096 Werte kann. Darum musste ich das angleichen.

Die Baudrate ist übrigens 100000/s und das Protokoll 8E2 also 1 Startbit, 8 Datenbits, 1 even Paritybit, 2 Stopbits

void HAL_UART_RxCpltCallback_SBUS(UART_HandleTypeDef *huart)
{
uint16_t i;

if (uart_data[0] == 0x0F && uart_data[24] == 0x00)
{
// stolen from https://github.com/zendes/SBUS
channels[0] = (((uart_data[1] | uart_data[2] << 8) & 0x07FF) << 1);
channels[1] = (((uart_data[2] >> 3 | uart_data[3] << 5) & 0x07FF) << 1);
channels[2] = (((uart_data[3] >> 6 | uart_data[4] << 2 | uart_data[5] << 10) & 0x07FF) << 1);
channels[3] = (((uart_data[5] >> 1 | uart_data[6] << 7) & 0x07FF) << 1);
channels[4] = (((uart_data[6] >> 4 | uart_data[7] << 4) & 0x07FF) << 1);
channels[5] = (((uart_data[7] >> 7 | uart_data[8] << 1 | uart_data[9] << 9) & 0x07FF) << 1);
channels[6] = (((uart_data[9] >> 2 | uart_data[10] << 6) & 0x07FF) << 1);
channels[7] = (((uart_data[10] >> 5 | uart_data[11] << 3) & 0x07FF) << 1);
channels[8] = (((uart_data[12] | uart_data[13] << 8) & 0x07FF) << 1);
channels[9] = (((uart_data[13] >> 3 | uart_data[14] << 5) & 0x07FF) << 1);
channels[10] = (((uart_data[14] >> 6 | uart_data[15] << 2 | uart_data[16] << 10) & 0x07FF) << 1);
channels[11] = (((uart_data[16] >> 1 | uart_data[17] << 7) & 0x07FF) << 1);
channels[12] = (((uart_data[17] >> 4 | uart_data[18] << 4) & 0x07FF) << 1);
channels[13] = (((uart_data[18] >> 7 | uart_data[19] << 1 | uart_data[20] << 9) & 0x07FF) << 1);
channels[14] = (((uart_data[20] >> 2 | uart_data[21] << 6) & 0x07FF) << 1);
channels[15] = (((uart_data[21] >> 5 | uart_data[22] << 3) & 0x07FF) << 1);

for( i = 0; i < 12; i++ )
{
if ( rc_rev == 1 )
{
channels = 4095 - channels;
}
}

RC_RECEIVED = 1;
}
else
{
// if TX is started first the first interrupt read could hit
// any point within the s-bus frame
// delay start of next read until we hit the gap between s-bus frames
// and get in sync
// HAL_Delay do not work here
for (i = 0; i < 5000; i++) // ~3.2ms
{
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_1);
}
RC_ERROR++;

}
HAL_UART_Receive_IT(&huart1, (uint8_t*) uart_data, 25);
}
 
#18
War ein sehr steiniger Weg aber jetzt löppt's.
Die Übertragung ist sehr stabil , jetzt folgt noch die exakte Auswertung.
Alle 11 mSek kommt ein Paket.
Mega 32 mit 16 MHz Quarz.
Als Baudrate habe ich 96000 eingestellt. Von 88000 bis 105000 gehts auch.
Ich werde noch berichten mit Code.

viele Grüße
Rainer
 

MarenB

Runter kommen sie immer!
#20
FPV1

Banggood

Oben Unten