CanHaptics Lab 4: Controlled actuation using PID
Task: create an actuated interaction using Haply and a PID controller
Goals
The main goals of this lab were to get comfortable with tuning PID controllers and learn how to implement a guided interaction using Haply.
Materials
PID example provided by the course instructors. My modified version of that code can be found here.
Tools
Haply device, Processing Development Environment.
Tuning the PID
Tuning a proportional-integral-derivative controller. If, like me, this is only your second time tuning a PID controller, you might want to have a buddy around to discuss your experiences while fiddling with the parameters. Thanks Hannah E. for keeping me company throughout this lab!
Proportional component
Prompt: Run the code and try out the P controller. How does it feel? What happens when you change the target position? What does changing the P parameter do? Do you notice any problems?
In the context of Haply, if the proportional component component is too small, the end effector might not reach the target point. Conversely, if the magnitude of P is too big, in a purely proportional system, the Haply starts oscillating around the set point. To reach a stable PID, I started adding P until the end effector: (a) reaches the target consistently, and (b) starts oscillating or overshooting around the set point.
Derivative component
Prompt: Add the D component to your controller. Tip: You can use a high smoothing (close to 1) to better see the effect of the derivative filter when manually moving the handle, but this adds delay and should be reduced for improving the stability. How does this change the behavior of the Haply? Are there any problems?
First, I tried increasing D alone, without adding proportional gain, and moving the handle manually. As the derivative component grows, the Haply starts feeling “bumpier”.
Then, for the purpose of achieving a stable response, I added D to damp the oscillatory behavior caused by adding proportional gain. Once I had a proportional gain that met the criteria discussed in the previous section, I started adding D until the end effector stopped oscillating or overshooting around the set point. Finding a good P-D dyad wasn’t always trivial, as sometimes the Haply would lose track of its position. In this case, holding the device with a light grip helped achieving a stable combination of P and D, as it introduces some degree of dampening to the system and slows the movement.
Integral component
Prompt: Add the I component to your controller. How does this change the behavior of the Haply? Can you create a stable system that reaches the target?
Adding the integral component slows down the action of reaching a new target, and often creates a gap between the end effector and the desired target. I also found that adding I most times causes the system to be more unstable and rarely was able to add the integral component without destabilizing the system.
Path tracking
Prompt: Implement path tracking, specifically, replace the random position by a position following a track over time (e.g., a circle or square). What happens when you hold the handle ? How is it affected by the PID parameters?
For path tracking, I implemented the trajectory represented by the intersection of these three line equations:
y = 1.67x + 0.3
y = –x + 0.3
y = 0.33x – 0.1
The device should start at the point (–0.3, –0.2), following the filled line up to (0, 0.3). Then, should follow the dashed line towards (0.3, 0). Finally, the device loops back to the start point following the dotted line.
if (index < 3 && path) {
current_time = millis();
if(last_time == 0){
last_time = current_time;
}
if ((current_time - last_time) < movement_duration) {
if(index == 0 && xr <= 0){
xr = xr + 0.0001;
yr = 1.667*xr + 0.3;
} else if(index == 1 && xr <= 0.3) {
xr = xr + 0.0001;
yr = -1*xr + 0.3;
} else if(index == 2 && xr >= -0.3) {
xr = xr - 0.00015;
yr = 0.333*xr - 0.1;
}
} else {
index++;
last_time = current_time;
}
} else if (index == 3) {
index = 0;
xr = -0.3;
yr = -0.2;
}
I tried both leaving Haply undisturbed and holding the handle while in path tracking mode. I found that holding the handle adds an extra dampening to the system, introducing some extra lag between the end effector and the target.
Sampling rate
Prompt: Play with the controller update rates, and with introducing delays. Hint: use the “looptime” parameter. How does this change the system? What happens if you sample faster or slower? What happens if it’s random (this would require some coding)?
Since my implementation of path tracking consisted of modifying the (x,y) coordinates of the target point over time, one direct effect of changing the looptime parameter is the change in speed of how often the target point changes. The implementation was parametrized to have a closed triangle shape for the default looptime. If the loop is longer, the rate of position change (for the set point) is lower, which also causes the triangle to not be completely formed. When the loop is short, I started having stability issues, as the points change faster than the Haply can keep track of. Last, changing the looptime randomly sometimes cause the system to be unstable.
Reflections
These are a few things I noticed while playing around with the PID controller:
- To get any feedback from Haply after adding proportional gain, I had to move the end effector away from the initial, neutral position. Otherwise, nothing would happen and the device would stay “locked” in place.
- Throughout the process, the controller loses track of the encoder reading very easily. I often had to reset my device because the visual feedback did not match what I was seeing in the physical Haply. Also, the end effector knob flies away with strong movements, so it might be a good idea to keep it off while calibrating the controller.
- Tuned PID values are not consistent between two different Haplys, or a lot of the times, not even between two different runs of the same code. The system can be quite unstable, and the haptic feedback can be jarring if you are still a novice with the device.