Page 1 of 1

Arduino Serial Code to RPi Serial Code

Posted: Mon Apr 29, 2019 10:16 pm
by krebera
Hi, all! I've been working with the lovely https://github.com/p-h-a-i-l/hoverboard-firmware-hack project on github. The host of the repo graciously supplied some Arduino C code to interface with the overridden hoverboard over a UART connection. I'm trying to get the code to run on a raspberry pi, which works a little differently. I've tried recreating this code in Python, and then in c++ trying out termios.h and wiringSerial.h.

I think the reason it isn't working is that I simply don't understand what's going on in the code. I feel like the for loop is just building the checksum (0 - the data bits). But at the same time, the mySerial.write() command uses the ups.UART_PACKET, which doesn't really make sense to me since only the ups.msgToHover is ever modified here. That being said, it's probably a lack of understanding on my part. Obviously something is working here because it works flawlessly on an arduino.

I started up minicom on the Pi and made a connection to the arduino in Hex mode to see if I couldn't just mimic the bits and the first thing I noticed is that although I had the code set up to send the exact same command every second, the hex bits didn't always match! Like between calls, even those first couple bits (like SOM and len) weren't always 0x02 and 0x07, which really surprised me. That's probably another thing I just don't understand well enough to make an informed guess about.

Here's the sample code for an Arduino / microcontroller:

Code: Select all

typedef struct MsgToHoverboard_t{
  unsigned char SOM;  // 0x02
  unsigned char len;  // len is len of ALL bytes to follow, including CS
  unsigned char cmd;  // 'W'
  unsigned char code; // code of value to write
  int16_t base_pwm;   // absolute value ranging from -1000 to 1000 .. base_pwm plus/minus steer is the raw PWM value
  int16_t steer;      // absolute value ranging from -1000 to 1000 .. wether steer is added or substracted depends on the side R/L
  unsigned char CS;   // checksumm
};

uint16_t baseSpeed = 0;

typedef union UART_Packet_t{
  MsgToHoverboard_t msgToHover;
  byte UART_Packet[sizeof(MsgToHoverboard_t)];
};

void setHoverboardPWM( int16_t base_pwm, int16_t steer )
{
  UART_Packet_t ups;

  ups.msgToHover.SOM = 2 ;  // PROTOCOL_SOM; //Start of Message;
  ups.msgToHover.len = 7;   // payload + SC only
  ups.msgToHover.cmd  = 'W'; // PROTOCOL_CMD_WRITEVAL;  // Write value
  ups.msgToHover.code = 0x07; // speed data from params array
  ups.msgToHover.base_pwm = base_pwm;
  ups.msgToHover.steer = steer;
  ups.msgToHover.CS = 0;

  for (int i = 0; i < ups.msgToHover.len; i++){
    ups.msgToHover.CS -= ups.UART_Packet[i+1];
  }

  mySerial.write(ups.UART_Packet,sizeof(UART_Packet_t));
}
What do you guys this is going on here? Any help is appreciated.
Thanks so much.

Re: Arduino Serial Code to RPi Serial Code

Posted: Mon Apr 29, 2019 11:06 pm
by scotty101
Have a look at C code tutorials that explain the Union typedef.
A Union will create a type definition that will exist in the same section of memory but can be many different data types. For example in this case it is both a structure of type MsgToHoverBoard and an array of bytes.
As the structure is written to, so is the array.

As for why you aren't getting the same values each time, no idea. You haven't shared enough about your setup.

Re: Arduino Serial Code to RPi Serial Code

Posted: Tue Apr 30, 2019 4:20 am
by krebera
Okay. So as the msgToHover is written to, the typedef union is automatically creating a byte array alongside it! That makes a lot of sense. Thank you for the explanation. That's a pretty cool way to get the data formatted.

As for the setup, I just had the arduino Tx into the RPi Rx, and had it write out (0,0) for speed and steer every 2000 millis. I then tested with (500,0) and (0,500) but I was caught up in the fact that even the bits that were not supposed to change would fluctuate between messages (usually in repetition, but still not the same one every time).

Re: Arduino Serial Code to RPi Serial Code

Posted: Tue Apr 30, 2019 8:03 am
by B.Goode
As for the setup, I just had the arduino Tx into the RPi Rx,


No doubt that is clear to you. But it is not detailed enough for people who can't see your setup.

Are you using the uart defined on 2 pins of the 40-way header of your RPi? Have you read the Raspberry Pi Foundation documentation:
both (uarts) are 3.3V devices, which means extra care must be taken when connecting up to an RS232 or other system that utilises different voltage levels. An adapter must be used to convert the voltage levels between the two protocols. Alternatively, 3.3V USB UART adapters can be purchased for very low prices.
Ref: https://www.raspberrypi.org/documentati ... on/uart.md

Re: Arduino Serial Code to RPi Serial Code

Posted: Tue Apr 30, 2019 3:43 pm
by krebera
Ah I see no why that wasn't enough information.
I am using the pi with a 3v3 logic level 32u4-based microcontroller running SoftwareSerial for pins 10 and 11. I have pin 11 (Software Tx) going to RPi Rx (BCM 15). I have the setup configured correctly, have the serial console disabled and get accurate readouts from other serial sources so I assume everything is configured correctly.

When I test the Pi itself, I just wire BCM 15 to BCM 14 to read the output.

Re: Arduino Serial Code to RPi Serial Code

Posted: Tue Aug 27, 2019 9:57 am
by sturesson
Have you got the communication to work?

Re: Arduino Serial Code to RPi Serial Code

Posted: Tue Aug 27, 2019 11:20 am
by hippy
This would be my rough and ready Python version of the Arduino code. Might need to swap the bytes round in AddWord if the endianess is wrong -

Code: Select all

def AddByte(s,b):
  return s + chr(b & 0xFF)

def AddWord(s,w):
  s = AddByte(s, w >> 8)
  s = AddByte(s, w )
  return s

def setHoverboardPWM(base_pwm, steer):
  s = ""
  s = AddByte(s, 2)        # som
  s = AddByte(s, 7)        # len
  s = AddByte(s, ord("w")) # cmd
  s = AddByte(s, 7)        # code
  s = AddWord(s, base_pwm) # base_pwm
  s = AddWord(s, steer)    # steer
 
  checksum = 0
  for c in s:
    checksum = checksum - ord(c)

  s = AddByte(s, checksum) # checksum

  ser.write(s)