Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.Sign up
Synchronize controls with the CAN bus #547
This enhancement works way better than I hoped, and actually reduces the CPU utilization of boardd. The primary goal was to ensure that steering sensor data from the vehicle was neither skipped OR reused by controls due to mismatches in sample timing.
The current logic uses a static 5 ms sleep time between the end of one CAN sample and the start of the next CAN sample in boardd. This results in very irregular sample resolution due to varying traffic loads and USB thread contention. For cars with heavy CAN traffic, the sample period of a particular 100Hz CAN frame can be deteriorated to an effective alternating 50Hz / 200Hz rate. This irregularity causes a direct deterioration of controls.
The proposed logic has 2 synchronization modes. Both modes require the cp.update() method to wait for a packet from boardd. The difference is in the way boardd determines when to send the packet. If the new "syncID" value is set in interface for a vehicle, then boardd will synchronize itself on the receipt of that CAN frame. This ensures that controls will never outpace the CAN bus (even if it runs below 100Hz).
The second mode is the default mode, when there isn't a syncID defined in interface. In this mode, boardd will precisely synchronize on time. It will drain the Panda 3 times per 0.01 seconds, but it will only send the data 1 time per 0.01 seconds. To ensure precision, the first 2 calls to the Panda will occur at a "soft" 4.5 ms, with the sleep occurring outside of the USB lock. However, the 3rd call to the Panda will occur inside the USB lock, so that USB contention doesn't disrupt timing.
In order to prevent irregularity in control processing after the packet is received from boardd, the existing rate keeper is used to stage the data that will be sent back to the vehicle. However, there can be only 1 absolute rate keeper, so an optional offset was added to the rk.keep_time() method. This allows for occasional disruptions in the system without overrunning the secondary rate keeper.
FYI... I just fixed some [embarrassing] mistakes I made while cleaning up the code for this PR. I apparently cleaned too deep ,and broke a couple things. I just finished retesting both sync modes, and have a cabana drive to share from each.