Driver Regulation System (Part 1)
Development of the Driver Regulation System (DRS) for SPARK
Recap
So last I left off, I got the parts and now it’s time to start figuring out how I will be able to take control of the RC car with a computer. Now it’s time to actually start getting stuff put together!!
Purpose & Motivation
One of the requirements that I had was to make sure that I have a deadman switch to ensure that I can stop the car if there happens to be a runaway. Especially since this RC car will be driving itself. From my time at the Space Systems Lab, I learned how important it is to make sure safety is considered in the design process. As such, I wanted to focus on this problem first and make sure I had a solid solution.
One thing all RC cars have are radios and remotes, and I figured it would be a great idea to just leverage that for my solution. The idea is simple: while the trigger on the remote is held, the car can drive as it pleases based on commands from the computer. If the trigger is let go, then the car must stop and all commands from the computer must be ignored. This works really well because the radios also have a fixed range, so if the car ends up going too far from the operator, it will also just stop.
To make this possible, I needed a subsystem that sits in between the radio, traction, steering, and computer. This is where the Driver Regulation System (DRS) came into my design for SPARK.
Requirements
- the DRS shall interpret telemetry from the radio constantly
- the DRS shall terminate all control to the steering and traction if the trigger on the remote is not held
- the DRS shall permit computer control of steering and traction if the trigger on the remote is held
- the DRS shall facilitate control commands and telemetry between the computer and hardware
- the DRS shall contain a watchdog that terminates control if the software hasn’t sent a command in [TBD] milliseconds
- the DRS shall provide telemetry to inform the computer if the watchdog wasn’t pet or if the trigger on the remote was released
- the DRS shall be run off actuator power
- the DRS shall provide a serial interface at a 115200 baud rate
- the DRS shall re-permit computer control of steering and traction if the trigger on the remote is held
Approach
There are many ways to build a system like this. I simply went with the easiest and cheapest approach. The architecture that was devised is shown in figure 1.
So that’s a cool picture. What does it actually mean? Well let’s start with the ESP-32, which is effectively the DRS itself. The ESP-32 is a cheap microprocessor that contains two processing cores. This means that the microprocessor can do two tasks at the same time in true real time. To leverage this, I used FreeRTOS to create 2 threads/tasks that I then pinned to the cores by setting the thread affinity.
On one of these cores, I have a thread (sequence of executions) that is purely listening to the Pulse Width Modulation (PWM) signals coming from the radio and monitoring the trigger on the remote. This thread will take the value from the radio and set a boolean flag (deadman_triggered) depending on the state of the remote’s trigger.
On the other core, I have another thread that is listening to the serial bus to collect commands from a processor. Once a command is received, it checks the status of the deadman_triggered boolean flag (managed by the other thread) to see if it can forward that command to the hardware. If the flag is false, then the command is tossed and ignored. If the flag is true, then the command is forwarded to the hardware and telemetry is produced to return to the processor.
That is about it. With these two threads working together, I am able to cut comms safely when I want the car to stop, and I am able to send data to the hardware when I want the car to go.
Implementation Pseudo Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// other global variables
bool command_passthrough_enable;
void setup() {
// setup serial connection
// setup pwm pins for input and output
// setup status leds
// set global vars to default values
// pin deadman_monitor to core 0
// start deadman_monitor task
// pin control_monitor to core 1
// start control_monitor task
}
void deadman_monitor() {
while (true) {
// read radio
if (remote trigger held down == true) {
command_passthrough_enable = true;
} else {
command_passthrough_enable = false;
}
sleep(some time); // sleep is technically optional here
}
}
void control_monitor() {
while (true) {
if (serial input provided) {
// read serial
if (command_passthrough_enable) {
// process command
// print telemetry
} else {
// do nothing
}
}
}
}
void loop() {
return;
}
You’re probably wondering where the logic for the watchdog is. In my code I put it under the control_monitor section, but I’m still on the fence about whether I will really use it. Once I reach full system integration with software, I will make that decision, but right now it’s a bunch of commented-out logic in the control monitor.
If you would like the actual source, feel free to reach out to me at rvishnoi439@gmail.com and I will happily email the source
Next Steps
Now that I have an architecture for my subsystem, I can finally start engineering the system!!

