Reading Second Axis on XBee S2's with Router AT and Coordinator API, direct IO

Working on an arduinoless joystick to control a snow plow robot using direct IO. I have the x axis of the code working but am not used to serial, can someone help me refine the code to work with the second axis as well. I am not sure how to pull the data from the D1 pin. I have been referencing the Xbee S2 Quick reference Guide: http://www.tunnelsup.com/xbee-s2-quick-reference-guide-cheat-sheet. The code i have thus far is a derivative of code found in the Arduino Cook book by Michael Margolis.

The Setup:

Controller - 2 axis joystick
Series 2 xbee in Router AT mode
X axis D0 - Set to ADC output
Y axis D1 - Set to ADC output

Receiver - Arduino Uno + series 2 xbee in Coordinator API mode
pin 9 led emulates x axis control
pin 12 led will emulate y axis control

The code which is working for the X axis:

#define LEDPINX 9
#define LEDPINY 12

void setup() {
Serial.begin(9600);
pinMode(LEDPINX, OUTPUT);
pinMode(LEDPINY, OUTPUT);
}

void loop() {

if (Serial.available() >= 21) { // Wait until we have a mouthful of data

if (Serial.read() == 0x7E) { // Start delimiter of a frame

// Skip over the bytes in the API frame we don’t care about
for (int i = 0; i < 18; i++) {
Serial.read();
}

// The next two bytes are the high and low bytes of the sensor reading
int analogHigh = Serial.read();
int analogLow = Serial.read();
int analogValue = analogLow + (analogHigh * 256);

// Scale the brightness to the Arduino PWM range
int brightness = map(analogValue, 0, 1023, 0, 255);

Serial.print(“Analog High”);
Serial.println(analogHigh);
Serial.print(“Analog Low”);
Serial.println(analogLow);
Serial.print(“Analog”);
Serial.println(analogValue);
Serial.print(“Brightness”);
Serial.println(brightness);
Serial.println(" ");
//delay(1000);

// Light the LED
analogWrite(LEDPINX, brightness);
}
}
}

I have the x axis of the code working but am not used to serial, can someone help me refine the code to work with the second axis as well.

First thing to do is get the XBee off the Serial pins, so you can use Serial to debug your code.

      // Skip over the bytes in the API frame we don't care about

including the number of bytes of data in the packet and the description of what data is in the packet.

You're not off to a great start.

I am able to pull up the serial in to monitor what the code is doing, is this what you are referring to?

I would like to not skip over all the bytes as i know the data for pin D1 is in there, I have not learned how to pull specific information from the transferring data. Can you aid in explaining how the D0 and D1 information is being pulled.

Thanks!!!!

Can you aid in explaining how the D0 and D1 information is being pulled.

First, you need to set D1 back to not being used. Open the serial monitor, and observe what is in a packet.

Then, set D1 back to being an analog in. Open the serial monitor again, and observe what is in a packet.

For one thing, the packet should be larger. The actual number of bytes in the packet should have gone up by two.

For another, one of the early fields should have changed. This field shows which of the Dx pins have data in the packet. The packet may contain data for D0 and D2, for instance. Or D1 and D3. Knowing which pins the data is for is often important, which is why the data is in the packet.

The data for the analog pins and the digital pins is in order in the packet. The data for D1 is the next two bytes after the data for D0.

Really appreciate all the help!

Ran the serial with:

Image is attached
D0 enabled and D1 disabled and then again with D0 enabled and D1 Enabled. I noticed the additional packets you mentioned:

with d1 disabled - 7E,0,12,92,0,13,A2,0,40,93,34,5F,9C,8A,1,1,0,0,1,0,A6,83
with d1 enabled - 7E,0,14,92,0,13,A2,0,40,93,34,5F,C8,7B,1,1,0,2,1,0,0,0,A6,64

Correct me if I am wrong:
-the change from 12 to 14 is the length
-9C to C8 is the Destination Network Address
-8A to 7B is the brodcast
-83 to 64 is the checksum

D1 Pin Disabled and then Enabled.jpg

Ah i get it…each of the pis has a high and low reading which is pulled from the data for each pin. By enabling another pin, two more bytes become available, one for the High and one for the Low. In this code the 1,0 before the A6,83 is for D0, how can i tell from the two lines of code which ones are associated with Pin D1? it looks like the D1 pin values moved in the segment or changed from when D1 was disabled to enabled. Once i know which two bytes are the high and low respectivly for pins D1, then i can skip all data except for these two bytes and read them out as a separate variable.

The 7E value is the start byte of an API frame. The next two values (00, 12, and 00, 14) are the MSB and LCB of the length field (18 and 20 bytes, respectively). The length does not include the length bytes or the checksum byte. The next byte (92 in both cases) is the frame type - RX I/O data received. The next 8 values, the same in both cases, is the 64 bit address of the sender. The next 2 values are the 16 bit address of the sender. I can't see why these changed. The next byte is 1 or 2, depending on the packet byte - directed or broadcast. The next byte is the number of samples - always 1. Next (0 in both cases) is the digital channel mask - 0 means no digital pin data. Next is the analog channel mask - 0 or 2. The number of bits set is the number of analog values to read. This is then followed by two bytes of digital data (if the digital channel mask is not 0) and then two bytes per analog value.

It does not look like your first example is sending any analog data. The second example is sending analog data for A1 only.

That is strange....I ensured that both d0 and d1 are set to adc on the transmitter side and on the receiver side with the arduino all the pins were left as default (disabled). Should I swap the pins to try d2 and d3 on the transmitter?. I have been reading that there may be some additional data or junk that can jump onto the d0 and d1 lines.

Thank you for the breakdown of the frame data!

Should I swap the pins to try d2 and d3 on the transmitter?

Yes. Show the new packets.

Paul

Attached are the frames with d2 enabled and d3 disabled, and then again with both d2 and d3 enabled.

d2 adc and d3 disabled - 7E,0,12,92,0,13,A2,0,40,93,24,5F,13,9D,1,1,0,0,4,2,7,93
d2 adc and d3 adc - 7E,0,14,92,0,13,A2,0,40,93,34,5F,13,9D,1,1,0,0,C,2,8,2,9,7F

The high and low pin for d2 is 7,93 and for d3 it is 9,7F?

The high and low pin for d2 is 7,93 and for d3 it is 9,7F?

No. The 4 and C are the analog channel mask values. 4 (0b0100) means that D2 is providing data. C (0b1100) means that D2 and D3 are providing data. The D2 data is 2,7. or 2,8 The C3 data is 2,9.

93 and 7F are the checksum values.

Got it working with d0 and d1 pins! Need to work on making the led fade smoother (the y axis basically just goes from on to off)

Attached is the frame and the 4 last digits are my outputs from the joystick.

Last four digits of the dataset:
“…X Axis High, X Axis Low, Y Axis High, Y Axis Low”

What I have:

//Setup LEDs
#define LEDPINX 9
#define LEDPINY 12

void setup() {
Serial.begin(9600);
pinMode(LEDPINX, OUTPUT);
pinMode(LEDPINY, OUTPUT);
}

void loop() {

if (Serial.available() >= 23) { // Pull data

if (Serial.read() == 0x7E) { // Start delimiter

for (int i = 0; i < 18; i++) {
Serial.read();
}

// The next two bytes are the high and low bytes of the sensor reading for the X Axis
int analogHighX = Serial.read();
int analogLowX = Serial.read();
// The next two bytes are the high and low bytes of the sensor reading for the Y Axis
int analogHighY = Serial.read();
int analogLowY = Serial.read();

//Values for X and Y axis
int analogValueX = analogLowX + (analogHighX * 256);
int analogValueY = analogLowY + (analogHighY * 256);

// Scale the brightness of LEDs
int brightnessX = map(analogValueX, 0, 1023, 0, 255);
int brightnessY = map(analogValueY, 0, 1023, 0, 255);

Serial.print("X “);
Serial.print(analogHighX);
Serial.print(” “);
Serial.print(analogLowX);
Serial.println(” ");
Serial.print("Y “);
Serial.print(analogHighY);
Serial.print(” “);
Serial.print(analogLowY);
Serial.println(” ");

// Light the LEDs
analogWrite(LEDPINX, brightnessX);
analogWrite(LEDPINY, brightnessY);
}
}
}

x and y output.jpg

I’d suggest skipping data in steps, with an explanation of what is being skipped, in case you decide to not just randomly ignore data.

      // Skip the packet size 
      for (int i = 0; i < 2; i++)
      {
        Serial.read();
      }

      // Skip the 64 bit address 
      for (int i = 0; i < 8; i++)
      {
        Serial.read();
      }
      // Scale the brightness of LEDs
      int brightnessX = map(analogValueX, 0, 1023, 0, 255);
      int brightnessY = map(analogValueY, 0, 1023, 0, 255);

A rather computationally intense way to divide by 4.

This is true, i will need to clean up my code a bit as it gets more complex. This will control the snowplows movement, now I'll add a another joystick to control the plow height and buttons to control my camera (which is on servos)....should be ready for the snow!

Just left them so i can hone in on differences in the joysticks or if i want to increase dead spots on the joystick Ex, if i only ever want to go in reverse at %50 the full speed of the robot I can introduce this here.

I also improved the voltage divider circuit, and figured out that i had the one led on a non PWM pin (the xbee shield was covering the fact that pin 11 is not PWM), this is why it would only turn on and off. The LEDs scale as expected and now i can print the PWM voltage to two other pins to control the 0-5V logic that the wheelchair joystick uses.

Don't need to do this necessary but is there a way i can transfer information back from the robot from the controller with the current setup: Router AT (controller) and Coordinator API (robot). Was thinking ultra sonic sensors behind the robot to ensure i don't back into things or potentially a microphone to transfer audio from the robot back to the controller.