trying to understand what I need to do with using values from received data
charleyshf
Posts: 165
Hoping to get some direction on what I am doing wrong..
I have been working with a Robo Claw motor controller hooked up to my prop since last week and I am either missing the ball here, or just not going about this the right way.
The end result I am looking for is to have the prop control my custom robot along with keeping track of my wheel encoders which the Robo Claw does, I just have to read the values in from the Robo Claw and use them "correctly". I probably could of used the quadencoders.spin file from the OBEX, but I wanted to have the Robo Claw do all the hard work so my prop has one less thing to deal with.
The code I am working on now will display all 6 bytes in the PST like this:
0,0,0,16,10000100,36
0,0,3,122,10000000,13
0,0,7,44,10000000,67
0,0,13,51,10000000,80
0,0,18,137,10000000,43
The first problem I have is the first 4 bytes will count up to 255 then the number to the left will go up by one, so if byte 4 goes over 255, byte 3 goes up by one, and byte 4 starts over at 0,so clearly I am not doing this correctly.
Next, if the encoder goes in reverse, and all 4 bytes are at 0, all 4 bytes go to 255 which is not what I expected to see, I would like to see "-" and then the count
I am VERY lost on byte 5, it contains 8 bits and it looks like it's displaying in PST backwards, how would I reverse that so PST show's it correctly, maybe more important though I am only interested in certain bits, maybe just the direction bit (Bit1) how would I just display that bit?
From the manual on the Robo Claw:
Byte 1,2,3 and 4 make up a long variable which is received MSB first and represents the current count which can be any value from 0 - 4,294,967,295. Each pulse from the quadrature encoder will increment or decrement the counter depending on the direction of rotation.
Byte 5 is the status byte for M1 decoder. It tracks counter under
Bit6 - Reserved
I have been working with a Robo Claw motor controller hooked up to my prop since last week and I am either missing the ball here, or just not going about this the right way.
The end result I am looking for is to have the prop control my custom robot along with keeping track of my wheel encoders which the Robo Claw does, I just have to read the values in from the Robo Claw and use them "correctly". I probably could of used the quadencoders.spin file from the OBEX, but I wanted to have the Robo Claw do all the hard work so my prop has one less thing to deal with.
The code I am working on now will display all 6 bytes in the PST like this:
0,0,0,16,10000100,36
0,0,3,122,10000000,13
0,0,7,44,10000000,67
0,0,13,51,10000000,80
0,0,18,137,10000000,43
The first problem I have is the first 4 bytes will count up to 255 then the number to the left will go up by one, so if byte 4 goes over 255, byte 3 goes up by one, and byte 4 starts over at 0,so clearly I am not doing this correctly.
Next, if the encoder goes in reverse, and all 4 bytes are at 0, all 4 bytes go to 255 which is not what I expected to see, I would like to see "-" and then the count
I am VERY lost on byte 5, it contains 8 bits and it looks like it's displaying in PST backwards, how would I reverse that so PST show's it correctly, maybe more important though I am only interested in certain bits, maybe just the direction bit (Bit1) how would I just display that bit?
From the manual on the Robo Claw:
Byte 1,2,3 and 4 make up a long variable which is received MSB first and represents the current count which can be any value from 0 - 4,294,967,295. Each pulse from the quadrature encoder will increment or decrement the counter depending on the direction of rotation.
Byte 5 is the status byte for M1 decoder. It tracks counter under
flow, direction, overflow and if the encoder is operational. The byte value represents:
Bit0 - Counter Underflow (1= Underflow Occurred, Clear After Reading)
Bit1 - Direction (0 = Forward, 1 = Backwards)
Bit2 - Counter Overflow (1= Underfl ow Occurred, Clear After Reading)
Bit3 - Reserved
Bit4 - Reserved
Bit5 - ReservedBit3 - Reserved
Bit4 - Reserved
Bit6 - Reserved
Bit7 - Encoder OK (1 = OK, 0 = FAIL)
Byte 6 is the CRC checksum. It is calculated the same way as sending a command. It can be used to validate the resulting data. The following example will read M1 counter register, status byte and CRC value with Robo Claw address set to 128.
''Baudrate to RoboClaw is at 2400 ''PINOUTS: ''P12 - Tx to RoboClaw Rx with 2.2k resistor ''P13 - Rx to RoboClaw Tx with 2.2k resistor CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 MS_001 = 80_000_000 / 1_000 ' To calculate when using the pause method in MS If you want to wait 0.1 seconds, ' you use pause(100). Want to wait 2.5 seconds, use pause(2_500). RX_Pin = 13 TX_Pin = 12 VAR long Lenc[6] OBJ SERIAL : "Extended_FDSerial_128ByteBuffers" PST : "Parallax Serial Terminal" PUB Main repeat showcountl PUB showcountl | j PST.START (2400) ' Starts PST PAUSE(1_000) SERIAL.START(RX_Pin, TX_Pin, 0, 2400) ' Starts FullDuplexSerial in another cog Pause (1_000) serial.RXflush serial.tx(128) ' this resets the encoder count to zero for both encoders Pause(2) serial.tx(18) ' same Pause(2) serial.tx(148 & %01111111) ' same pause (1_000) repeat repeat j from 0 to 5 'gets first 4 bytes which is encoder data serial.tx(128) serial.tx(16) Lenc[j] := Serial.rx Lenc[6] := 0 PST.Dec(Lenc[0]) PST.Str(string(",")) PST.Dec(Lenc[1]) PST.Str(String(",")) PST.Dec(Lenc[2]) PST.Str(String(",")) PST.Dec(Lenc[3]) PST.Str(String(",")) PST.Bin(Lenc[4],8) PST.Str(String(",")) PST.Dec(Lenc[5]) PST.Newline Pause (500) serial.RxFlush PUB pause(ms) | t t := cnt repeat ms waitcnt(t += MS_001)
I would really appreciate any ideas on this, thank you.
zip
18K
Comments
encoderValue := Lenc[0] << 24 | Lenc[1] << 16 | Lenc[2] << 8 | Lenc[3]
PST.Dec(encoderValue)
John Abshier
255,255,255,255 is one long which belongs together. If you convert it to hexadecimal things might get clearer because there you can simply concatenate the strings to convert it to a long.
$FF,$FF,$FF,$FF
Now make one long out of it: $FF_FF_FF_FF.
A long as such can have different meanings. For example you can store a 4 character string in one long. Or it can be an unsigned number with a range from 0 to 2^32 -1 which is something around 4 billion. Or it can be a signed number. Looking at the hexadecimal representation of signed number is also interesting:
$00_00_00_00 = 0
the max. positive number is:
$7F_FF_FF_FF which is something around 2 billion (= 2^31 - 1)
The negative numbers start from
$FF_FF_FF_FF = -1
The smallest negative number is:
$80_00_00_00 which is something around -2 billion ( = -2^31 )
So, if you get 4 times 255 it means that you received a -1.
Bitfields have the same rules as usual numbers. The most significant digit is on the left. And that's what your terminal shows you!
Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
If you are only interested in one bit you can extract it with boolean operations.
If you want to keep the value of that bit:
theBit := Lenc[ 4 ] & |< 1
1 is simply the number of the bit. But I think you want something like:
theBit := ( Lenc[ 4 ]>>1 ) & 1
Here 1 is as well the bit number you're interested in. You make the bit of interest the least significant bit by shifting all bits of the received byte to the right one time. The & 1 then will set all other bits to zero and only keep the value of bit 0 (which now contains the value of former bit 1).
Then you can replace the PST.BIN( Lenc[ 4 ], 8 ) by a
PST.BIN( theBit, 1 ) to display only that one bit
or
PST.BIN( Lenc[ 4 ]>>1, 1 )
if you only want to display the bit and you don't need the result in the code following.
@John, your code worked great!
@MagIO2, thank you for explaining what I was missing, I have to admit it's been a while since I was programming in spin and feel like I just went back to the beginning of it all, it's taken me a few reads to get a grip around it, thank you again.
and turn it into something like this:
This does not work and I am doing something wrong here, I also sent this to the PST, and I do not see anything that would resemble 2000. Any ideas where I went wrong? Thanks in advance
You have to use the array named byte which is buildin in SPIN:
byte[ @QspeedM1 ][0]
byte[ @QspeedM1 ][1] ....
So, in your code you'd call tx with byte[ @QspeedM1 ][y]
PS:
Currently I'm not sure of the order of the bytes of a long. Maybe you have to count y down from 3 to 0 to send it in the right order.
Thank you for getting back to me so quick!!
I tried the following code:
I also tried 0 to 3 on the repeat line, in PST I get back 007208 when I use 3 to 0 and I get 208700
when I use 0 to 3. Maybe I have the serial.tx line wrong??
Thanks again for your help
2000 in decimal is $7D0 in hex, or $00_00_07_D0 if you were to write it as four delimited byte values. What you're seeing in your output is 0, 0, 7, 208 (007208) or 208, 7, 0, 0 (208700). 208 is the decimal value of hex $D0.
So, given that when you read the numbers from the controller you're getting them high-byte to low-byte, you want to use the 0 to 3 loop, not the 3 to 0 loop.
If you're not comfortable reading hex numbers, you could just put a delimiter in loop, like this:
And one last note - Spin doesn't do any optimization, so if you want to squeeze the most speed out of your code, and save a little memory, use the CONSTANT keyword where possible, like this:
That tells Spin that the expression is constant, so it computes the value 41 at compile time, instead of doing it at runtime in your code.
0 * 2^24 + 0 * 2^16 + 7 * 2^8 + 208 = 2000
You have to understand what you output and hex helps here:
2000 = $00_00_07_D0
You have to transmit this as 4 separate bytes to the robo-thing. Sending it as single numbers to PST will first send $00 , then $00, then $07 and then $D0 which is 0 0 7 208 and without separator it reads like 007208 ;o)
2 = $00_00_00_02
Send it in the wrong order and you get 2 0 0 0 or 2000 without separator.
What the robo claw manual says is this:
I'm wondering about the 4 bytes (long) thing they are talking about.
These values are not enough for a valid representation of the speed. So you have to take more than one byte. The people who build the robo claw decided to use a long = 4 bytes. In a long you have 32 bits and a value range from 0 to 2^32 - 1. For signed numbers this range is simply divided in 2 parts, one representing the positive numbers (0 to 2^31-1 ) and the other half representing the negative numbers ( -1 to -2^31 ).
Problem is, that the serial interface is transferring data bytewise. So these longs representing the speeds of M1 and M2 have to be transferred bytewise. There is no way around that.
The developers also decided to transfer the longs as binary data and not as strings because this is the fastest way to transfer a long. This means that you simply transfer one byte after the other like they are stored in the memory. That's why they mentioned 4 bytes in the description. So, for your number 2000 which is equal to $00_00_07_D0 in hexadecimal writing (in hex two digits are exactly one byte) you have to send $00, then $00, the $07 and then $D0.
For the PST you did NOT send binary data, because we can not read that. You send the bytes converted to a decimal string or now in your latest version as a hexadecimal string, so that you can read it on the terminal.
The only question open so far is, what is the expected order of the 4 bytes. Do you have to send most significant byte (MSB) first or least significant byte (LSB) first? Depending on this answer you either have to count y upwards from 0 to 3 or downwards from 3 to 0.
Serial.tx(2)
Serial.tx(0)
Serial.tx(0)
Serial.tx(0)
is wrong. It is not 2000! It's either $02_00_00_00 or $00_00_00_02 for the robo claw depending of the way it assembels the bytes back to a long either MSB or LSB.
CRC = (address + cmd + speed.byte3 + speed.byte2 + speed.byte1 + speed.byte0 +
speed2.byte3 + speed2.byte2 + speed2.byte1 + speed2.byte0) & 0x7F
Adding up the individual byte values of a number is a lot different than adding the values as longs. For example, the number 4096 is $1000 in hex, or (16, 0) as two bytes. If you added it to itself, you'd get a value of 8192, $2000 hex, or (32, 0) as two bytes. Taking 8192 and masking off the bottom 7 bits would give you zero, whereas taking the individual bytes of the two values and adding them all up:
16 + 00 + 16 + 00 = 32
Short version: You need to add the bytes up. It'd probably be easiest to do it in your send loop. Every time you transmit a byte value, add it to a running sum. When you're done sending everything (except the crc), you take that running sum, mask the bottom 7 bits, and send those too.
You could create a function like this:
Then just use that in your code, like this:
I think that's where I was going wrong before(among other things), treating it like a long.. I have to take some time and get some reading in on this stuff, my only brain cell just lit up, fell out, and hit the floor.....
now where the hec did I leave the advil....
Thanks again