The purpose of this lab is to get experience with PID control.
I created arrays to store the data points. I created a command to pull the data to python once I turned off the PID loop. I sent data point #, milliseconds, PWM, and TOF distance reading to python to aid in debugging and allow me to graph my data.
I created a few different sections of code to allow PID to run smoothly on my car.
1- Add a command that allows you to change your PID values on the spot. While testing PID, it was very annoying to have to wait a few minutes for the code to compile each time I wanted to change PID values. This made testing a lot easier.
2- Add a command to start and stop PID from python.
3- Inside the void loop (), place code that checks to see if PID is turned on. If so, run the PID loop.
4- The PID loop checks for new TOF readings, updates arrays, and calls the command to calculate a new PWM. If no TOF reading is available, this is where the linear interpolation occurs. The current distance is determined, send to PID calculations, then a PWM is returned. From this PWM, the correct move (either forward or backward, and how fast) command is called.
5- The PID Calculations function is where I send the current distance and target distance to get back a PWM from the PID loop.
6. On the python side, I call ble.send_command(CMD.PIDCONTROL, ".15|.4|1") to set my values, ble.send_command(CMD.PIDCONTROLON, "1") to start PID, and ble.send_command(CMD.PIDCONTROLON, "0") to turn off pid. I use a notification handler to process my array and call ble.send_command(CMD.TRANSFER, "") to get my data.
I started off by writing a P controller. I then tested a range of values for Kp. If Kp was too large, the car would overshoot and crash into the wall then drive back and forth. If Kp was too small, I found the car would get stuck and not be able to get to the target distance as the PWMs from the P loop would be too small for the car to move. I noticed many mechanical limitations of the system, such as the car behaving differently when the battery was low, my left wheels requiring a variable amount of more PWM to turn than the right wheels, and the minimum value of PWM needed to make the car move. I set my min PWM to 50 and the max to 150, I found that letting the car go up to 250 caused it to respond more unpredictably. Limiting the max PWM to 150 saw little decrease in the time needed to get to the wall and many times more predictability, so this parameter was worthwhile in improving overall performance. I found my optimal Kp value to be .15. Here, the car wouldn't crash into the wall and wouldn't get stuck with too little PWM input. Too much Kp (=.4) caused the car to bounce back and forth around the target distance.
I implemented a PWM lower-bound cut-off of 50 as can be seen here. Below 50, the car does not respond.
This shows the car's oscillations around the target as it overshoots and compensates.
In my returned arrays, there would be columns that read 0. Calculated from the missing rows, the sampling rate is ~100 ms. To fill this in, I created a linear interpolation that is triggered in the main PID loop if the distance sensor fails to have a reading ready. (Code listed in PID loop above). After implementing, the zero rows in my arrays disappeared. After interpolation, sampling rate is ~70 ms.
I was able to get my P loop working reliably. I wrote a PI and PID loop, and after much testing I have decided I need some more office hours to help debug my PI loop. Currently, the PWM is always maxed out and I suspect there is an error with my integrator error, causing the PWMs to always be maxed. My car keeps crashing into the wall when I run the code and infinite print statements have not come to the rescue. I would like to get PI & PID working ASAP so I can have more reliable positional controls on my car.
For me, the theme of the lab was debugging. I'd run basic example code to test my TOF and motor drivers when things started to go haywire to see if there was a hardware or software issue. A fresh battery also solves a lot of issues. Finally, print statements are your best friend to see where a loop is getting stuck. I'm a lot more confident with how all the sections of the .ble operate together as well now after setting up the code for this lab in so many areas of the master file.