Lab 7

Estimate Drag and Momentum

Getting Velocity

I chose my step response to be 170 as that was a reasonable speed for what I had done in prior labs and was greater than 50% of the maximum u which was 255 due to PWM limits. I still used 255 as my PWM when u = 1 since in a prior lab I fixed the straightness of my car and managed to remove my calibration factor. After that I ran the vehicle and collected data. However, due to noise issues in the velocity data which many other students had as well, I then snipped the data and plotted a line of best fit to my ToF data. Using this, I then took the derivative of this line to get the velocity. Plots of the noisy data, the true ToF measurements, the line of best fit, its velocity, as well as the motor input are seen below. Broken Down: Plot 1 is the ToF measurement raw and the computed velocity with raw data. As one can see, there is a lot of high noise in the velocity. ToF measurements: As one can see I then made my measurement take the line of best fit which the comparison can be seen in the second plot. Since the line of best fit is just a 2nd degree polynomial, I took its derivative to get the velocity. In the last plot, one can see the motor input is consistently 170 until around when it is near its target.
.
Given these findings, I saved the data then found the steady state speed to be 1.42 m/s. 90% of that is 1.278 and therefore, I used the line representing the velocity to find my rise time to be roughly 1,274 ms by subtracting the timestamp that was associated with 1.278 and the initial timestamp in the data.

Computing A and B

To get A and B I used the following equations: I then computed d as .667 / 1.42 which came out to be .469 kg/s. I got .667 due to my motor input being 170/255 and 1.42 was my steady state time.
Then to compute m, I computed -d * 1.274 / ln(.1) which was .25949 kg.
Given all of this my matrices were:

Initialize KF

After this I put these matrices as np arrays in python and then compute Ad, Bd, C, and mu as follows:
My ToF sensors are flipped so doing C as [-1 0] flipped my KF. As a result, I did [1 0]. To initialize my state vector, I used the measurements from my saved data and similarly had to keep the initial mu as positive. Next, I needed to specify my covariance matrices depending on the confidence I had for my process versus sensor. I ended up needing to adjust these values quite a bit from my initial guesses where I computed them using sqrt(100/sampling time) for sigma1, sigma2 and sqrt(100/sensor variance). I got sampling time by averaging the time between each sensor measurement, and I got sensor variance by computing the variation in measurements when my robot was stationary. These computations gave me sigma1, sigma2, sigma3 = 85, 85, 19. After implementing the simulation, I found this would trust the sensor measurements too much and therefore, overfit to the data. To get it to work better, I drastically increased the sigma_z value compared to the process getting it to be sigma1, sigma2, sigma3 = 50, 50, 200. This setup of values also ended up working on the hardware.

Implement and test your KF in Jupyter

After that to test my parameters and tune them, I implemented the KF function in Jupyter lab and then ran through my data using the KF. I scaled my input to .667. The function and process can be seen below:
As mentioned earlier, my first set of sigma parameters were overfitting to the ToF measurements. As a result, I decided to increase my trust in my process a lot more. I also flipped the signs on my initial mu and C matrix, as they were the opposite of the example code since I get my measurements differently. A and B as computed earlier along with their derivative equivalents (where Delta_T was computed using the time between measurements) worked perfectly on their first try, as well as my initial sigma of [[400, 0],[0 400]]. I share three charts below which demonstrate as described.
Below, I include a list of the parameters that impact performance:

Implement the Kalman Filter on the Robot

C Code

First, I initialized the properly library and stated using namespace BLA and then declared the global variables as seen below:
After these global definitions, I implemented kf_func() which the final form can be seen below. Some bugs I came across while debugging kf_func was that since all my computations were in seconds for individual values, I had to take Delta_T and divide it by 1000 since it was in ms or else it would cause an integer overflow error and return nan values. Other bugs also included originally using sigma_mu as kf_mu in situations where there weren't measured values. However, in the end this was my kf_func.
After using this as my kf_func, I then needed to call this function. The first case was just standard, use a ToF measurement when you have a ToF measurement. The code snippet can be seen below. But basically, I just get the expected control with my PID_control function, I use that as my u by taking it as a percentage of 255 and for my y I use my actual ToF measurement.
The other case I need to consider is if there is no new ToF value. For this case I use the last ToF measurement as my y, the time from that ToF measurement as my Delta_T, and last_control output as my u. I run it through my kalman filter to get my measurement which I use instead of my ToF measurement for the PID_control. A code snippet is seen below.
After that, I ran my code on the robot and videod it and sent the data of the ToF sensors and the Kalman Filter over. The video is seen below:
There are two charts I share below. Measurements are in (mm) and time is (ms).
.