Saturday, August 27, 2011

XBee Enabled Joystick pIII

If you are arriving at part III first, check out the first two parts.

Xbee Enabled Joystick, part I
Xbee Enabled Joystick, part II

I finally got around to demonstrating this project. It has been a long time in the making. Throwing an Arduino with an XBee shield onto my homemade RC boat, Das Boot seemed like the simplest method to demonstrate the 'XBee Enabled Joystick'.


Setup

The setup is the same as before in the first two parts. I only changed the sample rate on the joystick XBee to 0x021, which translates to 33ms, or about 30Hz. Below you can find sample code I used to demonstrate this project. I'll admit, the code was quick and dirty, but demonstrates some principles of parsing the XBee sample packet.

Enjoy the video!




Schematic

I'm including the schematic for the transmitting XBee (the black box seen in the video with the blinking LEDs). Really, it is quite simple.


Board **Updated

This is the board layout for the transmitting XBee (black box). All the joystick outputs are routed to the ADC and GPIO pins of the XBee, like the schematic shows.

Top

Bottom

Example Code


// Simple sketch that takes in XBee sample data and converts
// it to usuable PWM servo control signals.  This example will
// control 2 servos, throttle and rudder (steering).

#include <Servo.h>

#define BUFFER_SIZE   50
#define THROTTLE_PIN  9
#define RUDDER_PIN    10
#define THROTTLE_ADC  2
#define RUDDER_ADC    1
#define SERVO_MIN     900
#define SERVO_MAX     2100

#define XBEE_START    0x7E
#define XBEE_CMDID    0x83
#define XBEE_ADC_RES  10
#define XBEE_ADC_CTR  (0x0001 << ((XBEE_ADC_RES) - 1))
#define XBEE_NUM_ADC  5

#define SERIAL_TIMEOUT  10000
#define SERIAL_BAUD     115200

Servo throttle;  // Throttle servo
Servo rudder;    // Rudder servo, steers the vehicle

int rxbuffer[BUFFER_SIZE];
int data_count = 0;
unsigned int buttons = 0;
unsigned long axis[5];

// Simple function that indefinitely waits for a byte over serial
unsigned char get_byte();
// Same as above, but can be given a timeout.  If it takes too long
// to receive a byte, the functions returns 0
unsigned char get_byte(int timeout);
// Returns the length of the sensor packet sent from the XBee
int get_length();
// Parses the packet from the XBee.  Return 1 if a valid packet
// has been received.
int get_packet();

unsigned char get_byte()
{
  while (!Serial.available()) {;}
  return Serial.read();
}

unsigned char get_byte(int timeout)
{
  int i = 0;
  while (!Serial.available() && i < timeout) {timeout++;}
  if (Serial.available()) {
    return Serial.read();
  } else {
    return 0;
  }
}

int get_length()
{
  int length = 0;
  // Get two bytes from the serial stream, which equal the
  // length of the packet
  length = (get_byte() << 8) | get_byte();
  return length;
}

int get_packet()
{
  int i, j = 0;
  int length = 0;
  int num_samples = 0;
  int channel_ind_msb = 0;
  int channel_ind_lsb = 0;
  unsigned char checksum = 0;
  unsigned char adc_msb = 0, adc_lsb = 0;
  char c = 0;
  // First step is to read in the length
  length = get_length();
  // Next figure out if this is the command we're looking for
  if (get_byte() != XBEE_CMDID) {
    return 0;
  }
  checksum += XBEE_CMDID;
  
  // The next couple bytes tell us a little more about this packet
  // Right now, we won't do anything with them, other than add them
  // to our checksum
  checksum += get_byte();  // Source Address MSB
  checksum += get_byte();  // Source Address LSB
  checksum += get_byte();  // Source Address RSSI
  checksum += get_byte();  // Source Address Options
  
  // The next byte contains the number of samples
  num_samples = get_byte();
  checksum += num_samples;
  
  // Repeat the following steps for for each sample.  Hopefully, 
  // for this program this will always be 1.
  for (i=0; i < num_samples; i++) {
    
    // Find out which lines are active
    channel_ind_msb = get_byte();
    checksum += channel_ind_msb;
    channel_ind_lsb = get_byte();
    checksum += channel_ind_lsb;
    
    // If any digital lines are active, read them in
    if ((channel_ind_msb & 0x01) || channel_ind_lsb) {
      // Right now, not doing anything with this data
      checksum += get_byte();
      checksum += get_byte();
    }
        
    // Now, read in all the ADC values
    for (j=0; j < 5; j++) {
      if (channel_ind_msb & 0x01 << (j+1))
      {
        // There is a reading for this ADC
        adc_msb = get_byte();
        checksum += adc_msb;
        adc_lsb = get_byte();
        checksum += adc_lsb;
        // Join the bytes into an int
        axis[j] = (adc_msb << 8) | adc_lsb;
      }
    }
    
  }
  // return 1 if there is a correct checksum
  if ((0xFF - checksum) == get_byte()) 
  {
    return 1;
  } else {
    return 0;
  }
}

void setup() {
  int i=0;
  // Start serial port at SERIAL_BAUD bps.
  // For this example, it should be 115200:
  Serial.begin(SERIAL_BAUD);
  //Set up some pins as PWM for a servo
  rudder.attach(RUDDER_PIN, SERVO_MIN, SERVO_MAX);
  throttle.attach(THROTTLE_PIN, SERVO_MIN, SERVO_MAX);
  // Zero out the joystick axis values
  for (i=0; i < XBEE_NUM_ADC; i++)
  {
    axis[i] = 0;
  }
}

void loop() {
  // Let's parse us an XBee sample packet!
  if (get_byte(SERIAL_TIMEOUT) == XBEE_START) {
    if (get_packet())
    {
      // Only command the servos if a valid
      // packet has been received.
      rudder.write((axis[RUDDER_ADC]*180)/1024);
      throttle.write((axis[THROTTLE_ADC]*180)/1024);
    }
  }
}

39 comments:

  1. Heyy... Very Nice Project haan!! Cool....
    Which motor you have used here??? and how you are controlling your "Direction Plate"????

    ReplyDelete
  2. The motor is a Hobbyking motor,
    http://www.hobbyking.com/hobbyking/store/uh_viewitem.asp?idproduct=5430&aff=304010

    and the rudder is controlled by an old Hitec 55 servo. I'll have to do a writeup on my boat. I have another video of it on my youtube channel

    http://youtu.be/UC4OHopGD1s

    ReplyDelete
  3. Woah!! Cool configuration.
    But i am wondering about what is within the black box( transmitter )?

    ReplyDelete
  4. There, I updated the post to include the board layout of the black box. The schematics for the black box are included. That is the really neat part, there is no additional microcontroller connected to the joystick. The XBee uses its ADCs and GPIOs to gather data and automagically send it to the Arduino.

    ReplyDelete
  5. Hi again, I complettly understan everithing on the left side of de schemics of the black box, but, what are the lonly thins on the right, one loks like a voltage divider or something, and the other leds an stuff by their own...?

    ReplyDelete
    Replies
    1. I realize there could be some better markings on that schematic. U1 is a 3.3V voltage regulator, hence the 5V in and 3.3V out. There are two status LEDs, one for 5V to tell that the board is powered, and one for 3.3V to tell that the 3.3V regulator is working. Then, on the far right there is a DC barrel connector jack, which is where you plug in the 5V in.

      Delete
  6. This comment has been removed by the author.

    ReplyDelete
  7. I was wondering how your sketch works when you never include the xbee library at the beginning. There are other xbee receiving commands that I see in the Xbee examples of RX that aren't included either. Have you updated this sketch ? If so can you upload it ? I'm trying to do what you seem to have done.

    Thanks !!!

    ReplyDelete
    Replies
    1. The entire sketch is there. I actually don't use the XBee library. It manually parses the packets from the serial port. I'm not familiar with the XBee library, but it might offer a simpler solution.

      Delete
  8. I set up two servos and have 2 xbees that communicate packets and you're sketch didn't work for me. Nothing happened. You must have the controller connected to a PC. I was trying to use a stand alone pot connected to a power supply and xbee as the remote. Arduino is on the receiving side with receiving xbee.

    ReplyDelete
    Replies
    1. You must configure the XBee connected to the joystick to automatically sample the ADCs and send the samples to a specific address. I cover this in Part II.

      http://blog.ilektronx.com/2011/07/xbee-enabled-joystick-part-ii.html

      If you are not receiving anything with the arduino it must be an XBee configuration problem.

      Delete
  9. Not true. I can see packets just like in your Part II. When I move the joystick connected to the transmitter Xbee, the X-CTU hex values change accordingly to the designated pin used on the receiving Xbee. Your sketch is not decoding my packets.

    ReplyDelete
    Replies
    1. Can you correctly manually decode the packets and verify that the XBees are in API mode and that both have the correct baud rate?

      If you post the stream of what you are seeing through X-CTU, I can try to take a look at it and try to tell if the incoming data to the XBee is correct.

      Delete
  10. 7E 00 12 83 12 34 28 00 01 06 04 00 00 02 51 02 0D 03

    ReplyDelete
  11. Something is not right with that packet. It almost looks correct. It is sending ADC readings for A1, A0 and shows that DIO 2 is enabled. However, what you posted is not a complete packet. It shows that the length is 0x0012 (decimal 18) and there are only 14 bytes following the packet (if you assume the last byte is a checksum). In addition, the last byte is not a valid checksum. The sketch is probably determining that it is not a valid packet and discarding.

    It is possible that the API definition has changed, which I will check. Which XBees are you using and with which firmware?

    ReplyDelete
  12. 7E 00 0E 83 12 34 38 00 01 06 04 00 04 02 08 01 FB E9

    Packet I received today above. The other I had written down from before.

    Xbee versions are Series 1 802.15.4 Firmware 10ED

    You can see my xbee config profiles from the files here that can be loaded into X-CTU:

    http://www.shaputer.com/xbee

    Thank you for your help !

    ReplyDelete
    Replies
    1. That looks like a better packet. I've used the 10ED firmware series 1, so there shouldn't be anything weird. I skimmed the .pro files, and I don't see anything strange with them.

      Also, do you have any indication that the arduino itself is receiving the serial data? What xbee shield are you using? The sparkfun shield has a switch to change which pins to use. The non-uart pins don't support very fast baud rates. One last question, which arduino are you using?

      Delete
  13. Arduino UNO R3 with the Adafruit Xbee adapter

    http://adafruit.com/products/126

    I don't have indication that the arduino is receiving serial data. Using pins 2 and 13 for Xbee RX/TX. Have tried other pins with no success. Which pins should you use for the data in this case ?

    ReplyDelete
    Replies
    1. The sketch listed only supports the hardware serial, pins 0 and 1 on the arduino. From arduino.cc

      UART TTL (5V) serial communication, which is available on digital pins 0 (RX) and 1 (TX)

      Hardware serial is your best bet. However, if you wish to use software serial, check out http://arduino.cc/en/Reference/SoftwareSerial


      You can modify the sketch to something like example, where you add the following lines

      #include

      SoftwareSerial mySerial(10, 11); // RX, TX

      Then, everywhere where there is 'Serial' replace it with 'mySerial'

      Delete
  14. I have verified communication with the Xbee and the Arduino board via pins 0-RX and 1-TX using Arduino's Serial Monitor. I had to use another program online that I could understand to change the packet length to 18 instead of 22.

    ReplyDelete
  15. If I could get the values to be between 0-1023 where around 500 is the neutral position, I think I can handle the rest of the programming. I just don't know how to program that. Unfortunately I don't understand your code.

    This is the sketch I used to get the data through the Arduino successfully. I understand this one.

    https://github.com/ricklon/Xbee-Joystick-Control/blob/master/arduino/XbeeControlledRobot256uno/XbeeControlledRobot256uno.pde

    ReplyDelete
  16. Checking out your .pro files, it looks like you have the baud rate set to 19200, my sketch is set to 115200, on the line

    #define SERIAL_BAUD 115200

    Try changing the line to

    #define SERIAL_BAUD 19200

    or whatever you have the interface rate set to for your XBees

    ReplyDelete
  17. Still reading that only 1.2V can go to an ADC pin on Xbee. This is my exact setup. This sketch almost works. I'll probably just go with Esplora and Xbee. No decoding.....that's my problem.

    http://nootropicdesign.com/projectlab/2012/02/18/xbee-robotics-platform/

    ReplyDelete
    Replies
    1. According to the XBee manual and my experience, the ADCs are 3.3V ADCs

      Delete
  18. Changed baud rate originally and didn't work.

    ReplyDelete
  19. I enable 2 more pins on each Xbee and the packet stays the same size. Why doesn't it ever get more than 18 bytes ?

    ReplyDelete
    Replies
    1. The byte count will only increase with ADC pins enabled. Digital pins get lumped into a bit field in the first two bytes after the bytes signaling which pins are included in the sample. The sketch in this post counts which ADCs are enabled and reads in the appropriate values, regardless of length.

      Delete
  20. Thank you. That was very helpful. :+}

    ReplyDelete
  21. I really appreciate all the work and the fast responses you have given people on here. and thanks everyone for asking questions... your work helped me grasp API's a little better then I have before. I still feel like I'm missing something... especially with your sketch. (you lost me in a few parts there.) but overall you did an amazing job.

    ReplyDelete
  22. Hi Everyone, Its been a long time since anyone posted on this page. I just found this project and its really cool. I got everything working after a little digging through the previous posts. Having the correct baud rate helps :) I have a questions that I hope you can help with. When I run this I get both the throttle and rudder servo working at the same time? Only one Axis works and it moves both servos at the same time. I have one in Pin 9 and one in Pin10. How is this possible? Last question is do I need to make any connections on the sparkfun board other then Pins9,10 and the power for the servos. I see in your pic you have other wires and you use the open space to make connections. Do I have to do anything with the D0 and D1 pins from the Xbee. Do they go into anything? I had them go into Pins 1 and 2 on the Uno board but even w/o it the servos still act as one? Maybe you can post a picture or drawwing of the proper connection on the UNO. Thanks!!!

    ReplyDelete
    Replies
    1. Did you use the code verbatim? Or did you make some mods? If you post the modified code I can try checking it out. Are you writing the same value to both axis? If not, are you parsing the individual packets from the xbee correctly?

      My xbee board has some thermsistors attached to it, so you can ignore the other connections. All you need is 5V for the servos, the PWMs to Pins 9&10, and GND.

      Delete
    2. Thanks for getting back to me. I found the issue and it was with the way I hooked up the joystick to the Xbee. In your instructions, you mention using D0-D3 for the joystick inputs, so when I hooked up the joystick I started with D0 and D1. The Arduino code is looking at 1 and 2 not 0 and 1. I made the Xbee ADC inputs match the code and it works great now.

      Delete
  23. Nice job! I'm working on a serial joystick interface shield for an unoR3 that converts the signals to ppm output to either feed a radio tx module or radio trainer port for a fpv flightstick
    http://www.rcgroups.com/forums/showpost.php?p=22831596&postcount=44
    just wish I had a better understanding on the code

    ReplyDelete
    Replies
    1. If you just want to connect a joystick to an arduino and then spit out the proper signal to the trainer port, it should less complicated than this with the XBee. Have you already got the joystick hacked so that you can read the pot values from the separate axis? The tricky part will be combining them into a single channel that the trainer port understands. The regular Arduino PWM libraries can't do that, so you'll probably have to bit-bang it out (which can be a little tricky).

      I like the idea of having a proper joystick for FPV.

      Delete
  24. Im working on a wireless robot controlled car and I just cant seem to get a simple led to flash with my arcade joystick 4 micro switches and Xbee S1 modules, I have looked at 25 examples on how to hook it up and just cant seem to grasp it, I have configures the Xbee using XCTU and I can talk to both of the xbees through the terminal port. But when it comes to simple joystick to work cant get it.
    I would really appreciate some help and would be really greatfull

    ReplyDelete
    Replies
    1. Do you have a log or blog of your project? If you have some documentation of what you've attempted somewhere, I'd be happy to check it out.

      Delete
    2. hey thax for your reply, I got that bit working, now im stuck on reading from xbee transmitter to arduino xbee receiver. Cant get the xbee libraries to work on arduino, i f u have any free time add me on skype : kaba55 i will really appreciate it i don't have much time for my project and all i have is the programming left

      Delete
  25. I am stuck in a small problem im using arduino code and i need a way to get out of a if statement because im using a microswitch joystick its imposible to press both switches at same time so the last if statement wont function

    if(Rj==LOW && Fj==HIGH && Lj==HIGH && Bj == HIGH ){
    RIGHT(leftspeed,rightspeed);
    }
    else if(Fj== LOW && Rj==HIGH && Lj==HIGH && Bj == HIGH ){
    FORWARD(leftspeed,rightspeed);
    }
    else if(Fj==LOW && Rj==LOW){
    RIGHT_FORWARD(leftspeed,rightspeed);
    }
    I want it if Right and forward button is pressed to go only tho the RIGHT_FORWARD function and to skip RIGHT and LEFT Functions because they do different things

    ReplyDelete

Youtube Channel

Loading...