Our robot was controlled by approximately 1500 lines of C code, separated into modules according to function. The final system was composed of modules controlling platform abstraction, gameboard geometry, navigation, cannon control, and strategy. The code made fairly extensive use of threading, growing to eventually utilize five simultaneous execution threads, with asynchronous control of navigation, cannon control and targeting, and movement failure recovery.
The navigation control code ran in its own thread, and implemented a Finite State Machine (FSM) to manage transitions between drive phases. Our design defined four navigation states: ROTATE_ONLY, ROTATE, DRIVE, and DONE. A Proportional Integral Derivative (PID) controller was used to control rotational velocity, with forward velocity determined proportionally up to a user-defined maximum forward velocity. The use of a platform abstraction layer made it easy to drive the robot backwards: setting a flag in the platform module caused headings to be reported 180° off gyro values, and transposed motor setpoints to effect reverse motion.
The cannon's accuracy depended on acheiving a precise rotational speed, and having an accurate calibration relating rotational speed to distance. Speed was managed by another PID controller thread, with a larger integral term to prevent droop. The desire for fast convergence presented a trade-off: with a normal operating speed of approximately 1500 RPM, the encoder only produces 150 counts per second. If we run the control loop at 10 Hz, this only leaves us with 15 clicks expected each cycle, meaning our best-case accuracy is approximately ±7%. Actual performance was significantly worse, forcing a 3 Hz update and consequently slow convergence to achieve accuracy.
Most of the geometry functions were relatively simple, and most of the code in this module is spent embedding arrays of vertex coordinates. We performed no geometric collision avoidance, instead simply ensuring we never traversed more than one territory at a time. The most problematic part of this module, and indeed the entire design, was in the coordinates used to engage the levers in each territory. For best performance, we hoped to engage the lever while aligned with the ball deposit in the center, allowing us to fire in-place. Unfortunately, the precision required to achieve this was often too tight, and we often missed the lever due to innacuracies in both movement and VPS data. We attempted to improve our success rate by hard-coding offsets for each lever / target pair, totalling 12 points which needed to be empirically tuned. However, this too was insufficiently accurate, and we added an additional fallback behavior which mined balls while perpendicular to the wall, a pose somewhat less sensitive to error.
Source code is available on github.