space-concordia-robotics / robotics-prototype

Teleoperated Mars rover with autonomous capabilities intended for robotics competitions.
https://spaceconcordia.github.io/robotics.html
25 stars 18 forks source link

Implement communication between PDS and Jetson #542

Closed VimFreeman closed 2 years ago

VimFreeman commented 2 years ago

The new PDS code is ready and needs to be integrated into our system. The task will consist of either adapting the current Comms Node or creating a new one specifically for PDS (preferred). Keep in mind that the PDS is not on the same bus as the Teensies.

On the PDS side receiving and sending must be implemented. Since we are using UART, there will need to be bus control by the Jetson. This issue does not include creating and parsing the commands that the PDS will respond to. That will be done after. Do use the current internal comms library since it has all the logic already implemented.

Here is an explanation and example of a protocol:

Protocol Example We first distinguish the bus nodes as controller and client. There can be only one controller, but multiple client. Each client has an address (1-15), the controller has a fixed address 0. A conversation between the controller and the client is called a transaction. A transaction is constructed by multiple packets. A packet contains multiple bytes sent in series by one device. A packet is a stream of bytes sent by one device. Each packet: - Starts with two fixed bytes (sync word), 0x55, 0x77. - Follows by an address byte. The lower nibble is the address of the intended receiver, the higher nibble is the complement of the lower nibble. - Follows by a single byte indicating the length N of the effective payload. N can be zero, indicating a zero-length payload. - Follows by N bytes of effective payload. If N is zero, this field is not present. - Ends with 2 bytes of CRC16. The CRC is computed from the address byte to the last byte of the payload. Implementation doesn't matter as long as it is a CRC16. A transaction is a conversation between the controller and a single client. A transaction is always initiated by the controller and contains two packets. - The first packet is sent by the controller, addressing the client and optionally carries a payload. - The client, if present, responds with a packet, addressing the controller and optionally carries a payload. Packets sent by the controller is called the OUT packet. OUT packets always have a non-zero address. Packets sent by the client is called the IN packet. IN packets always address device 0 (the controller). Only the controller can initiate a transaction so the controller coordinates the bus, ensuring no two devices are speaking at the same time. The clients cannot speak until the controller addresses it, thus, the controller needs to poll individual clients for updates. The controller and clients should expect noise, truncated and corrupted packets on the bus. All invalid packets are dropped silently. The controller implements a timeout and if it failed to receive a response (the IN packet), it retries the transaction or throws an error. The client can safely drop all invalid packets and do nothing. The payload and interpretation of the payload is application-specific. The comms protocol is inspired by the USB protocol and ensures reliable data transmission Here's an example of a valid transaction: controller puts an OUT packet: `55 77 E1 03 0A 0B 0C 9A 40` 0xE1 is the address byte (addr = 1) 0x03 is the payload length (N = 3) [0x0A, 0x0B, 0x0C] is the payload 0x9A40 is the CRC16 of [0xE1, 0x03, 0x0A, 0x0B, 0x0C] client puts an IN packet: `55 77 F0 00 4F BA` 0xF0 is the address byte (addr = 0) 0x00 is the payload length (N = 0) There is no payload. 0x4FBA is the CRC16 of [0xF0, 0x00] The CRCs are obtained from some arbitrary online calculator, just for reference. We need to implement the controller on the Jetson. I would suggest maybe implementing it as a method that - takes the client address, as a number - takes the payload to be sent and its length, as an array of bytes The function then sends an OUT packet and waits for any IN packet. The function then - returns the payload received and its length, as an array of bytes - reports any error conditions (or throws exceptions) After all it's just a suggestion (I actually have no idea how this will be implemented in the Jetson)