SBUS Library

Status
Not open for further replies.
I might be miss-understating how sbus works... but can I send and receive data on the same line?
As in-
I’m using inputs on a t3.5 as a controller to send out sbus to a transmitter. But how can I recieve data back from the transmitter? How would I select and set the receiving pin on the t3.5?

Thanks for all of the help!
 
Last edited:
I might be miss-understating how sbus works... but can I send and receive data on the same line?
As in-
I’m using inputs on a t3.5 as a controller to send out sbus to a transmitter. But how can I recieve data back from the transmitter? How would I select and set the receiving pin on the t3.5?

Thanks for all of the help!

When you declare the SBUS object, you specify the serial port to use. The TX pin is used for transmitting packets and the RX pin is used for receiving packets. If you need to split RX and TX across multiple serial ports, you would want to declare separate objects. Typically, I've had three use cases:
1. SBUS Transmitter --> SBUS receiver --> Teensy --> SBUS servos. I can use the SBUS library on the Teensy to interpret pilot inputs from the SBUS transmitter and have flight control software on the Teensy to control a drone.
2. Teensy reading analog stick positions --> 900 MHz or 2.4 GHz transmitter --> Receiver --> Teensy --> Servos. In this case, I have a Teensy in a custom built transmitter reading the stick positions and generating an SBUS packet. I transmit the packet with a 900 MHz or 2.4 GHz radio modem interpret the SBUS packet by a Teensy in the drone and send the SBUS commands to the servos.
3. SBUS Receiver --> Teensy --> PWM Servos. In this case, I interpret SBUS packets with a Teensy and convert the packets into PWM commands.

Hope that helps clear things up! Feel free to post follow up questions...
 
FYI, I've updated this library. Besides adding support for some other boards and updating to Arduino 1.5 format for integration into the library manager, the following features have been added:
* Ability to set custom endpoints for each SBUS channel. Previously, these were set to 172 to 1811, which are the FrSky defaults. This feature may be useful if you're using different endpoints for a channel, but still want to map the readCal function to +/- 1.0.
* Ability to set a polynomial calibration for each channel for reading. After the count data is converted to +/- 1 in readCal, a custom polynomial can be applied for each channel. This would enable you to receive data in terms of commanded control surface position, for instance.
* A writeCal method. Previously, all commands were in terms of raw counts. Now, the writeCal method allows commands from +/- 1.0 and converts those commands to counts using the end points for each channel.
* Ability to set a polynomial calibration for each channel for writing. Before the +/- 1.0 command is converted to counts in writeCal, a polynomial calibration can be applied. This would enable you to send commands in terms of command control surface position, for instance.

Hope the changes are useful! As always, let me know if you run into any issues or have any feature requests. Also, I regularly use FrSky products, so any beta testers using Futaba products would be much appreciated.
 
Hi Brtaylor,
Can you comment as to whether what I describe below can be done more or less directly with your code, and just in case, you see something crazy about what I'm proposing, let me know?

I'm in the midst of a project to evolve the smallest possible (for me) fixed-wing "autonomous" aircraft. To get a handle on the physics of this sort of thing, I've built a Teensy 3.1 based flight recorder which rides along on the R/C flights of my electric Pandora. It records on a Micro-SD time, GPS position, magnetic heading, GPS altitude, barometric altitude, pitch, roll, and yaw a bit faster than 20 records/ sec.

Right now, I'm building another plane (a pusher) the better to add a pitot tube to sense airspeed. This would be in addition to the data collected above.

It would be wonderful to also record control input; throttle setting, as well as aileron, elevator, and rudder. I'm using a FRSKY X8R which has an s-bus port.

My idea is to write each of these four channels to a separate field in each record such that i would collect a more or less instantaneous status of all these variables. I would then use the accelerometer data with the s-bus data to discover control rate effectiveness, etc.

Do you think I can make my s-bus data accessible to this project using your code?

Is there anything crazy above?

best regards,

John
 
Hi Brtaylor,
Can you comment as to whether what I describe below can be done more or less directly with your code, and just in case, you see something crazy about what I'm proposing, let me know?

I'm in the midst of a project to evolve the smallest possible (for me) fixed-wing "autonomous" aircraft. To get a handle on the physics of this sort of thing, I've built a Teensy 3.1 based flight recorder which rides along on the R/C flights of my electric Pandora. It records on a Micro-SD time, GPS position, magnetic heading, GPS altitude, barometric altitude, pitch, roll, and yaw a bit faster than 20 records/ sec.

Right now, I'm building another plane (a pusher) the better to add a pitot tube to sense airspeed. This would be in addition to the data collected above.

It would be wonderful to also record control input; throttle setting, as well as aileron, elevator, and rudder. I'm using a FRSKY X8R which has an s-bus port.

My idea is to write each of these four channels to a separate field in each record such that i would collect a more or less instantaneous status of all these variables. I would then use the accelerometer data with the s-bus data to discover control rate effectiveness, etc.

Do you think I can make my s-bus data accessible to this project using your code?

Is there anything crazy above?

best regards,

John

Easy peasy. My SBUS library can directly give you pilot inputs. If you use the readCal function, you can get these so that full stick deflection is +/-1 on each channel.

It sounds like you're attempting to do some aerodynamic parameter estimation. My suggestion would be to get a spare accelerometer and go through a process of measuring control surface deflections in terms of degree or radian deflection. I typically use the faired position as zero, send SBUS step commands to the servos and use the accelerometer to measure the resulting angular deflection. You can then use a polynomial best fit to figure out the SBUS command your control laws need to send to get a desired control surface position. Recording the commanded control surface positions and measuring the aircraft response will enable you to estimate the control effectiveness (not quite as good as using POTs to measuring the surface positions, but okay depending on the frequency of your inputs).

Then you know your stick positions, control surface commands, and the aircraft responses.

If I can make a brief plug - my startup has a line of add-on backpacks that work well with the Teensy 3.1 and would work well for the sort of project you're describing (https://bolderflight.com/products/teensy/). We also have a Teensy 3.6 based solution with an integrated MPU-9250 IMU and BME-280 static pressure sensor (https://bolderflight.com/technical/#marmot-flight-control-system). With that setup, I am able to record data at 400 Hz all day long.

Brian
 
Brian, this sounds pretty good. I realize that I'm not doing anything original here, but the challenge keeps me busy. it's late here and I'll try to respond more intelligently in the morning. john
 
Brian,
This project is 3 years old. The objective was to develop expertise in semi-autonomous (plane takes off and flies itself on a prescribed route and lands itself) very small fixed wing aircraft design. Although I scratch designed and built a nice-flying 48" wingspan R/C Tractor, my investment in time and affection for the result lessened my interest in using it as a mule for auto-pilot design. Accordingly, I bought a Pandora from Motion R/C and set it up as a tail-dragger - looks something like a C-185.

I used the Pandora to learn how to fly R/C, which took a lot longer than I expected - my 3500 hrs PIC in the usual GA planes had very little positive effect on this. Pandora was a good choice, easily repaired with hot glue after all but the most severe crashes. I'm on my third, btw.

I designed, using EAGLE, a PCB motherboard to hold the Teensy 3.2, the voltage regulator, the MicroSD adapter, and the Molex jacks to connect to the Clock, the GPS, the Accelerometers, compass, gyros, and pressure sensor, as well as the external power connector, a serial output to connect an external output display, a switch to turn power on/off.

All of this was installed in the cabin roof of the Pandora, see photo.

View attachment cabin-roof.pdf


The hardware in the photos goes back to the beginning. The idea was to collect flight data on an "understood" airframe flying at the local R/C field.

It has worked well and I now have gigs of flight data as per earlier post. I've also realized that developing flight control software in simulation might consume fewer airframes. I wanted to model my own plane in X-Plane and so needed the control responses hence the need for S-Bus channel capture which is why we're talking about this.

Once I get through this (simulation development) and the resulting device can fly the Pandora smoothly and accurately, I'll set out to reduce airframe to smallest thing I can make work. I have 2 3D printers (used mostly for tooling and brackets), a cnc mill, cnc router, lathe, several bench saws, drill press, re-flow oven, oscilloscopes with support equipment and most (but not all) of the other stuff one accumulates over a lifetime of doing things like this.

I had intended to make my own electronic package for the small planes which would be T-Shaped in section with the top containing the devices which need to be horizontal and the leg, the micro-processor, the voltage regulator, the gps and the clock. My thought was to build this up from the chips, not use modules. I also expected that it would be too small for me tomake myself so I'd do the boards in Eagle and send them out to a job shop. I don't know if this stage will have any recording. One can buy very small 900 mHz receivers now. The ones with simply an S-Bus output are very compact and offer the opportunity to locate the receiver for best antenna reception and drive the servos from an sbus-converter located to reduce runs to servos.

I have a long way to go and don't really know when I'm going to get to later stages. I'm 76 and have plenty (but not enough) time to pursues this.

One thing I have discovered is beating yourself to death on one design element wastes time. Far better to have 4 or 5 aspects of project going at the same time, this way you can work on something else if you stall on one thing. And then, Voila!, at 3 in the morning you'll realize a solution to whatever had you stuck,but in the meantime you progressed other parts of project. So I'll have some airframe thing going, along with tooling improvements, maybe upgrading pcb's, and then some code.

And yes, I know that other guys are doing this ad probably more effectively than I am, but this doesn't bother me. This is for fun, not commercial. A lifetime spent doing projects for other people has left me with a bad case of "customer avoidance" I gave at the office. No More.

best,
John ferguson
 
Last edited:
Hi Brian,
I've looked at your site and it's clear you are doing what I'm trying to do and likely much more successfully, but then I'm doing this for fun.
two more photos, one of the flight recorder showing the Teensy 3.2, the voltage regualtor, the Jacks and the MicroSD slot.
also bottom of pcb. As I said, esigned in Eagle, and then etched with my cnc router. and hand soldered. I haven't gotten to using the reflow oven yet. I'm still doing through-hole components and module boards. when I get to SMD, then will be time for the reflow set-up.

flight-recorder-pcb1.jpg
flight-recorder.jpg
 
Hi Brian,
I've looked at your site and it's clear you are doing what I'm trying to do and likely much more successfully, but then I'm doing this for fun.
two more photos, one of the flight recorder showing the Teensy 3.2, the voltage regualtor, the Jacks and the MicroSD slot.
also bottom of pcb. As I said, esigned in Eagle, and then etched with my cnc router. and hand soldered. I haven't gotten to using the reflow oven yet. I'm still doing through-hole components and module boards. when I get to SMD, then will be time for the reflow set-up.

View attachment 16486
View attachment 16487

Cool photos, thanks for sharing! I really like Osh Park for 2 and 4 layer boards, if you end up needing the extra complexity. Osh Stencils are nice for cheap stencils - my preference is their stainless stencils and choose a thickness based on your part pitch. My re-flow profile for leaded solder is 250F for 6 minutes (this timing isn't critical, you're just warming up all the components) and then warm the oven to 450F and hold for 2 minutes at that temperature.
 
Cool photos, thanks for sharing! I really like Osh Park for 2 and 4 layer boards, if you end up needing the extra complexity. Osh Stencils are nice for cheap stencils - my preference is their stainless stencils and choose a thickness based on your part pitch. My re-flow profile for leaded solder is 250F for 6 minutes (this timing isn't critical, you're just warming up all the components) and then warm the oven to 450F and hold for 2 minutes at that temperature.

The wire you see in the top-side photo is the one lead which couldn't be confined to the back. I've made maybe 3 dozen boards for different purposes and this is the first where I just couldn't do it without a crossing. I especially appreciate your recommendations for a fab shop. So far I've done everything myself, but even if i can do smd's without vias, I'll still need the stencils.

BTW, what is the most recent update date on your library?

thanks again for your thoughts.

john
 
The wire you see in the top-side photo is the one lead which couldn't be confined to the back. I've made maybe 3 dozen boards for different purposes and this is the first where I just couldn't do it without a crossing. I especially appreciate your recommendations for a fab shop. So far I've done everything myself, but even if i can do smd's without vias, I'll still need the stencils.

BTW, what is the most recent update date on your library?

thanks again for your thoughts.

john

Looks like Oct 31, 2018.
 
Here is what I've done:
Teensy 3.2 - powered externally with 5 volt to Vin port
GND from power source to Pin 0

input from X8R sbus port through 1k resistor to base of N3904, gnd to emitter, output to teensy pin 0 from collector which also has 10k resistor to plus 5v

X8R connected to 4 servos plus motor - operated r/c from Taranis x9d - when battery connected to esc powering all of this, servos wiggle and motor revs.

when I start the monitor is see the message from setup but nothing else.

Where have I screwed up?

Code:
/*
  * All the stuff Brian wrote*
This is intended to read th sbus and print result to monitor jaf 5-4-2019
*/

// This example reads an SBUS packet from an
// SBUS receiver (FrSky X8R) and then takes that
// packet and writes it back to an SBUS
// compatible servo. The SBUS out capability (i.e.
// writing a command to the servo) could be generated
// independently; however, the packet timing would need
// to be controlled by the programmer, the write function
// simply generates an SBUS packet and writes it to the
// servos. In this case the packet timing is handled by the
// SBUS receiver and waiting for a good packet read.

//modified to write to monitor jaf 5-4-2019
#include "SBUS.h"

// a SBUS object, which is on hardware
// serial port 1
SBUS x8r(Serial1);

// channel, fail safe, and lost frames data
uint16_t channels[16];  //checkl to make sure this is needed. jaf 5-4-2019
//bool failSafe;
//bool lostFrame;

void setup() {
  // begin the SBUS communication
  x8r.begin();
  Serial.begin(115200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // send an intro:
  Serial.println("Start Reading SBUS output");
  delay(5000);
}

void loop() {
float channels[16]; bool failSafe; bool lostFrame;
  // look for a good SBUS packet from the receiver
 // if(x8r.readCal(&channels[1], &failSafe, &lostFrame)){

    // write the SBUS packet to the monitor
    
if(x8r.readCal(&channels[1], &failSafe, &lostFrame)){
  Serial.println(channels[1]);
}
  
}
 
Here is what I've done:
Teensy 3.2 - powered externally with 5 volt to Vin port
GND from power source to Pin 0

input from X8R sbus port through 1k resistor to base of N3904, gnd to emitter, output to teensy pin 0 from collector which also has 10k resistor to plus 5v

X8R connected to 4 servos plus motor - operated r/c from Taranis x9d - when battery connected to esc powering all of this, servos wiggle and motor revs.

when I start the monitor is see the message from setup but nothing else.

Where have I screwed up?

Code:
/*
  * All the stuff Brian wrote*
This is intended to read th sbus and print result to monitor jaf 5-4-2019
*/

// This example reads an SBUS packet from an
// SBUS receiver (FrSky X8R) and then takes that
// packet and writes it back to an SBUS
// compatible servo. The SBUS out capability (i.e.
// writing a command to the servo) could be generated
// independently; however, the packet timing would need
// to be controlled by the programmer, the write function
// simply generates an SBUS packet and writes it to the
// servos. In this case the packet timing is handled by the
// SBUS receiver and waiting for a good packet read.

//modified to write packet to monitor jaf 5-4-2019
#include "SBUS.h"

// a SBUS object, which is on hardware
// serial port 1
SBUS x8r(Serial1);

// channel, fail safe, and lost frames data
uint16_t channels[16];  //checkl to make sure this is needed. jaf 5-4-2019
//bool failSafe;
//bool lostFrame;

void setup() {
  // begin the SBUS communication
  x8r.begin();
  Serial.begin(115200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // send an intro:
  Serial.println("Start Reading SBUS output");
  delay(5000);
}

void loop() {
float channels[16]; bool failSafe; bool lostFrame;
  // look for a good SBUS packet from the receiver
 // if(x8r.readCal(&channels[1], &failSafe, &lostFrame)){

    // write the SBUS packet to the monitor
    
if(x8r.readCal(&channels[1], &failSafe, &lostFrame)){
  Serial.println(channels[1]);
}
  
}

What are you accomplishing with the N3904 and resistors? Should work fine with the SBUS receiver directly connected to the Teensy.
 
Boy are you quick. I'd thought that the inverted logic applied to the teensy as well as the Mega. Wrong?
 
Yep, the Teensys can do inverted logic and the library is handling all of that for you.

That's good.

While we're here you suggested that my aerodynamics recorder might want to see control surface deflections. My thought had been that I would relate control input and airspeed to rate of change in in pitch,roll, and yaw. I looked at control surface deflection as a bit of black-box system where I care about the result but not every element of how it is achieved.

At this point, since I haven't gotten there yet, I don't know how I'm going to learn what I need from my data.

now, back to the garage to see how reading sbus output directly works.

thank you so much for your help.

john ferguson - lived in Richfield 1945-1954.
 
That's good.

While we're here you suggested that my aerodynamics recorder might want to see control surface deflections. My thought had been that I would relate control input and airspeed to rate of change in in pitch,roll, and yaw. I looked at control surface deflection as a bit of black-box system where I care about the result but not every element of how it is achieved.

At this point, since I haven't gotten there yet, I don't know how I'm going to learn what I need from my data.

now, back to the garage to see how reading sbus output directly works.

thank you so much for your help.

john ferguson - lived in Richfield 1945-1954.

Hi John,

Typically, people will estimate non-dimensional coefficients to model the aircraft dynamics. One part of that process essentially normalizes the data by the airspeed. The mass properties of the aircraft (i.e. total mass and mass distribution) are also typically normalized out. This is useful because you can then apply the estimated coefficients to simulate the aircraft at a variety of airspeeds and mass loading conditions.

Using the control surface deflections as the input is nice because it gives you a very generic input that the aircraft model was created against. In other words, assuming the control surface sizes and positions don't change, a 1 degree deflection is always a 1 degree deflection and will always produce the same aircraft response. If you use a different metric, like a normalized SBUS signal from a pilot stick, that model is then only valid for that input signal. So if you apply trims or switch from a linear stick mapping to non-linear mapping, you would need to generate a new model.

Similar with mass properties and airspeed. You certainly don't need to estimate non-dimensional coefficients, but then your model is less generally applicable. If you don't estimate the mass properties separately, your model is only valid for the mass properties as the aircraft was flown. If you don't non-dimensionalize against airspeed, your model is only valid for the airspeed flown.

In general, with electric RC aircraft, I would say that it is safe to assume that the mass properties are not changing and can be ignored. Also, you're probably okay not non-dimensionalizing around airspeed given the limited operational envelope of RC aircraft. I would non-dimensionalize the control surface deflections, however. This would enable your models to be valid regardless of the stick shaping or control laws you use in the future.

RP-1168 is a great NASA research publication on one approach to aircraft model estimation (https://www.nasa.gov/centers/dryden/pdf/88044main_H-1299.pdf). Aircraft System Identification: Theory and Practice is another good resource (it starts from a more basic level) and it contains additional estimation approaches (https://www.amazon.com/Aircraft-Sys...ugene+morelli&qid=1557077037&s=gateway&sr=8-1).

Brian
 
Last edited:
Hi Brian,
Thanks much for these views as well as the references.
BTW, did you see any problem with my code?

john
 
Last edited:
Hi Brian,
Bingo, getting rid of the transistor inverter did the trick.
thanks for a useful library

best regards,

john
 
Hi Brian,
Now that I have one channel printing fine, I want to move on to printing the 4 channels my project needs. What you've done is

Code:
 if(x8r.readCal(&channels[0], &failSafe, &lostFrame)){
  Serial.println(channels[0]);

Do you think doing the PACKET check for channels[0] would be adequate such that the Serial.print(ln) section could print each channel in succession or do I need to do a frame check for each channel?

best,
John
 
Hi Brian,
Now that I have one channel printing fine, I want to move on to printing the 4 channels my project needs. What you've done is

Code:
 if(x8r.readCal(&channels[0], &failSafe, &lostFrame)){
  Serial.println(channels[0]);

Do you think doing the PACKET check for channels[0] would be adequate such that the Serial.print(ln) section could print each channel in succession or do I need to do a frame check for each channel?

best,
John

You should just do readCal once and then print all the channels in succession.

This line:
Code:
x8r.readCal(&channels[0], &failSafe, &lostFrame)

is just passing the addresses of the channels array, fail safe variable, and lost frame variable to the readCal method. The method needs the address so that it can write data to them in order to update their values. So, even though I am passing "&channels[0]", that is simply the address of the array. In fact, if you passed "&channels[1]" instead, you would get a buffer overflow because the readCal method would be trying to write a 16 size array, but start at the address of the second index, overflowing the buffer by 1.

So the correct approach would be:
Code:
if(x8r.readCal(&channels[0], &failSafe, &lostFrame)){
  for (unsigned int i = 0; i < 16; i++) {
    Serial.print(channels[i]);
    Serial.print("\t");
  }
  Serial.println();
}
 
Hi Brian,
I have now integrated your sbus code with my flight recording code and it works great. I decided to use x8r.read() rather than readCal because I will be able to use this form of output (somewhat edited) to drive my simulation directly. I'm looking forward to doing a bunch of flights and see what I get.

Thanks again for this very useful code.

john
 
I'm using the SBUS library to talk to a DJI Ronin-S Gimbal. (example of someone else using a Futaba: https://www.youtube.com/watch?v=bQW3NOoDCOw ). The first 4 channels all play nice, Pan, Tilt, Roll, and what I think is focus control... the next three channels (based on other people stuff) controls the record, mode, center/selfie. so (starting from 0) that puts mode at Ch 5 and CH6. The weirdness is it is acting like the LSB from CH6 is actually the MSB for Ch 5... Anyone else have any weirdness with writing, or has anyone else hooked this library to a Ronin-S? (I've tried this on both a Teensy LC and Teensy 3.5 ... same behavior). (I can post code in the morning, but curious if anyone else had any thoughts...)
 
and the code...(just modified from the example at this point!):
Code:
#include <TimerOne.h>
#include "SBUS.h"
SBUS x8r(Serial1);

volatile uint16_t ain[16];

void setup() {

  Serial.begin(1000000);

  x8r.begin();

  Timer1.initialize(9000);
  // 7-14ms is what I found online... both ext work... left at 9ms

  Timer1.attachInterrupt(sendSBUS);

  for (uint8_t i = 0; i < 16; i++)ain[i] = 1023;


}

void loop() {
  while (1) {
    ain[0] = 1100;

    //  0 is pan 1024+ right
    //  1 is tilt 1024+ down
    //  2 is  .... focus motor???
    //  3 is roll 1024+ clockwise
    //  4 is photo/record
    //  5 is user profile... 0=1
    //  6 in Recenter/selfie/user profile  OVERLAP???  :P
    //        b0 is user 2 or 3  ???
    //        b1-11 value
    //        centered on 1023
    //    900 is user 2, partial recenter
    /*
       online found this...
       CH4: Photo/Record
       CH5: User Profile
       CH6: Recenter/Selfie
    */
    for (int i = 0; i < 16; i++) {
      Serial.print(ain[i]);
      Serial.print("\t");
    }
    Serial.println();
    delay(100);
  }

}

void sendSBUS() {
  uint16_t channels[16];
  for (uint8_t i = 0; i < 16; i++) {
    channels[i] = (uint16_t)ain[i];
  }
  // write the SBUS packet to an SBUS compatible servo
  // hopefully the Ronin-S!
  x8r.write(&channels[0]);
}
 
Status
Not open for further replies.
Back
Top