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

  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
    Quote Originally Posted by brtaylor View Post
    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,f 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
    Hi Brian

    the updated code looks fine. Thanks for the information above.
    Frame==packet, right ? To sum it up : receiver looses connection with TX -> packet/frame status changes from SBUS_SIGNAL_OK to SBUS_SIGNAL_LOST for around 100 packets/frames -> then status changes to SBUS_SIGNAL_FAILSAFE. I hope i got it right.

    regards Andi

  13. #13
    Hi Brian

    I played around with the SBUS_SIGNAL_LOST a little bit. I started counting lost and received packets and transmit now the ratio via SPort to the Taranis-TX. At RSSI around 20-25 30-40% of the packages are still received. RSSI is fine, but what counts is the amount of packages received. SBUS-servos seem to be quite forgiving. I once made a test and if I remember well they still work at refresh rates below 1Hz.
    In the next few days I will make a test and drive a few kilometers. Earlier tests gave around 3000m range, but at that time i could not receive information about % of packets received.

    regards Andi

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

    the updated code looks fine. Thanks for the information above.
    Frame==packet, right ? To sum it up : receiver looses connection with TX -> packet/frame status changes from SBUS_SIGNAL_OK to SBUS_SIGNAL_LOST for around 100 packets/frames -> then status changes to SBUS_SIGNAL_FAILSAFE. I hope i got it right.

    regards Andi
    Yes, that's all correct! Logically it makes sense too, even with my RX and TX close to each other I'll occasionally get a lost packet, which is expected by the system. So it makes sense that it waits for a short bit to re-establish the connection before going into failsafe mode.

    Brian

  15. #15
    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

  16. #16
    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

  17. #17
    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

  18. #18
    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 07:14 PM.

  19. #19
    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

  20. #20
    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).

  21. #21
    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;
    }

  22. #22
    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.

  23. #23
    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?

  24. #24
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,684
    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.

  25. #25
    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.

Posting Permissions

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