Description of the data exchange protocol between LPC2378 and COM-Express module over USB
Most of the I/Os comming with Robotino 3 are still connected to a NXP LPC2378 microcontroller (MC). In contrast to previous versions of Robotino the interface between the MC and Robotino's internal industral PC is no longer RS232 but USB. This page describes the protocol used for communication between MC and PC over USB.
Package assembly
All data send from PC to MC and vice versa has the form
Field name
|
Bytes
|
Description
|
Head
|
1
|
Start of package
|
Length
|
2
|
Length of package payload
|
Payload
|
|
Payload data
|
Checksum
|
2
|
Calculated from length and payload bytes
|
Head
The package header is the unique byte 0xAA.
Length
The number of bytes of the (not escaped) payload data.
package[1] = length & 0xFF;
package[2] = 0xFF & ( length >> 8 );
Payload
The package payload data. The payload is composed of one or more commands.
Checksum
Complement 2 of the sum of Length and Payload bytes before escaping.
uint16 calculate_checksum( const uint8* data, int dataSize )
{
uint16 out = 0;
for( int i=0; i<dataSize; ++i )
{
out += *p;
++data;
}
return 0xffff & ( (1<<16) - out );
}
Data escaping
The Head byte 0xAA must be unique through out all data send. By this the receiver knows that whenever it reads 0xAA that a new package begins. This is achieved by going through all the Length, Payload and Checksum bytes and whenever 0xAA or the escape byte 0x55 is found this byte is prefixed with 0x55 and the byte is xored with 0x20.
uint8* data; //the complete package data (Head, Length, Payload, Checksum)
uint8* escapedData; //buffer big enough to hold the escaped package data
for( int i=1; i<numBytesInData; ++i ) //not that we are starting at 1, we do not escape the Head
{
if( 0xAA == *data || 0x55 == *data )
{
*(escapedData+++) = 0x55;
*(escapedData++) = ( *data ^ 0x20 );
}
else
{
*(escapedData++) = *data;
}
++data;
}
When reading an escaped package look for the escape byte 0x55. When you found 0x55 in the stream read the next byte and xor it with 0x20 to get the unescaped value.
QByteArray read( int length ) const
{
QByteArray ba( length, 0 );
int i=0;
while( i<length )
{
char ch = 0;
if( 1 != _serial->read( (unsigned char*)&ch, 1 ) )
{
throw ParserException( "Error reading 1 byte" );
}
if( 0x55 == ch )
{
if( 1 != _serial->read( (unsigned char*)&ch, 1 ) )
{
throw ParserException( "Error reading 1 byte" );
}
ba[i] = ( ch ^ 0x20 );
}
else if( 0xAA == ch )
{
throw ParserException( "Found HEAD" );
}
else
{
ba[i] = ch;
}
++i;
}
return ba;
}
Commands
Field name
|
Bytes
|
Description
|
Tag
|
1
|
The command tag
|
Length
|
1
|
Number of bytes of command data
|
Data
|
|
The command data. If Length=0 there is no Data field at all.
|
Tag
Name
|
Value
|
Command data
|
Description
|
Direction
|
GET_HW_VERSION
|
1
|
none
|
Requesting the hardware version
|
PC->MC
|
HW_VERSION
|
2
|
String
|
Response to GET_HW_VERSION
|
MC->PC
|
GET_SW_VERSION
|
3
|
none
|
Requesting the software version
|
PC->MC
|
SW_VERSION
|
4
|
String
|
Response to GET_SW_VERSION
|
MC->PC
|
GET_DISTANCE_SENSOR_READINGS
|
5
|
none
|
Requesting the readings of all infrared distance sensors
|
PC->MC
|
DISTANCE_SENSOR_READINGS
|
6
|
Byte
|
Type
|
Description
|
0-1
|
uint16
|
raw ADC reading of distance sensor 0
|
...
|
16-17
|
uint16
|
raw ADC reading of distance sensor 8
|
|
Response to GET_DISTANCE_SENSOR_READINGS. See GET_ADC_PARAMETERS.
|
MC->PC
|
GET_ADC_PARAMETERS
|
7
|
none
|
Requesting the parameters of the AD converter(s).
|
PC->MC
|
ADC_PARAMETERS
|
8
|
Byte
|
Type
|
Description
|
0
|
uint8
|
bit resolution of the ADC
|
1-4
|
float
|
ADC reverence voltage in Volts
|
|
Response to GET_ADC_PARAMETERS.
|
MC->PC
|
SET_MOTOR_SPEED
|
9
|
Byte
|
Type
|
Description
|
0
|
uint8
|
motor number
|
1-2
|
int16
|
speed set-point in rpm (rounds per minute)
|
|
Set the speed set-point for one motor
|
PC->MC
|
GET_ALL_MOTOR_SPEEDS
|
10
|
none
|
Requesting the speed of all motors
|
PC->MC
|
ALL_MOTOR_SPEEDS
|
11
|
Byte
|
Type
|
Description
|
0-1
|
int16
|
speed of motor 0 in rpm
|
...
|
6-7
|
int16
|
speed of motor 3 in rpm
|
|
Response to GET_ALL_MOTOR_SPEEDS.
|
MC->PC
|
SET_MOTOR_POSITION
|
12
|
Byte
|
Type
|
Description
|
0
|
uint8
|
motor number
|
1-4
|
int32
|
motor position in encoder ticks
|
|
Set the position counter of one motor
|
PC->MC
|
GET_ALL_MOTOR_POSITIONS
|
13
|
none
|
Requesting the position of all motors
|
PC->MC
|
ALL_MOTOR_POSITIONS
|
14
|
Byte
|
Type
|
Description
|
0-3
|
int32
|
position of motor 0
|
...
|
12-15
|
int32
|
position of motor 4
|
|
Response to GET_ALL_MOTOR_POSITIONS.
|
MC->PC
|
SET_MOTOR_PID_PARAMETERS
|
15
|
Byte
|
Type
|
Description
|
0
|
uint8
|
motor number
|
1
|
uint8
|
kp
|
2
|
uint8
|
ki
|
3
|
uint8
|
kd
|
|
Set PID parameters of one motor.
|
PC->MC
|
GET_ALL_MOTOR_PID_PARAMETERS
|
16
|
none
|
Requesting the PID controller parameters of all motors
|
PC->MC
|
ALL_MOTOR_PID_PARAMETERS
|
17
|
Byte
|
Type
|
Description
|
0
|
uint8
|
kp of motor 0
|
1
|
uint8
|
ki of motor 0
|
2
|
uint8
|
kd of motor 0
|
...
|
9
|
uint8
|
kp of motor 3
|
10
|
uint8
|
ki of motor 3
|
11
|
uint8
|
kd of motor 3
|
|
Response to GET_ALL_MOTOR_PID_PARAMETERS.
|
MC->PC
|
SET_ALL_DIGITAL_OUTPUTS
|
18
|
Byte
|
Type
|
Description
|
0
|
uint8
|
each bit reflects the setting of one digital outputs port at Robotino's IO connector
|
|
Set digital output ports at Robotino's IO connector.
|
PC->MC
|
SET_ALL_RELAYS
|
19
|
Byte
|
Type
|
Description
|
0
|
uint8
|
bit 0 is the set-state of relay 0 at Robotino's IO connector
bit 1 is the set-state of relay 1 at Robotino's IO connector
|
|
Set the relays at Robotino's IO connector.
|
PC->MC
|
SET_ODOMETRY
|
20
|
Byte
|
Type
|
Description
|
0-3
|
float
|
x-position in meters
|
4-7
|
float
|
y-position in meters
|
8-11
|
float
|
rotation in radians
|
|
Set the odometry to the given pose
|
PC->MC
|
SET_ODOMETRY_ROTATION
|
21
|
Byte
|
Type
|
Description
|
0-3
|
float
|
rotation in radians
|
|
Set the odometry to the given rotation. Used when a gyroscope is connected to the PC to forward the gyroscope readings to the MC where the odometry is processed.
|
PC->MC
|
GET_ODOMETRY
|
22
|
none
|
Request odometry readings from the MC
|
PC->MC
|
ODOMETRY
|
23
|
Byte
|
Type
|
Description
|
0-3
|
float
|
x-position in meters
|
4-7
|
float
|
y-position in meters
|
8-11
|
float
|
rotation in radians
|
|
Response to GET_ODOMETRY
|
MC->PC
|
GET_MOTOR_CURRENT_CONVERSION_FACTOR
|
24
|
none
|
Request the motor current conversion factor from the MC
|
PC->MC
|
MOTOR_CURRENT_CONVERSION_FACTOR
|
25
|
float
|
Response to GET_MOTOR_CURRENT_CONVERSION_FACTOR. The factor in A/V (Ampere/Volt) to convert the motor current readings from the ADC into Ampere.
|
MC->PC
|
GET_ALL_MOTOR_CURRENT_READINGS
|
26
|
none
|
Request current readings from all motors
|
PC->MC
|
ALL_MOTOR_CURRENT_READINGS
|
27
|
Byte
|
Type
|
Description
|
0-1
|
uint16
|
ADC readings from motor 0 current sensor
|
...
|
6-7
|
uint16
|
ADC readings from motor 3 current sensor
|
|
Response to GET_ALL_MOTOR_CURRENT_READINGS.
|
MC->PC
|
GET_DISTANCE_SENSOR_AMPLIFICATION
|
28
|
none
|
Request the amplification between the distance sensor signal an the ADC input.
|
PC->MC
|
DISTANCE_SENSOR_AMPLIFICATION
|
29
|
float
|
Response to GET_DISTANCE_SENSOR_AMPLIFICATION. Amplification between the distance sensor signal an the ADC input.
|
MC->PC
|
GET_ANALOG_INPUT_AMPLIFICATION
|
30
|
none
|
Request the amplification between the analog input ports at Robotino's IO connector an the ADC input.
|
PC->MC
|
ANALOG_INPUT_AMPLIFICATION
|
31
|
float
|
Response to GET_ANALOG_INPUT_AMPLIFICATION. Amplification between the analog input port signal an the ADC input.
|
MC->PC
|
GET_ALL_ANALOG_INPUTS
|
32
|
none
|
Request all analog input readings.
|
PC->MC
|
ALL_ANALOG_INPUTS
|
33
|
Byte
|
Type
|
Description
|
0-1
|
uint16
|
ADC readings from analog input port 0
|
...
|
14-15
|
uint16
|
ADC readings from analog input port 8
|
|
Response to GET_ALL_ANALOG_INPUTS. Readings of all analog input ports.
|
MC->PC
|
GET_ALL_DIGITAL_INPUTS
|
34
|
none
|
Request all digital input readings.
|
PC->MC
|
ALL_DIGITAL_INPUTS
|
35
|
uint8
|
Response to GET_ALL_DIGITAL_INPUTS. Readings of all digital input ports.
|
MC->PC
|
Data types
Name
|
Number of bytes
|
Description
|
String
|
Depends of the TAGs data length
|
Seqeunce of characters. The string is not terminated by 0.
|
uint8
|
1
|
Unsigned character
|
int8
|
1
|
Signed character
|
uint16
|
2
|
Unsigned short. Serialization is little endian.
|
int16
|
2
|
Signed short. Serialization is little endian.
|
uint32
|
4
|
Unsigned int. Serialization is little endian.
|
int32
|
4
|
Signed int. Serialization is little endian.
|
float
|
4
|
Floating point number single precision. Serialization is little endian.
//encoding
char* data;
float f = 1.23f;
char* p = (char*)&f;
encodingData[0] = *(p++);
encodingData[1] = *(p++);
encodingData[2] = *(p++);
encodingData[3] = *(p++);
//decoding
float f2;
p = (char*)&f2;
*(p++) = encodingData[0];
*(p++) = encodingData[1];
*(p++) = encodingData[2];
*(p++) = encodingData[3];
|
Communication example
Communication between PC and MC is driven from the PC. Initially the PC will ask for the hardware and software version of the MC.
Byte number
|
Value
|
Description
|
0
|
0xAA
|
HEAD
|
1
|
0x04
|
Package length low byte
|
2
|
0x00
|
Package length high byte
|
3
|
0x01
|
GET_HW_VERSION
|
4
|
0x00
|
Data length of GET_HW_VERSION
|
5
|
0x03
|
GET_SW_VERSION
|
6
|
0x00
|
Data length of GET_SW_VERSION
|
7
|
?
|
Checksum low byte
|
8
|
?
|
Checksum high byte
|
Answer from MC
Byte number
|
Value
|
Description
|
0
|
0xAA
|
HEAD
|
1
|
0x0E
|
Package length low byte
|
2
|
0x00
|
Package length high byte
|
3
|
0x02
|
HW_VERSION
|
4
|
0x05
|
Data length of HW_VERSION
|
5
|
0x33
|
"3"
|
6
|
0x2E
|
"."
|
7
|
0x30
|
"0"
|
8
|
0x2E
|
"."
|
9
|
0x30
|
"0"
|
10
|
0x04
|
SW_VERSION
|
11
|
0x05
|
Data length of SW_VERSION
|
12
|
0x33
|
"3"
|
13
|
0x2E
|
"."
|
14
|
0x30
|
"0"
|
15
|
0x2E
|
"."
|
16
|
0x30
|
"0"
|
17
|
?
|
Checksum low byte
|
18
|
?
|
Checksum high byte
|