Forum Rule: Always post complete source code & details to reproduce any issue!
Page 1 of 3 1 2 3 LastLast
Results 1 to 25 of 59

Thread: SBUS Library

Hybrid View

  1. #1
    Senior Member brtaylor's Avatar
    Join Date
    Mar 2016
    Location
    Portland, OR
    Posts
    537

    SBUS Library

    Hello everyone, I have an introduction of me in a recent post.

    I'd like to announce availability of an SBUS library. SBUS is a protocol for RC receivers to send commands to servos. Unlike PWM, SBUS uses a bus architecture where a single signal line can be connected up to 16 servos with each receiving a unique command. SBUS capable servos are required; each can be programmed with a unique address (Channel 0 - 15) using an SBUS servo programmer. Advantages of SBUS include the reduction of wiring clutter and ease of parsing commands from RC receivers.

    I'd like to give big shout outs to Uwe Gartmann on ARMmbed and Paul Stroffregen on this PJRC thread. I learned a lot about SBUS parsing and sending a serial 8E2 SBUS packet based on those resources.

    This library enables Teensy devices to read and parse SBUS packets from an SBUS capable RC receiver. Data can be read as counts or calibrated to +/- 1.0 values. Additionally, SBUS packets can be created and sent to SBUS capable servos given an array of position commands. I tested the code using the X8R and X4R SBUS receivers and the D25MA SBUS servo. I hope the library is useful and I would love feedback, especially on additional receivers and servos!

    Brian

  2. #2
    Hi Brian

    nice other people are still working on this SBUS stuff. Fortunately, the problem with T3.2 and and 8E2 will with T3.5/6 be a problem going away.

    I had short look at your code. The problem I see is thanks to the performance of the T3.2 not that much of a problem, because there is still plenty of processing power left - but : during the transmission of an SBUS packet the teensy is absorbed by this task and not available for other inbterrupt driven tasks like handling an IMU.

    Maybe you have a look at what is already published in the thread you mentionned. The solution with an interrupt-driven approach frees a considerable amount of processor time, takes only little time for each byte to be sent and works on Futaba and Frsky servos.

    By the way - do you have information about the SBUS2 protocol ? I know it is around, but its hard to have a hand on it.

    regards Andy

  3. #3
    Senior Member brtaylor's Avatar
    Join Date
    Mar 2016
    Location
    Portland, OR
    Posts
    537
    Hi Andy, thanks! Good idea and I've been working on updating the library to use interrupts for the serial write. Going on a short vacation, but hope to have something working later next week.

    My understanding with SBUS2 is that it's used for sending telemetry. I am pretty excited to try this with the FrSky products, especially with OpenTX on my Taranis transmitter. From what I understand, at least for FrSky products, the telemetry downlink is pretty low bandwidth, but I've still been considering it to send health and status bits from the aircraft to the Taranis transmitter to issue a warning to the pilot with most of the uplink / downlink occurring over 900 MHz. I'll be sure to post as I have a chance to dig into it further...

    Brian

  4. #4
    Senior Member brtaylor's Avatar
    Join Date
    Mar 2016
    Location
    Portland, OR
    Posts
    537
    I'm still working to develop a satisfactory method of sending data using interrupts on Teensy 3.1/3.2, but I did find this work on SBUS2 to send telemetry data using Futaba components:
    http://sbustelemetrysensors.blogspot.com/

    Brian

  5. #5
    Hi Brian

    did you have a look at https://forum.pjrc.com/threads/23956...l=1#post109492 ?
    If you did I would like to know what did not work. Maybe I have to improve my code.

    Another question (maybe not the right place) - why did you choose AMS 5812 and AMS 5915 instead of MS5611 and MS4525 ?

    Andi

  6. #6
    Senior Member brtaylor's Avatar
    Join Date
    Mar 2016
    Location
    Portland, OR
    Posts
    537
    Hi Andi,

    Thanks! I did have a look at the code. The issue I was having was that IntervalTimer needs to be a global, as I learned here:
    https://forum.pjrc.com/threads/37021...rduino-Library

    I got it working, cleaned up, and tested this morning. My SBUS library has been updated and is now using interrupts rather than elapsedMicros to send the SBUS packet on the Teensy 3.1/3.2.
    https://github.com/bolderflight/SBUS

    I'll post a reply to your pressure transducer question in a moment on the AMS5812 / AMS5915 thread:
    https://forum.pjrc.com/threads/36102...5915-Libraries

    Best!
    Brian

  7. #7
    Hi Brian

    the arrival of my first T3.6 was a good reason to end a loooong break. I had a look at your latest SBUS-coding and it worked right away. Thanks for the work.

    However - if I pull the SBUS signal wire from the X8R and reconnect, the program quite often hangs and is unable to resync.

    Well, this affects operation only if the wiring is not 100%, but it also shows some weakness in the sync coding. The code from mbed has the same problem and I had it as well last spring. On T3.2 I found a solution that seemed to work reliable, but did not work on T3.6. I found the reason and resync looks quite reliable and fast.

    Please let me know if you can reproduce the problem as feedback If you are interested in my resync-solution let me know.

    regards Andi

  8. #8
    Senior Member brtaylor's Avatar
    Join Date
    Mar 2016
    Location
    Portland, OR
    Posts
    537
    Quote Originally Posted by hw999 View Post
    Hi Brian

    the arrival of my first T3.6 was a good reason to end a loooong break. I had a look at your latest SBUS-coding and it worked right away. Thanks for the work.

    However - if I pull the SBUS signal wire from the X8R and reconnect, the program quite often hangs and is unable to resync.

    Well, this affects operation only if the wiring is not 100%, but it also shows some weakness in the sync coding. The code from mbed has the same problem and I had it as well last spring. On T3.2 I found a solution that seemed to work reliable, but did not work on T3.6. I found the reason and resync looks quite reliable and fast.

    Please let me know if you can reproduce the problem as feedback If you are interested in my resync-solution let me know.

    regards Andi
    Hi Andi,

    It took a few tries, but I was able to reproduce the problem. Yes, I'd be interested in seeing your resync solution.

    Thanks!
    Brian

  9. #9
    Hi Brian

    here my sync routine :

    //------------------------------------------------------------
    int Teensy_SBUS::trySBUSSync(){

    int i;

    elapsedMillis waiting; // "waiting" starts at zero


    #ifdef DEBUG_SBUSTRYSYNC
    Serial.println("TrySync");
    #endif


    trySync++; // for statistics only, member of class, to be stored on SD card for reliability check

    for (i=1; i<25; i++) {
    sbusData[i] = 0;
    }

    while(port1.available()) // clear any data in buffer, port1.clear() worked on T3.2, on T3.6 probably not
    port1.read();

    waiting = 0;

    while((port1.available() <25)&&(waiting<50)){ // let buffer fill, but stop after 50ms
    delay(1);
    }

    if (port1.available() <25){ // looks like no packet came in
    memcpy(channels,failsafeChannels,36); // Teensy must failsafe now on its own
    SBUS_status=SBUS_NO_PACKET; // not SBUS convention, used in this program
    }
    else{
    SBUS_status=readSBUSpacket(); // integrity is checked in this routine as well

    }


    #ifdef DEBUG_SBUSTRYSYNC
    printSBUSBytesHEX();
    printChannelData();
    #endif


    return SBUS_status;
    }
    //------------------------------------------------------------

    Do you have knowledge when the frame lost bit is actually activated on X8R ? Is in this context one frame one packet ? How many lost frames does it take for the failsafe ?

    regards

    Andi

  10. #10
    Senior Member brtaylor's Avatar
    Join Date
    Mar 2016
    Location
    Portland, OR
    Posts
    537
    Quote Originally Posted by hw999 View Post
    Hi Brian

    here my sync routine :

    //------------------------------------------------------------
    int Teensy_SBUS::trySBUSSync(){

    int i;

    elapsedMillis waiting; // "waiting" starts at zero


    #ifdef DEBUG_SBUSTRYSYNC
    Serial.println("TrySync");
    #endif


    trySync++; // for statistics only, member of class, to be stored on SD card for reliability check

    for (i=1; i<25; i++) {
    sbusData[i] = 0;
    }

    while(port1.available()) // clear any data in buffer, port1.clear() worked on T3.2, on T3.6 probably not
    port1.read();

    waiting = 0;

    while((port1.available() <25)&&(waiting<50)){ // let buffer fill, but stop after 50ms
    delay(1);
    }

    if (port1.available() <25){ // looks like no packet came in
    memcpy(channels,failsafeChannels,36); // Teensy must failsafe now on its own
    SBUS_status=SBUS_NO_PACKET; // not SBUS convention, used in this program
    }
    else{
    SBUS_status=readSBUSpacket(); // integrity is checked in this routine as well

    }


    #ifdef DEBUG_SBUSTRYSYNC
    printSBUSBytesHEX();
    printChannelData();
    #endif


    return SBUS_status;
    }
    //------------------------------------------------------------

    Do you have knowledge when the frame lost bit is actually activated on X8R ? Is in this context one frame one packet ? How many lost frames does it take for the failsafe ?

    regards

    Andi
    Hi Andi,

    Can you try this development branch and let me know if it fixes the sync issues that you're having?
    https://github.com/bolderflight/SBUS/tree/updatedSync

    Thanks much!
    Brian

  11. #11
    Senior Member brtaylor's Avatar
    Join Date
    Mar 2016
    Location
    Portland, OR
    Posts
    537
    Quote Originally Posted by hw999 View Post
    Do you have knowledge when the frame lost bit is actually activated on X8R ? Is in this context one frame one packet ? How many lost frames does it take for the failsafe ?
    I had a bug in the code for the failsafe and lost frames, which I noticed while looking into making the sync more robust. Fixes have been pushed to the master branch and the development branch I posted previously testing out the more robust sync. Additionally, I did some testing on my X8R and X4R. With both of these receivers, as soon as they lose connection to the transmitter the lost frames starts counting. 102 frames, or a little more than 900 milliseconds later, the failsafe is activated.

    Best,
    Brian

  12. #12
    Hello brian,
    thanks for the sbus library. i am having problem in scaling the values. i can see that, when transmitter is sending 982 (minimum value on pixhawk), the code receives it as 172 and when it sends 2006,it receives as 1811. this becomes nonlinear, i dont understand how to recover and map the values for a servo.please help me on this.Thank u

  13. #13
    Senior Member brtaylor's Avatar
    Join Date
    Mar 2016
    Location
    Portland, OR
    Posts
    537
    Quote Originally Posted by chandra2sekhar2000 View Post
    Hello brian,
    thanks for the sbus library. i am having problem in scaling the values. i can see that, when transmitter is sending 982 (minimum value on pixhawk), the code receives it as 172 and when it sends 2006,it receives as 1811. this becomes nonlinear, i dont understand how to recover and map the values for a servo.please help me on this.Thank u
    Are you trying to use this library to receive SBUS signals from a receiver, send SBUS commands to a servo or both?

    If receiving SBUS signals from a receiver, which receiver are you using? What is the minimum and maximum values using the read function, rather than the readCal function?

    Thanks,
    Brian

  14. #14
    Quote Originally Posted by brtaylor View Post
    Are you trying to use this library to receive SBUS signals from a receiver, send SBUS commands to a servo or both?

    If receiving SBUS signals from a receiver, which receiver are you using? What is the minimum and maximum values using the read function, rather than the readCal function?

    Thanks,
    Brian
    Hi,brian
    thanks for your kind reply. immediately after making this post, i was able to solve the issue, by mapping the outputs. receiver outputs was min 982, max 2006. so scaled it to that range from (172 to 1811)..Thank u

  15. #15
    Junior Member
    Join Date
    Sep 2017
    Posts
    4
    This library has been very useful for me while setting up a joystick emulator with a Teensy LC and a FrSky XM receiver so I can use my Taranis transmitter as a Windows USB game controller.

    I'm mapping channels 1 through 6 to the joystick analog axes, rotations, and sliders successfully.

    However, I've run in to a problem. I'm also trying to map the remaining 10 channels (7 through 16) to act like joystick buttons and set a button to be pressed whenever the input from the SBUS channel is over a threshold. I seem to get this to work for three to four buttons at a time, but whenever I try to add code for more buttons/channel readings it seems I no longer get the SBUS library read function to return true any longer. Serial.print statements still produce output in the loop function before the read call, but nothing after ever is executed and the joystick basically never updates as a result.

    I'm new to C++ and Arduinos so perhaps I'm just overlooking something obvious in my code?

    Code:
    #include <SBUS.h>
    
    #define SBUS_MIN 172 // minimum value SBUS input
    #define SBUS_MAX 1811 // maximum value SBUS input
    #define ANALOG_MIN 0 // minimum value analog joystick output
    #define ANALOG_MAX 1023 // maximum value analog joystick output
    #define SBUS_ON 1600; // minimum value SBUS input to determine if button should be considered pressed
    
    SBUS sbus(Serial1);
    
    uint16_t channels[16];
    uint8_t failSafe;
    uint16_t lostFrames = 0;
    
    void setup() {
      sbus.begin();
    }
    
    void loop() {
      if (!sbus.read(&channels[0], &failSafe, &lostFrames)) return;
     
      Joystick.X(mapSbusToAnalog(channels[0]));
      Joystick.Y(mapSbusToAnalog(channels[1]));
      Joystick.Z(mapSbusToAnalog(channels[2]));
      Joystick.Zrotate(mapSbusToAnalog(channels[3]));
      Joystick.sliderLeft(mapSbusToAnalog(channels[4]));
      Joystick.sliderRight(mapSbusToAnalog(channels[5]));
    
      Joystick.button(1, mapSbusToDigital(channels[6]));
      Joystick.button(2, mapSbusToDigital(channels[7]));
      Joystick.button(3, mapSbusToDigital(channels[8]));
    //  Joystick.button(4, mapSbusToDigital(channels[9]));
    //  Joystick.button(5, mapSbusToDigital(channels[10]));
    //  Joystick.button(6, mapSbusToDigital(channels[11]));
    //  Joystick.button(7, mapSbusToDigital(channels[12]));
    //  Joystick.button(8, mapSbusToDigital(channels[13]));
    //  Joystick.button(9, mapSbusToDigital(channels[14]));
    //  Joystick.button(10, mapSbusToDigital(channels[15]));
    }
    
    long mapSbusToAnalog(uint16_t& value) {
      return (value - SBUS_MIN) * (ANALOG_MAX - ANALOG_MIN) / (SBUS_MAX - SBUS_MIN) + ANALOG_MIN;
    }
    
    boolean mapSbusToDigital(uint16_t& value) {
      return value >= SBUS_ON;
    }
    Whenever I uncomment the lines that set button 4 and/or 5, it seems I never get a SBUS packet read again. Sometimes button 4 seems to not cause this, sometimes it does... I initially tried all of them and that did not work. I slowly enable lines and was testing with Serial.print debug statements to isolate the problem when I found out that I could enable 3 or 4 buttons before the problem appeared again.

    Am I overloading the Teensy LC somehow? Did I maybe get a bad Teensy LC? Is this some SBUS nuance I don't understand? Is this the joystick library? Is it my bad coding? I'm not even sure where to start looking further. Any ideas would be very appreciated!
    Last edited by aemyers; 09-27-2017 at 06:14 PM.

  16. #16
    Senior Member brtaylor's Avatar
    Join Date
    Mar 2016
    Location
    Portland, OR
    Posts
    537
    Can you post or link the code for the Joystick class? I'm not seeing anything obvious, but I want to try to replicate the issue.

    Brian

  17. #17
    Junior Member
    Join Date
    Sep 2017
    Posts
    4
    Quote Originally Posted by brtaylor View Post
    Can you post or link the code for the Joystick class? I'm not seeing anything obvious, but I want to try to replicate the issue.

    Brian
    I'm using the default Joystick code that comes with Teensyduino 1.39 (Arduino 1.8.3).

  18. #18
    Senior Member brtaylor's Avatar
    Join Date
    Mar 2016
    Location
    Portland, OR
    Posts
    537
    I'm not able to replicate it completely since I'm not familiar with the joystick functionality, but I played some with outputting everything to the screen using Serial.print statements. That return that you have after the if statement is troubling. Can you try the following?

    Code:
    #include <SBUS.h>
    
    #define SBUS_MIN 172 // minimum value SBUS input
    #define SBUS_MAX 1811 // maximum value SBUS input
    #define ANALOG_MIN 0 // minimum value analog joystick output
    #define ANALOG_MAX 1023 // maximum value analog joystick output
    #define SBUS_ON 1600; // minimum value SBUS input to determine if button should be considered pressed
    
    SBUS sbus(Serial1);
    
    uint16_t channels[16];
    uint8_t failSafe;
    uint16_t lostFrames = 0;
    
    void setup() {
      sbus.begin();
    }
    
    void loop() {
      if (sbus.read(&channels[0], &failSafe, &lostFrames)) {
        Joystick.X(mapSbusToAnalog(channels[0]));
        Joystick.Y(mapSbusToAnalog(channels[1]));
        Joystick.Z(mapSbusToAnalog(channels[2]));
        Joystick.Zrotate(mapSbusToAnalog(channels[3]));
        Joystick.sliderLeft(mapSbusToAnalog(channels[4]));
        Joystick.sliderRight(mapSbusToAnalog(channels[5]));
    
        Joystick.button(1, mapSbusToDigital(channels[6]));
        Joystick.button(2, mapSbusToDigital(channels[7]));
        Joystick.button(3, mapSbusToDigital(channels[8]));
        Joystick.button(4, mapSbusToDigital(channels[9]));
        Joystick.button(5, mapSbusToDigital(channels[10]));
        Joystick.button(6, mapSbusToDigital(channels[11]));
        Joystick.button(7, mapSbusToDigital(channels[12]));
        Joystick.button(8, mapSbusToDigital(channels[13]));
        Joystick.button(9, mapSbusToDigital(channels[14]));
        Joystick.button(10, mapSbusToDigital(channels[15]));
      }
    }
    
    long mapSbusToAnalog(uint16_t& value) {
      return (value - SBUS_MIN) * (ANALOG_MAX - ANALOG_MIN) / (SBUS_MAX - SBUS_MIN) + ANALOG_MIN;
    }
    
    boolean mapSbusToDigital(uint16_t& value) {
      return value >= SBUS_ON;
    }

  19. #19
    Junior Member
    Join Date
    Sep 2017
    Posts
    4
    Quote Originally Posted by brtaylor View Post
    Can you try the following?
    Same problem exists still. However, you motivated me to revert to basic isolation efforts again and if I remove all the Joystick calls together and just do Serial.print calls with results from SBUS, I can easily read all the values on all channels no problem. It has to be the Joystick code, right?

    I've poked around through a few threads of people doing custom joysticks, but they seem to modify the supporting code heavily. I'm going to have to dig deeper into all this I suppose. Thank you for at least looking at all this with me Brian! I sincerely appreciate your library and your attention.

  20. #20
    Junior Member
    Join Date
    Sep 2017
    Posts
    4
    Playing with the Joystick class a bit more, I did the following test which works fine.
    Code:
    int a;
    unsigned long toggle;
    boolean state;
    
    void setup() {
      a = 0;
      toggle = millis();
      state = false;
    }
    
    void loop() {
    
      if (++a > 1023) a = 0;
      Joystick.X(a);
      Joystick.Y(a);
      Joystick.Z(a);
      Joystick.Zrotate(a);
      Joystick.sliderLeft(a);
      Joystick.sliderRight(a);
    
      if (millis() - toggle < 2000) return;
      toggle = millis();
      state = !state;
      Joystick.button(1, state);
      Joystick.button(2, state);
      Joystick.button(3, state);
      Joystick.button(4, state);
      Joystick.button(5, state);
      Joystick.button(6, state);
      Joystick.button(7, state);
      Joystick.button(8, state);
      Joystick.button(9, state);
      Joystick.button(10, state);
    }
    So, it seems to be something about using the Joystick class with the SBUS library that causes the SBUS read to fail.

    Could there be some timing issue somewhere?

  21. #21
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,591
    Is there some way I could give this a try here? I don't have any hardware to give me the SBUS data into Serial1.

  22. #22
    Senior Member brtaylor's Avatar
    Join Date
    Mar 2016
    Location
    Portland, OR
    Posts
    537
    Quote Originally Posted by PaulStoffregen View Post
    Is there some way I could give this a try here? I don't have any hardware to give me the SBUS data into Serial1.
    Hi Paul, the library contains functionality to write SBUS packets as well, which need to be sent every 10ms. If you loopback Serial1 TX to Serial1 RX, this code will get you a good SBUS packet into Serial1.

    Code:
    #include "SBUS.h"
    
    SBUS x8r(Serial1);
    
    IntervalTimer myTimer;
    
    void setup() {
      Serial.begin(115200);
      while(!Serial){}
      x8r.begin();
      myTimer.begin(SendSbus, 10000);
    }
    
    void loop() {
      uint16_t channels[16];
      uint8_t failSafe;
      uint16_t lostFrames = 0;
      if (x8r.read(&channels[0], &failSafe, &lostFrames)) {
        Serial.println("Good Sbus packet received");
      }
    }
    
    void SendSbus() {
      uint16_t channels[16];
      x8r.write(&channels[0]);
    }
    I'll be traveling until Monday of next week, but happy to help debug after that.

  23. #23
    Junior Member
    Join Date
    Jul 2018
    Posts
    1
    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 by Dannyboyfl; 07-18-2018 at 07:25 PM. Reason: Posting from a phone...

  24. #24
    Senior Member brtaylor's Avatar
    Join Date
    Mar 2016
    Location
    Portland, OR
    Posts
    537
    Quote Originally Posted by Dannyboyfl View Post
    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...

  25. #25
    Senior Member brtaylor's Avatar
    Join Date
    Mar 2016
    Location
    Portland, OR
    Posts
    537
    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.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •