Go Down

Topic: Futaba SBUS reverse engineered to work with Arduino (Read 69797 times) previous topic - next topic

Glowtape

This is the inverter I use.
Both resistors are 1k


Nice to know this'll work instead of going with an 74HC14 or something.

CrossRoads

That's also good as a 12V driver for P-channel MOSFET to switch on higher voltage/current loads.
Pull up to 12V tho.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

Glattnos

Hi

I have problem to get this work properly. I get nothing back on the serial-port when I try this code:
Code: [Select]

#include <FUTABA_SBUS.h>
#include <Streaming.h>

FUTABA_SBUS sBus;

void setup(){
  sBus.begin();
  Serial.begin(115200);
}

void loop(){
  sBus.FeedLine();
    if (sBus.toChannels == 1){
    sBus.UpdateServos();
    sBus.UpdateChannels();
    sBus.toChannels = 0;
    Serial<<sBus.channels[0]<<","<<sBus.channels[1]<<","<<sBus.channels[2]<<"\r\n";
  }
}

But when I change in the end of the FUTABA_SBUS.ccp file from this:
Code: [Select]

        if (bufferIndex == 24){
          feedState = 0;
          if (inBuffer[0]==0x0f && inBuffer[24] == 0x00){
            memcpy(sbusData,inBuffer,25);
            toChannels = 1;
          }
        }

to this where I comment out the "&& inBuffer[24] == 0x00" like this:
Code: [Select]

        if (bufferIndex == 24){
          feedState = 0;
          if (inBuffer[0]==0x0f){                 // && inBuffer[24] == 0x00){
            memcpy(sbusData,inBuffer,25);
            toChannels = 1;
          }
        }


It works

I guess the "&& inBuffer[24] == 0x00" statement is to check the end of the string to be sure that it is changed to 0x00, it is earlier in the code set to 0xFF like this:
Code: [Select]

else{
          bufferIndex = 0;
          inBuffer[bufferIndex] = inData;
          inBuffer[24] = 0xff;
          feedState = 1;
        }


I have a Futaba R7008SB-reciver. What can be wrong? Someone that have any idea?

Glattnos

#63
Dec 22, 2015, 07:05 pm Last Edit: Dec 22, 2015, 07:27 pm by Glattnos
After sending the whole string I see that it looks like this:
Code: [Select]

0F E5 43 9F FA 02 08 16 18 02 10 80 00 04 20 00 01 08 07 38 00 10 80 00 04
0F E5 43 9F FA 02 08 16 18 02 10 80 00 04 20 00 01 08 07 38 00 10 80 00 14
0F E5 43 9F FA 02 08 16 18 02 10 80 00 04 20 00 01 08 07 38 00 10 80 00 24
0F E5 43 9F FA 02 08 16 18 02 10 80 00 04 20 00 01 08 07 38 00 10 80 00 34
0F E5 43 9F FA 02 08 16 18 02 10 80 00 04 20 00 01 08 07 38 00 10 80 00 04
0F E5 43 9F FA 02 08 16 18 02 10 80 00 04 20 00 01 08 07 38 00 10 80 00 14
0F E5 43 9F FA 02 08 16 18 02 10 80 00 04 20 00 01 08 07 38 00 10 80 00 24
0F E5 43 9F FA 02 08 16 18 02 10 80 00 04 20 00 01 08 07 38 00 10 80 00 34

0F in the begining is the start bit, the next 22 bytes are the channels(22bytes x 8bits=176bits, 176bits/11-bits = 16 11-bit channels), then the next byte is 00 all the time, but that is in this case byte 23 and not 24 so I changed to this:
Code: [Select]
if (inBuffer[0]==0x0f && inBuffer[23] == 0x00) //Changed to 23 instead of 24
That works!

But the last byte, it is going 04, 14, 24, 34 all the time. Anyone know why it is like that?

Edit: Hmmm byte 23 is the failsafe-bit so thats why that one is 00, if failsafe will activate it will change. So why is the last byte changing like that?

Becherraecher

...

But the last byte, it is going 04, 14, 24, 34 all the time. Anyone know why it is like that?

Edit: Hmmm byte 23 is the failsafe-bit so thats why that one is 00, if failsafe will activate it will change. So why is the last byte changing like that?
Don't actually know what that byte is exactly. Am using FrSky and Spektrum.
But Have you recognized that your byte is always cycling '04, 14, 24, 34, 04, ...'?
Seem like a rolling counter or something. Maybe some watchdog functionality for receiving bus members?
Maybe only first byte is counter '0x, 1x, ...' and second byte is something like a status byte 'y4, (y+1)4, ...' and changing when receiver is connected to TX or in binded state or something else?

Just my late night thoguths :)

Regards

dsones

Hi guys,

It is pretty cool this works!
Now that its know how it works is there any wat to reverse this and use it to send the sbus data from the arduino to a transmitter? something like a frsky xjt transmitter?

I would love to make a transmitter that way, send button or pulse signals to the arduino and finally send them converted in sbus to the xjt transmitter!

Sorry if my english is confusing im from the netherlands and not that good with this language..

Also pretty new to this forum lol!


Hope somebody had a idea/anwser to this, or maybe work something out together?


Cheers!

Erni

Quote
is there any wat to reverse this and use it to send the sbus data from the arduino
You can genrate the SBUS data on an Arduino by using this sketch:

rcgroups

If you want to make a FrSky like transmitter, you could just Flash OpenTX on an Arduino Mega:

rcgroups

dsones

Thank you very much erni.
You gave me so much good info!

I will take a look at it and if i come any furter i will update you.


i3dm

Hello guys,

i read some posts in this thread, and focused on the HW side - seems like a logic inverter is needed.
is there a way to run Sbus codes on a Pro Mini with no external HW?
i know the pro mini can do at least 2 PWM outputs, but im actually looking at going a different way and use the Arduino Pro mini to gather serial data from Jetcat ECU and convert it to SBUS protocol for telemtry.

i already did the Jetcat serial communication side when i did my mini GSU project:
https://www.youtube.com/watch?v=0nNGnf0DVl8

dally

is there a way to run Sbus codes on a Pro Mini with no external HW?
I am afraid the answer is no
Hey Ho! Pip & Dandy! Cooking my maleficent weapons

WhiteWind

Hi everyone! I am trying to use the described method to read my x4rsb receiver for my project. I was able from time to time read good values, but often I was received just a bunch of lost frames and errors. So I was trying to dig in that, and first of all I found, that not all the time 0F is the first byte, sometimes it's in the middle of the row:

Code: [Select]
0F E4 EB 1E 2B B2 C7 0A F1 B1 82 15 AC 18 1F F8 C0 07 3E F0 81 0F 7C 0 0
0F E4 E3 1E 2B B2 C7 0A F1 B1 82 15 AC 10 1F F8 C0 07 3E F0 81 0F 7C 0 0
0F E4 E3 1E 2B B2 C7 0A F1 B1 82 15 AC 08 1F F8 C0 07 3E F0 81 0F 7C 0 0
0F E4 EB 1E 2B B0 C7 8A F0 B1 82 15 AC 18 1F F8 C0 07 3E F0 81 0F 7C 0 0
0F E4 EB 1E 2B B2 C7 0A F1 B1 82 15 AC 10 1F F8 C0 07 3E F0 81 0F 7C 0 0


Ok, not the worse, but I decided to make a snake-line class, that will eat bytes one by one and pop them,if there is no place inside. I don't know, is there something ready for that, but it's really easy to implement. The goal was to catch byte row and check, if first and last byte are start and stop bytes. So, if true, we can decode the bytes the way it's done in the sbus library mentioned above;


my sbus.cpp
Code: [Select]
#include "SBUS2.h"
#include <Arduino.h>

void SBUS::begin() {
SBUS::begin(true);
}

void SBUS::begin(bool useTimer) {
//wiffer.begin();
if (useTimer) {
noInterrupts();
/*TCCR2A  = 0;
TCCR2B  = 0;
TCNT2   = 0;
OCR2A   = 249;
TCCR2A |= (1 << WGM21);
TCCR2B |= (1 << CS22);
TIMSK2 |= (1 << OCIE2A);*/
interrupts();
}

for (byte i = 0; i<18; i++) {
_channels[i]      = 0;
}

_goodFrames         = 0;
_lostFrames         = 0;
_decoderErrorFrames = 0;
_failsafe           = SBUS_FAILSAFE_INACTIVE;

_serial.begin(100000, SERIAL_8E1_RXINV_TXINV);
}

void SBUS::process() {
static byte buffer[25];
static byte buffer_index = 0;
wiffer.begin();//reset wiffer again
while (_serial.available()) {
byte rx = _serial.read();
wiffer.push(rx);

    for (int i = 0; i < WIFFER_LENGTH; ++i)
    {
    Serial.print(String(wiffer.get(i), HEX));
    Serial.print(' ');
    }
    Serial.println('--');
if (!wiffer.full()){
continue;
}
if (wiffer.first() == SBUS_STARTBYTE && wiffer.last() == SBUS_ENDBYTE){
Serial.println('???');
for (int i = 1; i < 25; ++i)
{
buffer[i] = wiffer.get(i);
}
_decoderErrorFrames += wiffer.lost();
_goodFrames += 26;
wiffer.begin();

_bytes=' ';
for (int i = 0; i < 25; ++i)
{
_bytes= _bytes + ' ' + String(buffer[i], HEX);
}

_channels[0]  = ((buffer[1]    |buffer[2]<<8)                 & 0x07FF);
_channels[1]  = ((buffer[2]>>3 |buffer[3]<<5)                 & 0x07FF);
_channels[2]  = ((buffer[3]>>6 |buffer[4]<<2 |buffer[5]<<10)  & 0x07FF);
_channels[3]  = ((buffer[5]>>1 |buffer[6]<<7)                 & 0x07FF);
_channels[4]  = ((buffer[6]>>4 |buffer[7]<<4)                 & 0x07FF);
_channels[5]  = ((buffer[7]>>7 |buffer[8]<<1 |buffer[9]<<9)   & 0x07FF);
_channels[6]  = ((buffer[9]>>2 |buffer[10]<<6)                & 0x07FF);
_channels[7]  = ((buffer[10]>>5|buffer[11]<<3)                & 0x07FF);
_channels[8]  = ((buffer[12]   |buffer[13]<<8)                & 0x07FF);
_channels[9]  = ((buffer[13]>>3|buffer[14]<<5)                & 0x07FF);
_channels[10] = ((buffer[14]>>6|buffer[15]<<2|buffer[16]<<10) & 0x07FF);
_channels[11] = ((buffer[16]>>1|buffer[17]<<7)                & 0x07FF);
_channels[12] = ((buffer[17]>>4|buffer[18]<<4)                & 0x07FF);
_channels[13] = ((buffer[18]>>7|buffer[19]<<1|buffer[20]<<9)  & 0x07FF);
_channels[14] = ((buffer[20]>>2|buffer[21]<<6)                & 0x07FF);
_channels[15] = ((buffer[21]>>5|buffer[22]<<3)                & 0x07FF);

((buffer[23])      & 0x0001) ? _channels[16] = 2047: _channels[16] = 0;
((buffer[23] >> 1) & 0x0001) ? _channels[17] = 2047: _channels[17] = 0;

if ((buffer[23] >> 3) & 0x0001) {
_failsafe = SBUS_FAILSAFE_ACTIVE;
} else {
_failsafe = SBUS_FAILSAFE_INACTIVE;
}

if ((buffer[23] >> 2) & 0x0001) {
_lostFrames++;
}

_lastGoodFrame = millis();
}
}
}

int SBUS::getChannel(int channel) {
if (channel < 1 or channel > 18) {
return 0;
} else {
return _channels[channel - 1];
}
}

int SBUS::getNormalizedChannel(int channel) {
if (channel < 1 or channel > 18) {
return 0;
} else {
return (int) lround(_channels[channel - 1] / 9.92) - 100; //9.92 or 10.24?
}
}

int SBUS::getFailsafeStatus() {
return _failsafe;
}

int SBUS::getFrameLoss() {
return (int) ((_lostFrames + _decoderErrorFrames) * 100 / (_goodFrames + _lostFrames + _decoderErrorFrames));
}

long SBUS::getGoodFrames() {
return _goodFrames;
}

long SBUS::getLostFrames() {
return _lostFrames;
}

long SBUS::getDecoderErrorFrames() {
return _decoderErrorFrames;
}

long long SBUS::getLastTime() {
return _lastGoodFrame;
}


String SBUS::getBytes() {
return _bytes;
}



//WIFFER

void WIFFER::begin(){
  _pointer = -1;
  _count = 0;
  _eternal = 0;
  for (int i = 0; i < WIFFER_LENGTH; ++i)
  {
  _data[i] = 0;
  }
}
void WIFFER::push(byte item){
  _pointer++;
  _eternal++;
  if (_count<WIFFER_LENGTH){
  _count++;
  }
  if (_pointer == WIFFER_LENGTH){
  _pointer = 0;
  }
  _data[_pointer] = item;
}
byte WIFFER::get(int index){
int target = (_pointer + 1 + index) % WIFFER_LENGTH;
return _data[target];
}
byte WIFFER::first(){
  if (_count<WIFFER_LENGTH){
  return _data[0];
  }else{
  if (_pointer + 1 < WIFFER_LENGTH){
  return _data[_pointer + 1];
  }else{
return _data[0];
  }
  }
}
byte WIFFER::last(){
return _data[_pointer];
}

int WIFFER::length(){
return _count;
}

bool WIFFER::full(){
return (_count == WIFFER_LENGTH);
}

unsigned long WIFFER::lost(){
return _eternal - _count;
}



Don't be surprised, the code is used on teensy board, so I have a little bit different hardware;
Whoa, it's working, but I am not sure about counting good and bad frames (i am counting bytes instead).
Lastly, I uploaded the code, and found that strange thing (0F is replaced to -- for the ease of reading).
Code: [Select]
-- E5 E3 1E 2B AE C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 81 8F 15 00 00
-- E5 E3 1E 2B AE C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 81 8F 15 00 00
-- E4 E3 1E 2B B0 C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 81 8F 15 00 00
-- E4 E3 1E 2B B0 C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 81 8F 15 00 00
-- E4 E3 1E 2B B0 C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 81 8F 15 00 00
-- E4 E3 1E 2B B0 C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 81 8F 15 00 00
-- E5 E3 1E 2B AE C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 81 8F 15 00 --
-- E5 E3 1E 2B AE C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 F0 00 -- E5 E3 1E 2B
-- E5 E3 1E 2B AE C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E 15 -- E5 E3 1E 2B
-- E5 E3 1E 2B AE C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 81 8F 00 -- E5
-- E5 E3 1E 2B AE C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 8F 00 -- E5 E3
-- E5 E3 1E 2B AE C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 8F -- E5 E3 1E
-- E5 E3 1E 2B AE C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 81 15 -- E4 E3
-- E4 E3 1E 2B B0 C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 81 15 -- E4 E3
-- E4 E3 1E 2B B0 C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 81 00 -- E5 E3
-- E5 E3 1E 2B AE C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 81 00 -- E5 E3
-- E5 E3 1E 2B AE C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 8F 00 -- E5 E3
-- E5 E3 1E 2B B0 C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 8F -- E5 E3 1E
-- E5 E3 1E 2B B0 C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 81 15 -- E5 E3
-- E5 E3 1E 2B AE C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 81 15 -- E5 E3
-- E5 E3 1E 2B AE C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 81 00 -- E5 D3
-- E5 D3 1E 2B AE C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 81 00 -- E5 D3
-- E5 D3 1E 2B AE C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 8F 00 -- E4 E3
-- E4 E3 1E 2B AE C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 15 -- E4 E3 1E
-- E4 E3 1E 2B AE C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 81 15 -- E4 E3
-- E4 E3 1E 2B B0 C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 81 00 -- E4 E3
-- E4 E3 1E 2B B0 C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 81 00 -- E5 03
-- E5 03 1F 2B AE C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 81 00 -- E5 03
-- E5 03 1F 2B AE C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 8F 00 -- E5 E3
-- E5 E3 1E 2B B0 C7 0A 56 B0 82 15 AC 60 05 F8 C0 07 3E F0 8F -- E5 E3 1E


Any ideas, why it's shorter? Why the length is not constant (but there is clearly an order in that), and what should I do with that stuff now?
Can someone tell me, if I am doing something wrong, or am I messed with the code?
May be there is something in frsky sbus, that is not described?  :o 

WhiteWind

I solved all the problems and, at last, my code is working good, as expected.
The problem was in too fast buffer polling (I downclocked the timer) and mostly in some kind of buffer overflow, as the reading buffer to the end on the starting of lost frame avalanche is making it work again.


Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy