CRC Issues in Serial Packet Mode

General discussion of using Roboclaw motor controllers
bsorel
Posts: 18
Joined: Sat Jan 16, 2016 11:02 am
CRC Issues in Serial Packet Mode

Post by bsorel »

I've been having problems issuing commands in serial packet mode. I've traced the problem to the CRC it seems. I dropped back to standard serial to make sure that my program and communication baudrate is sound and had no problem. I should state that i am using a PIC 18F4520 as the MCU with coding in C. Maybe someone could find something wrong with my CRC formula or the method at which I am sending the packets.
I'll attach the code that contains the CRC functions as well as the part which executes the instructions to drive both motors forward at a predefined quarter speed. thanks in advance, cause i'm stuck.

Code: Select all

void crc_clear()
 {
  crc = 0;
  crc_msb = 0;
  crc_lsb = 0;
 }
 
//Calculates CRC16 of nBytes of data in byte array message
u16 crc16(unsigned char *packet, int nBytes)
 {
  for (crc_cnt = 0; crc_cnt < nBytes; crc_cnt++)
   {

    crc = crc ^ (packet[crc_cnt] << 8);
    for (crc_bit = 0; crc_bit < 8; crc_bit++)
     {
      if (crc & 0x8000) 
       {
        crc = (crc << 1) ^ 0x1021;
       }
      else 
       {
        crc = crc << 1;
       }
     }
   }
  return crc;
 }
 
           if(receive == 1)  //Quarter Speed Command Up
           {
            getRequestUDP[0] = 0;
            
            //SPI_Ethernet_24j600_sendUDP(destIP, sourcePort, destPort, ok1, 4);
            crc_clear();
            packet = (address << 16) | (M1_Forward << 8) | quarter_speed;
            nBytes = 3;
            crc16(packet, nbytes);
            crc_msb = (crc >> 8);
            crc_lsb = crc;
            uart1_write(address);
            uart1_write(M1_Forward);
            uart1_write(quarter_speed);
            uart1_write(crc_msb);
            uart1_write(crc);
            delay_ms(20);
            RoboClaw_status = uart1_read();
            //SPI_Ethernet_24j600_sendUDP(destIP, sourcePort, destPort, roboclaw_status, 1);
            packet = (address << 16) | (M2_Forward << 8) | quarter_speed;
            crc_clear();
            RoboClaw_status = 0;
            nBytes = 3;
            crc16(packet, nbytes);
            crc_msb = crc >> 8;
            crc_lsb = crc;
            uart1_write(address);
            uart1_write(M2_Forward);
            uart1_write(quarter_speed);
            uart1_write(crc_msb);
            uart1_write(crc);
            delay_ms(20);
            RoboClaw_status = uart1_read();
            //SPI_Ethernet_24j600_sendUDP(destIP, sourcePort, destPort, roboclaw_status, 1);
            receive = 0;

            SPI_Ethernet_24j600_doPacket() ;  // process incoming Ethernet packets
           }
User avatar
Basicmicro Support
Posts: 1594
Joined: Thu Feb 26, 2015 9:45 pm
Re: CRC Issues in Serial Packet Mode

Post by Basicmicro Support »

Can you show what the CRC value calculated is for a given command? Reply witht he full command string sent to the Roboclaw and the calculated CRC16. Thanks.

Also jsut a quible:

uart1_write(crc_msb);
uart1_write(crc);
delay_ms(20);
RoboClaw_status = uart1_read();

I think the uart1_write(crc) should be uart1_write(crc_lsb);

uart1_write probably only writes the low byte of crc but its probably safer to explicity send the crc_lsb instead of the whole 16bit crc to uart1_write

Also the ack on a write command is garunteed to return in under 10ms. In actual practice the ack will return in a few hundred microseconds. So you can make your delay_ms shorter.
bsorel
Posts: 18
Joined: Sat Jan 16, 2016 11:02 am
Re: CRC Issues in Serial Packet Mode

Post by bsorel »

Thanks for the tip! I had to reverse the commands and send crc_lsb = crc before bitshifting not after. That got things up and running however i am having a heck of a time issuing speed and direction controls. I am using commands 0,1,4 and 5 yet when i assign the values for these commands it seems to be responsding as if its in 7 bit mode. My forward command with a value of 32 seems to make my motor almost full pin, whereas my reverse command with a value of 96 changes direction but now the speed is very slow. The stop command of with a value of 0 turns it forward again about quarter speed. What is going on here? I tried 7 bit control but then nothing happened. I tried to install your program but got this error microsoft.visuallbasic.powerpacks.vs version 10.0.0.0 be installed in the global assembly cache (GAC) first. Anyways here is my code maybe i''ve missed something very basic?

Code: Select all

          if(receive == 1)  //Quarter Speed Command Up
           {
            getRequestUDP[0] = 0;
            SPI_Ethernet_24j600_doPacket() ;  // process incoming Ethernet packets
            //SPI_Ethernet_24j600_sendUDP(destIP, sourcePort, destPort, ok1, 4);

            packet = (address << 16) | (M1_Forward << 8) | quarter_speed;
            crc_clear();
            nBytes = 3;
            crc16(packet, nbytes);
            crc_lsb = crc;
            crc_msb = (crc >> 8);
            uart1_write(address);
            uart1_write(M1_Forward);
            uart1_write(quarter_speed);
            uart1_write(crc_msb);
            uart1_write(crc);
            delay_ms(20);
            RoboClaw_status = uart1_read();
            //SPI_Ethernet_24j600_sendUDP(destIP, sourcePort, destPort, roboclaw_status, 1);
            packet = (address << 16) | (M2_Forward << 8) | quarter_speed;
            crc_clear();
            RoboClaw_status = 0;
            nBytes = 3;
            crc16(packet, nbytes);
            crc_lsb = crc;
            crc_msb = crc >> 8;
            uart1_write(address);
            uart1_write(M2_Forward);
            uart1_write(quarter_speed);
            uart1_write(crc_msb);
            uart1_write(crc);
            delay_ms(20);
            RoboClaw_status = uart1_read();
            //SPI_Ethernet_24j600_sendUDP(destIP, sourcePort, destPort, roboclaw_status, 1);
            RoboClaw_status = 0;
            receive = 0;

            SPI_Ethernet_24j600_doPacket() ;  // process incoming Ethernet packets
           }
           
          if(receive == 2)  //Quarter Speed Command Down
           {

            getRequestUDP[0] = 0;
            SPI_Ethernet_24j600_doPacket() ;  // process incoming Ethernet packets
            //SPI_Ethernet_24j600_sendUDP(destIP, sourcePort, destPort, ok1, 4);
            packet = (address << 16) | (M1_Reverse << 8) | three_quarter_speed;
            crc_clear();
            nBytes = 3;
            crc16(packet, nbytes);
            crc_lsb = crc;
            crc_msb = (crc >> 8);
            uart1_write(address);
            uart1_write(M1_Reverse);
            uart1_write(three_quarter_speed);
            uart1_write(crc_msb);
            uart1_write(crc);
            delay_ms(20);
            RoboClaw_status = uart1_read();
            //SPI_Ethernet_24j600_sendUDP(destIP, sourcePort, destPort, roboclaw_status, 1);
            packet = (address << 16) | (M2_Reverse << 8) | three_quarter_speed;
            crc_clear();
            RoboClaw_status = 0;
            nBytes = 3;
            crc16(packet, nbytes);
            crc_lsb = crc;
            crc_msb = crc >> 8;
            uart1_write(address);
            uart1_write(M2_Reverse);
            uart1_write(three_quarter_speed);
            uart1_write(crc_msb);
            uart1_write(crc);
            delay_ms(20);
            RoboClaw_status = uart1_read();
            //SPI_Ethernet_24j600_sendUDP(destIP, sourcePort, destPort, roboclaw_status, 1);
            RoboClaw_status = 0;
            receive = 0;
           }
          
          SPI_Ethernet_24j600_doPacket() ;  // process incoming Ethernet packets

          if(receive == 3)  //Motor Stop
           {

            getRequestUDP[0] = 0;
            SPI_Ethernet_24j600_doPacket() ;  // process incoming Ethernet packets
            //SPI_Ethernet_24j600_sendUDP(destIP, sourcePort, destPort, ok1, 4);

            packet = (address << 16) | (M1_Forward << 8) | motor_stop;
            crc_clear();
            nBytes = 3;
            crc16(packet, nbytes);
            crc_lsb = crc;
            crc_msb = (crc >> 8);
            uart1_write(address);
            uart1_write(M1_Forward);
            uart1_write(motor_stop);
            uart1_write(crc_msb);
            uart1_write(crc);
            delay_ms(20);
            RoboClaw_status = uart1_read();
            //SPI_Ethernet_24j600_sendUDP(destIP, sourcePort, destPort, roboclaw_status, 1);
            packet = (address << 16) | (M2_Forward << 8) | motor_stop;
            crc_clear();
            RoboClaw_status = 0;
            nBytes = 3;
            crc16(packet, nbytes);
            crc_lsb = crc;
            crc_msb = crc >> 8;
            uart1_write(address);
            uart1_write(M2_Forward);
            uart1_write(motor_stop);
            uart1_write(crc_msb);
            uart1_write(crc);
            delay_ms(20);
            RoboClaw_status = uart1_read();
            //SPI_Ethernet_24j600_sendUDP(destIP, sourcePort, destPort, roboclaw_status, 1);
            RoboClaw_status = 0;
            receive = 0;
           } 
User avatar
Basicmicro Support
Posts: 1594
Joined: Thu Feb 26, 2015 9:45 pm
Re: CRC Issues in Serial Packet Mode

Post by Basicmicro Support »

I dont see where you are defining the quarter_speed or three_quarter_speed values. Im assuming its in other code. Can you show a complete program(preferably simplified that shows the problem. I would recommend a simple program that just switchs back and forth between quarter_speed and three_quarter_speed every couple of seconds as a test.
bsorel
Posts: 18
Joined: Sat Jan 16, 2016 11:02 am
Re: CRC Issues in Serial Packet Mode

Post by bsorel »

Here's the rest of the code as it applies to the Roboclaw.

Code: Select all

u16 crc;
u8 crc_msb;
u8 crc_lsb;
u8 crc_cnt;
u8 crc_bit;
u8 nbytes;
u8 address = 0x80;
u8 M1_Forward = 0x00;
u8 M1_Reverse = 0x01;
u8 M2_Forward  = 0x04;
u8 M2_Reverse = 0x05;
u8 drive_M1 = 0x06;
u8 drive_M2 = 0x07;
u8 forward_quarter = 0x50;
u8 reverse_quarter = 0x30;
u8 stop = 0x40;
u8 M1_Position = 0x10;
u8 M2_Position = 0x11;
u8 motor_stop = 0x00;
u8 quarter_speed = 0x20;
u8 half_speed = 0x40;
u8 three_quarter_speed = 0x60;
u8 full_speed = 0x7F;
u32 packet;
u8 byte3; //high byte
u8 byte2;
u8 byte1;
u8 byte0;
u32 encoder1;
u32 encoder2;
u8 S3S4S5_Modes = 0x4A;
u8 e_stop_en = 0x02;
u8 e_stop_clr = 0x00;
char receive;
u8 RoboClaw_status;
char ok1[] = "OK:1";
//Clears CRC

void crc_clear()
 {
  crc = 0;
  crc_msb = 0;
  crc_lsb = 0;
 }
 
//Calculates CRC16 of nBytes of data in byte array message
u16 crc16(unsigned char *packet, int nBytes)
 {
  for (crc_cnt = 0; crc_cnt < nBytes; crc_cnt++)
   {

    crc = crc ^ (packet[crc_cnt] << 8);
    for (crc_bit = 0; crc_bit < 8; crc_bit++)
     {
      if (crc & 0x8000) 
       {
        crc = (crc << 1) ^ 0x1021;
       }
      else 
       {
        crc = crc << 1;
       }
     }
   }
  return crc;
 }
 
 while(1)
         { /*
          bad_synch = 0;              // set bad synchronization variable to zero
          cnt = 0;                    // reseting interrupt counter
          sync_flag = 0;              // reseting sync flag
          count_flag = 0;             // reseting count flag
          INT1IF_bit = 0;
          INT1IE_bit = 0;             // disable external interrupt on RB1 (for sync and sample)
          INT0IF_bit = 0;
          INT0IE_bit = 1;             // enable external interrupt on RB0 (start sync procedure)
           */
          SPI_Ethernet_24j600_doPacket() ;  // process incoming Ethernet packets
          asm CLRWDT;   //Clears watchdog timer

          if(receive == 1)  //Quarter Speed Command Up
           {
            getRequestUDP[0] = 0;
            SPI_Ethernet_24j600_doPacket() ;  // process incoming Ethernet packets
            //SPI_Ethernet_24j600_sendUDP(destIP, sourcePort, destPort, ok1, 4);

            packet = (address << 16) | (M1_Forward << 8) | quarter_speed;
            crc_clear();
            nBytes = 3;
            crc16(packet, nbytes);
            crc_lsb = crc;
            crc_msb = (crc >> 8);
            uart1_write(address);
            uart1_write(M1_Forward);
            uart1_write(quarter_speed);
            uart1_write(crc_msb);
            uart1_write(crc);
            delay_ms(20);
            RoboClaw_status = uart1_read();
            //SPI_Ethernet_24j600_sendUDP(destIP, sourcePort, destPort, roboclaw_status, 1);
            packet = (address << 16) | (M2_Forward << 8) | quarter_speed;
            crc_clear();
            RoboClaw_status = 0;
            nBytes = 3;
            crc16(packet, nbytes);
            crc_lsb = crc;
            crc_msb = crc >> 8;
            uart1_write(address);
            uart1_write(M2_Forward);
            uart1_write(quarter_speed);
            uart1_write(crc_msb);
            uart1_write(crc);
            delay_ms(20);
            RoboClaw_status = uart1_read();
            //SPI_Ethernet_24j600_sendUDP(destIP, sourcePort, destPort, roboclaw_status, 1);
            RoboClaw_status = 0;
            receive = 0;

            SPI_Ethernet_24j600_doPacket() ;  // process incoming Ethernet packets
           }
           
          if(receive == 2)  //Quarter Speed Command Down
           {

            getRequestUDP[0] = 0;
            SPI_Ethernet_24j600_doPacket() ;  // process incoming Ethernet packets
            //SPI_Ethernet_24j600_sendUDP(destIP, sourcePort, destPort, ok1, 4);
            packet = (address << 16) | (M1_Reverse << 8) | three_quarter_speed;
            crc_clear();
            nBytes = 3;
            crc16(packet, nbytes);
            crc_lsb = crc;
            crc_msb = (crc >> 8);
            uart1_write(address);
            uart1_write(M1_Reverse);
            uart1_write(three_quarter_speed);
            uart1_write(crc_msb);
            uart1_write(crc);
            delay_ms(20);
            RoboClaw_status = uart1_read();
            //SPI_Ethernet_24j600_sendUDP(destIP, sourcePort, destPort, roboclaw_status, 1);
            packet = (address << 16) | (M2_Reverse << 8) | three_quarter_speed;
            crc_clear();
            RoboClaw_status = 0;
            nBytes = 3;
            crc16(packet, nbytes);
            crc_lsb = crc;
            crc_msb = crc >> 8;
            uart1_write(address);
            uart1_write(M2_Reverse);
            uart1_write(three_quarter_speed);
            uart1_write(crc_msb);
            uart1_write(crc);
            delay_ms(20);
            RoboClaw_status = uart1_read();
            //SPI_Ethernet_24j600_sendUDP(destIP, sourcePort, destPort, roboclaw_status, 1);
            RoboClaw_status = 0;
            receive = 0;
           }
          
          SPI_Ethernet_24j600_doPacket() ;  // process incoming Ethernet packets

          if(receive == 3)  //Motor Stop
           {

            getRequestUDP[0] = 0;
            SPI_Ethernet_24j600_doPacket() ;  // process incoming Ethernet packets
            //SPI_Ethernet_24j600_sendUDP(destIP, sourcePort, destPort, ok1, 4);

            packet = (address << 16) | (M1_Forward << 8) | motor_stop;
            crc_clear();
            nBytes = 3;
            crc16(packet, nbytes);
            crc_lsb = crc;
            crc_msb = (crc >> 8);
            uart1_write(address);
            uart1_write(M1_Forward);
            uart1_write(motor_stop);
            uart1_write(crc_msb);
            uart1_write(crc);
            delay_ms(20);
            RoboClaw_status = uart1_read();
            //SPI_Ethernet_24j600_sendUDP(destIP, sourcePort, destPort, roboclaw_status, 1);
            packet = (address << 16) | (M2_Forward << 8) | motor_stop;
            crc_clear();
            RoboClaw_status = 0;
            nBytes = 3;
            crc16(packet, nbytes);
            crc_lsb = crc;
            crc_msb = crc >> 8;
            uart1_write(address);
            uart1_write(M2_Forward);
            uart1_write(motor_stop);
            uart1_write(crc_msb);
            uart1_write(crc);
            delay_ms(20);
            RoboClaw_status = uart1_read();
            //SPI_Ethernet_24j600_sendUDP(destIP, sourcePort, destPort, roboclaw_status, 1);
            RoboClaw_status = 0;
            receive = 0;
           }
bsorel
Posts: 18
Joined: Sat Jan 16, 2016 11:02 am
Re: CRC Issues in Serial Packet Mode

Post by bsorel »

It looks like I've jumped the gun a little bit on solving the CRC issue. It turns out that I never reset the RoboClaw back to serial packet mode after changing it to simple serial. So once again the commands that I am sending are met with only a slight flashing of the STAT1 Led. The packet I am testing is in Hex 80 00 20, equaling address, command and value. The result of the CRC is D2 6C MSB then LSB. According to the online CRC calculation it should be 0x3000. I sent you my code for the CRC calculation and function call. Is there anything wrong with what I've done. I used the example in the datasheet. Thanks in advance!
bsorel
Posts: 18
Joined: Sat Jan 16, 2016 11:02 am
Re: CRC Issues in Serial Packet Mode

Post by bsorel »

updated the code so that it more closely resembles the integer formats used in the datasheet:

Code: Select all

unsigned int crc16(unsigned char *packet, int nBytes) {
for (crc_byte = 0; crc_byte < nBytes; crc_byte++) {
crc = crc ^ (packet[crc_byte] << 8);
for (crc_bit = 0; crc_bit < 8; crc_bit++) {
if (crc & 0x8000) {
crc = (crc << 1) ^ 0x1021;
} else {
crc = crc << 1;
}
}
}
return crc;
}
It returns the same result D2 6C. In an edit to the previous post it looks like your using the CRC-CCITT (XModem) polynomial so the expected result should be 0x1F38.
User avatar
Basicmicro Support
Posts: 1594
Joined: Thu Feb 26, 2015 9:45 pm
Re: CRC Issues in Serial Packet Mode

Post by Basicmicro Support »

Use this to check your CRC16 is calculated correctly.

http://depa.usst.edu.cn/chenjq/www2/sof ... lation.htm

Click the CCIT-16 button to set the bit length and polynomial. Then type in the bytes your are sending without spaces.

If you are sending 80 00 20 then the CRC16 should be 1F 38.

Here are the functions we use in our Arduino library:


void crc_clear()
{
crc = 0;
}

void crc_update (uint8_t data)
{
int i;
crc = crc ^ ((uint16_t)data << 8);
for (i=0; i<8; i++)
{
if (crc & 0x8000)
crc = (crc << 1) ^ 0x1021;
else
crc <<= 1;
}
}

Instead of sending a full packet to the crc calculation routine we just update the CRC when we send each byte.

For you it would be something like this:

crc_ckear();
crc_update(0x80);
uart1_write(0x80);
crc_update(0x00);
uart1_write(0x00);
crc_update(0x20);
uart1_write(0x20);
crc_msb = crc>>8;
crc_lsb = crc&0xFF;
bsorel
Posts: 18
Joined: Sat Jan 16, 2016 11:02 am
Re: CRC Issues in Serial Packet Mode

Post by bsorel »

Thanks for the update. I will test and try out, since you may write some PIC library's in the future it may be relevant for you. Last night I just sent my calculated CRC value appended to the end of my message to get things moving. I'm just issuing static commands in my application (for right now) so it'll temporarily do. I got my calculation here:

http://www.lammertbies.nl/comm/info/crc ... ation.html

I used the CRC-CCITT (XModem) to get the result of 1F 38.
User avatar
Basicmicro Support
Posts: 1594
Joined: Thu Feb 26, 2015 9:45 pm
Re: CRC Issues in Serial Packet Mode

Post by Basicmicro Support »

Yes, 1021 poly is also called CCITT-Xmodem though there appears to be at least two varients(eg inverted poly).

Post Reply