-
Notifications
You must be signed in to change notification settings - Fork 3
RPi to Arduino Communication
WARNING: The RPi to Arduino functionality is mostly complete for now. However, the implementation is fairly different from what is described here. This document needs to be updated to reflect the current implementation.
Due to limitations to the RPi GPIO, it has been decided to use an Arduino (here called Arduino proxy) for general pin input/output operations. However, having a flexible and reliable communication between the two devices is not quite trivial. This document gives an overview of how the RPi and Arduino communicate together.
Here are the following main goals of the RPi-Arduino communication and the Arduino proxy itself:
- Reliable: Possible to detect if a message has been transmitted successfully.
- Flexible: Possible to control extra pins without flashing again the Arduino.
- Safe: Checks should be put in place to assure the correct command is executed. Moreover, the Arduino should go in a safe configuration if the RPi becomes unresponsive.
- Verbose: The RPi should know as much as possible about what is happening on the Arduino. For example, if the Arduino encounters an error, it should tell the RPi about it.
The communication stack consists of a few components all working together to reliably send messages between the two devices.
First, we use serial for the physical link.
Second, we need an actual format to send the messages across. For simplicity and flexibility purposes, Protocol Buffers is used.
Next, we need to have a way to detect errors that would be happening during the transmission. While serial does offer some basic checks with a parity bit, it could be good to have a bit more error checking. Adding a small 16 bit CRC should be enough for detecting most common errors in the transmission.
Finally, because serial only send streams of bytes, we need to be able to combine those bytes into packets. For this, we use COBS to provide packet framing. This allows to use the 0x0 byte to separate each of the packets.
All together, here is how the communication stack looks:

Or, another way to look at it:

Please look at the repo for the latest Protobuf definitions. This section will simply go over the major aspects of the messages.
The ArduinoIn message encapsulates any messages sent from the RPi to the Arduino. It consists of two fields:
-
messageId: A randomly generated id which will allow the Arduino to send a confirmation back to the RPi to confirm the message has been received. Also allows the Arduino to ignore message it already received.. -
data: Aoneoffield containing the actual message to be sent across. It could be a ping, a command to set a servo to a certain value, etc.
The Arduino will sent an acknowledgement message for every message it receives. While this may not be strictly needed for all messages (say a ping), it simplifies the whole protocol.
The RPi sends a ping message every second to the Arduino.
If the Arduino doesn't receive a ping for 10 seconds, it will fall back to a safe configuration. When that happens, the pingFailsafeTriggered flag will be set in the ArduinoInfo message.
The RPi needs to first send a ServoInit message to the Arduino. This will initialize the servos and also contains the safe value to fallback to. ServoControl messages are used to control the initialized servo.
The RPi needs to first send a DigitalInit message to the Arduino. This will initialize the digital pin and also contains the safe value to fallback to. DigitalControl messages are used to control the initialized digital pins.
The RPi is able to reset the Arduino by sending a Reset message. This message is sent anytime the rocket-code starts, and allows to make sure the Arduino is in a clear state before proceeding. Once the reset is done, the Arduino will send a ResetEvent message to indicate it is now ready to be initialized.
A PingFailsafeReset can be set to reset the pingFailsafeTriggered flag in case it ever gets triggered.
The ArduinoOut message encapsulates any messages sent from the Arduino to the RPi. It only consist of one field:
-
data: Aoneoffield containing the actual message to be sent across.
The ACK message is sent for every message the Arduino receives. It only data it contains is the messageId of the received message.
The Error message is sent anytime the Arduino encounters a unexpected situation. It consists of the error message, along with the error level (WARNING, FATAL).
The ArduinoInfo message is sent every 5 seconds to the RPi. The message contains:
-
sessionId: This id should be randomly generated every time the Arduino starts (i.e. generated in thesetup()). -
pingFailsafeTriggered: Set if the ping failsafe has been triggered. Can be reset by sending aPingFailsafeResetcommand.
The intended use of this message is to allow the RPi to detect if the Arduino did an unexpected reset. If so, the RPi will be able to reinitialize the appropriate pins on the Arduino.
The ResetEvent message is sent right at the end of the setup() function of the Arduino. It contains the current sessionId. This allows the RPi to know that the Arduino is in a fresh state and able to be initialized.
Here is an example of the intended communication flow between the RPi and the Arduino to setup a servo and digital pin:
- rocket-code is started.
- A
Resetmessage is sent to the Arduino. - Once the reset is done, the Arduino sends a
ResetEventto the RPi. - When the RPi receives the
ResetEvent, it will send aServoInitmessage and aDigitalInitmessage. - Anytime the RPi needs to control the servo, send a
ServoControlmessage. - Anytime the RPi needs to control the pin, send a
DigitalControlmessage.
Here is now an example of an unexpected Arduino reset:
- All the steps of Servo and Pin Control are followed.
- The RPi saved the
sessionIdwhen it received theResetEventin step 1. - For some reason, the Arduino (but not the RPi) resets.
- Again, for some reason, the RPi doesn't receive the
ResetEventmessage. - When the Arduino sends the next
ArduinoInfomessage, the RPi detects that thesessionIddoesn't match. - RPi send a
Resetmessage. - When the RPi receives the
ResetEvent, it stores the newsessionId. - The
ServoInitandDigitalInitmessages are sent again.
- Getting started
- Environment Variables
- Compiling the SBG Library on Linux\Unix\WSL
- Developing on Windows with VSCode
- Set Environment Variable In Vscode With The Cmake Plugin
- Creating Unit Tests
- Cross compiling for the Raspberry Pi
- Info and Error Logging in the Rocket Code
- Send Folder via SSH
Configuration:
Raspberry Pi Setup:
- Add a new wifi network on the Raspberry Pi
- Connect to Raspberry Pi via SSH
- Important Notes About Setting Up Raspberry Pi
- Running Emulation of Raspberry Pi
Logging Format: