Separating value into high and low Java bytes

duragezic

Lifer
Oct 11, 1999
11,234
4
81
edit: Okay, reopened this.

I need to control an iRobot Create. I am using two Sun SPOT devices, which use the Java CLDC 1.1 libraries. All that I am concerned with is controlling its velocity and turning radius. The drive command to do this has a serial sequence like this:

[137] [velocity high byte] [velocity low byte] [radius high byte] [radius low byte]


So I need to separate my velocity and radius integer values into high and low bytes before I can send them to the iRobot. So here is my code to do that:

int velocity, radius;
byte velocityHigh, velocityLow, radiusHigh, radiusLow;

// assume here that velocity and radius get a valid value from somewhere else

// separate parameters into high and low bytes
velocityHigh = (byte) ((velocity & 0xFF00) >> 8);
velocityLow = (byte) (velocity & 0xFF);
radiusHigh = (byte) ((radius & 0xFF00) >> 8);
radiusLow = (byte) (radius & 0xFF);

// send drive parameters to iRobot over UART
// [137] [velocity high] [velocity low] [radius high] [radius low]
spot.sendUART((byte) 137);
spot.sendUART(velocityHigh);
spot.sendUART(velocityLow);
spot.sendUART(radiusHigh);
spot.sendUART(radiusLow);

So I tried controlling the iRobot Create, and it sort of works, but it spins around in place most of the time, when it shouldn't. The iRobot Create manual gives this example for the drive command:

"To drive in reverse at a velocity of -200mm/s while turning at a radius of 500mm, send the following serial sequence:

[137] [255] [56] [1] [244]
velocity = -200 = 0xFF38 = [0xFF] [0x38] = [255] [56]
radius = 500 = 0x01F4 = [0x01] [0xF4] = [1] [244]"

So I wanted to test my above code by hard-coding in velocity = -200 and radius = 500, separating them into high and low bytes, then printing them out to see if the decimal values of the high and low bytes matched the example above (velocity = [255] [56], radius = [1][244]). However, using my above code got these values:

velocity = [-1] [56]
radius = [1][-12]

So, the velocity low byte matches the example, and the radius high byte is correct. However, it doesn't seem like my code is necessarily wrong. For example, -1 in decimal is equal to 0xFF in hex, so the fact that -200 in decimal is equal to 0xFF38 means my above code was correct in separating, since the high byte is [0xFF] = [-1]. However, we also know that 0xFF is equal to 255 in decimal. So it seems like the iRobot Create manual is not using twos complement.

Moreover, the Java documentation states that a Java byte is 8 bits and can be -127 to +128. The drive command serial sequence starts with [137], but 137 is not in the range of a Java byte. Printing (byte) 137 in Java results in a negative number, but it still gets interpreted by the iRobot correctly, since it does indeed the drive.

I think the reason why it spins in place is the iRobot Create manual says this:

"Special cases for radius:
turn in place clockwise = hex FFFF
turn in place counter-clockwise = hex 0001"

Therefore, when I have a negative radius value, the high byte is always 0xFF, so it turns in place.

So it seems weird, but its like the iRobot Create does not use twos complement, but Java on the Sun SPOT and host computers do. And it seems to be the reason why the robot spins in place when it should not (it is nearly impossible for me to orient my controller to get it to intentionally spin in place).

So I guess what I'm asking is if anyone knows of a way to separate a Java integer into high and low bytes, but not use twos complement. Such that instead of -127 to +128 being the valid range, I want 0 to +255 to be the valid range. Let me know if anyone needs clarification. Thanks.
 

Onund

Senior member
Jul 19, 2007
287
0
0
It sounds like your Java program is functioning correctly. The byte values being stored seem to be correct. I can't figure out what's going wrong with what you have posted. Does the spot.sendUART only take 1 8bit word or will it eat everything you send it?

no 2s: [255][56]==[1111 1111][0011 1000]
w/ 2s: [-1][56] == [1111 1111][0011 1000]

no 2s: [1][244] == [0000 0001][1111 0100]
w/ 2: [1][-12] == [0000 0001][1111 0100]

137 => 10001001
Java thinks 10001001 as a byte is 105 for some odd reason (1101001). Some odd reason means I don't know and am too lazy to find out why it does that. I'm sure there are much smarter people around who know the reason for that

byte b137 = (byte) 10001001;
byte cast137 = (byte) 137;
int i137 = 137;
Byte otherByte = Byte.valueOf("-119");

System.out.println("byte Byte: "+b137); //>> byte Byte: 105
System.out.println("cast Byte: "+cast137); //>> cast Byte: -119
System.out.println("int Byte: "+i137); //>> int Byte: 137
System.out.println("otherByte: "+otherByte); //>> otherByte: -119

System.out.println("byte Byte: "+Integer.toBinaryString((int)b137)); //>> byte Byte: 1101001
System.out.println("cast Byte: "+Integer.toBinaryString((int)cast137)); //>> cast Byte: 11111111111111111111111110001001
System.out.println("int Byte: "+Integer.toBinaryString(i137)); //>> int Byte: 10001001
System.out.println("otherByte: "+Integer.toBinaryString((int)otherByte)); //>> otherByte: 11111111111111111111111110001001
 

duragezic

Lifer
Oct 11, 1999
11,234
4
81
Thanks for the reply.

Hmm, yeah it seems just because when I print for example [255] that it says [-1], to the iRobot, it should not matter. And it doesn't seem to, since 137 (even though displayed as something else by Java) is transmitted and interpreted by the iRobot as 137. And my programs are generally working, like if I tilt left, it turns left, and the velocity or forward/backward movement or the radius of the turn is directly tied to the angle of tilt, as it should be. It just turns in place a lot, when it shouldn't. It will turn in place when the radius high byte + low byte equals

0xFFFF
or
0x0001

which seems like it should be very hard to get those exact values (the accelerometer is very touchy and very hard to keep it at precisely the same angle). So I could just have a bug in my program. I don't think when I printed (byte) 137 that it displayed 105, but that was running on a different Java platform.

The API only says:

"void sendUART(byte val)

Send a byte over the UART."

It does not throw any exceptions. I didn't try sending anything but a Java byte. I can try testing that when I am at the right computer. So yeah, I'm not sure why it spins in place so often but does work correctly part of the time. I might be able to work on it more before its due, otherwise it is somewhat acceptable as is. :)

Thanks again



 

Onund

Senior member
Jul 19, 2007
287
0
0
it is strange. Can you print out the values being sent and maybe you can see where things are going wrong? It sounds like you are using some sort of input device, if you just hardcode movement commands will it work correctly?