utra-robosoccer / soccer-embedded

Collection of embedded programs for an autonomous humanoid soccer robot
http://utrahumanoid.ca
32 stars 8 forks source link

PC Communication Protocol Structure #97

Open tygamvrelis opened 6 years ago

tygamvrelis commented 6 years ago

Describe the feature Since we have made good progress on Ethernet integration and will have the PC interface smoke test done relatively soon, now is a good time to start planning the nitty gritty details of the PC communication protocol. Let this issue be the place where we accumulate discussion for this topic.

Details include everything from finalizing which commands will be supported, to planning the payload structure byte-by-byte, to the response codes and everything in between. We can also discuss how the data will be buffered and processed in the event handler here.

To summarize the current state of affairs, the system will remain compatible with both UART and Ethernet links for this design iteration. This is good for compatibility (USB is everywhere—particularly in the current generation of our robot) and because the PCB which uses Ethernet is still in progress. This means we will still need to bake in error detection for UART and decide how that will be handled. We will probably use a CRC for that, so part of the process would be looking at communications standards and seeing which generator polynomial we should use.

We had previously discussed supporting 5 commands (copied verbatim from issue #36):

  1. GET_SENSOR_DATA: MCU returns cached data
  2. SET_MOTOR_POSITIONS: MCU enqueues set goal position commands for each motor and does not return anything to the PC
  3. SET_AND_GET: MCU enqueues motor commands and returns cached sensor data (combination of GET_SENSOR_DATA and SET_MOTOR_POSITIONS)
  4. GET_STATUS: Provide embedded systems status (maybe a string)
  5. GET_FORCED_SENSOR_DATA: MCU forces a read from all sensors then returns the fresh data when all sensor have reported in. This would primarily be a debugging command (perhaps it could even take an argument indicating which sensor to read from)

So in general, our payload may look like this:

This marks the end of the control data, and the start of the application data:

This marks the end of the application data and the start of the trailer (end of packet marker/error detection data):

Some interesting protocols I came across online are Modbus (abstracts the device to a table of registers) and Simple Sensor Interface Protocol (SSIP) which uses various queries to control the device. I recommend keeping these in the back of our minds as references.

Reason for request We all need to be on the same page as we implement PC interface features, and we want to strive to build an interface that will stand the test of time.

Timeline This starts being most relevant once the smoke test is done and will continue until this iteration of the design is done.

tygamvrelis commented 5 years ago

A new idea to reduce bandwidth:

The MCU receives goal angles from the PC and sends back current positions (between 0 and 300 degrees). Right now, these are sent as floats. However, I bet if we were to map these floats to uint16_t (mapped_value = (value / 300.0) * (2^16 - 1)), the (potential) loss in precision would not matter for control (resolution of 0.00456 degrees). It would really reduce our bandwidth requirements and thus reduce comm latency, so it is good to consider

rfairley commented 5 years ago

So in general, our payload may look like this:

Agree on including all the information mentioned in the packet here.

One other piece of information to consider adding is some unique identifier of the request sent by the PC to the MCU. The identifier is sent in the command/request packet, and returned somewhere in the response from the MCU alongside read data. The PC may do what it wishes with the identifier; for example it could compare the identifier in the request it sent to the identifier in the response it received. That way the PC would know from which command the data returned back originated.

The identifier may not be strictly unique, it could be just 1 byte. It would apply particularly in a situation like:

rfairley commented 5 years ago

Byte 3: length of message. Sanity check on number of bytes to process

Once we define error codes it might be feasible to have a message sent back to the PC in that situation e.g. "length not matching", "invalid checksum" for things like this. I imagine something like Rx thread writing the error (after being properly formatted as a response in our protocol) directly into a Tx queue, for the Tx thread to transmit.

rfairley commented 5 years ago

Another question for discussion:

If Rx is buffering packets, how should a situation where EventHandler is still busy processing other commands be handled? Drop commands, queue the commands to EventHandler, or drop and give a message back on the console saying "busy"?

rfairley commented 5 years ago

Noting here for reference: A protocol buffer like nanopb (https://github.com/nanopb/nanopb) can be used to generate standard accessor functions based on a schema, where we define the command and response formats (i.e. RobotState and RobotGoal). This would help unify the PC and MCU command parsing as the accessor functions are generated from one source of truth.

rfairley commented 5 years ago

I wonder if we should also have a command SET_STATE which modifies the running state of the MCU. E.g., a command SET_STATE and argument "stream" would switch the MCU to stream output instead of provide a 1-for-1 response to a command.