We are using the camera so that the robot goes into a loop and moves the drive wheels until the camera tells us that it is centered. this lets us aim the robot at the light. I can get it to work but I can’t get it to do it very fast. this is what i have so far right know.
The code makes the robot overshoot and oscillate back and forth. it takes ten or more seconds to get it to center and this is not very good.
I know there is a way to use a linear or even quadratic formula to increase the speed and to reduce the amount of overshoot instead of what i have i just don’t know how to go about programming it. Any help would be vary much appreciated.
you have discovered the world of PID control loops.
When your system overshoots that means the gain on your Proportional (the P part) is too high
you can fix this by lowering the gain, or adding the D part (differential) to the feedback algorithm.
If you think of it in terms of distance, velocity and acceleration (of your robot to point towards the target) then the P is like distance (how far off are we from where we want to be)
the D is like velocity (how fast are we moving towards the place we want to be)
and the I is something you use to make fine adjustments to the P (how far off we are times how long we have been ‘off’).
This is a whole semister in college - a very deep subject. To be honest the best approach is to keep turning your gain down until you stop overshooting, or you overshoot just a little and then center on one ‘bounce’.
Adding the I and D to the loop is more complex, and it will only make your response time slightly better than the slight-overshoot response time.
Indeed. If you search around, you can even find some sample code that people have posted (Kevin’s PID.C/H last year, and I posted a Proportional-only version of our teams gyro feedback code, amongst others).
something else that might help. When using feedback control (PID) loops, your system will respond better if it is way overpowered.
This means your bot needs to be able to turn very quickly. Another way of saying this is it needs to be able to turn very easily.
If you are using tank/skid steering and it take nearly full power to turn the robot, then the PID control system wont have any room to do its stuff (any headroom to make strong adjustments).
you might need to loosen up your steering by making the front wheels turn easier.
Another thing that causes overshoot is a slow response time. Make sure you code is as efficient as possible. Comment out all printF statements, and any other code that doesn’t need to be there.
Think of it this way, the control loop functions by telling the motors to do something, then looking to see what effect that had on the aim of the camera
if it takes a long time for the control loop to ‘look and see’ then the response will be too slow for a tight (fast) lock on target.
Today I tried implementing a PI loop. I’ve never done one before and was relying on non-proven code. I spent about three hours and called it quits. My new code that works great:
PAN_MOTOR = NEUTRAL + (pan_error / 5) + 11;
Adjust 5 and 11 to your needs.
Quote from my mentor: “Keep things as complex as necessary, and not a bit more.”
For future refrence, for an application like a turret one would typically start with just P, and D to damp, and if it’s too sluggish after damping (or you have steady state error) and I. In that order.
yes usually a simple proportional loop is pretty effective…
i don’t get the point of the +11 (recentering perhaps?)
But for us it wasn’t smooth/good enough (our robot is very rocky at turning…looking into omni wheels but thats another story)
if you go to kevin.org there is a nice PID code you can use…
Here’s a piece of code from the camera software (tracking.c) that implements a simple proportional controller:
-Kevin
static unsigned char pan_servo_position;
int temp_pan_servo;
int servo_step;
int pan_error;
// save the current pan servo PWM value into a local
// integer variable so that we can detect and correct
// underflow and overflow conditions before we update
// the pan servo PWM value with a new value
temp_pan_servo = (int)pan_servo_position;
// calculate how many image pixels we're away from the
// vertical center line.
pan_error = (int)T_Packet_Data.mx - (int)Tracking_Config_Data.Pan_Target_Pixel;
// Are we too far to the left or right of the vertical
// center line? If so, calculate how far we should step
// the pan servo to reduce the error.
if(pan_error > (int)Tracking_Config_Data.Pan_Allowable_Error)
{
// calculate how far we need to step the pan servo
servo_step = pan_error / (int)Tracking_Config_Data.Pan_Gain;
// Due to rounding error in the division calculation above,
// the step may be calculated as zero, which will make it
// impossible to converge on the target when x_error is
// smaller than X_GAIN. To get around this problem, we just
// test for the zero case and set the step size to one.
if(servo_step == 0)
{
servo_step = 1;
}
}
else if(pan_error < -1 * (int)Tracking_Config_Data.Pan_Allowable_Error)
{
// calculate how far we need to step the pan servo
servo_step = pan_error / (int)Tracking_Config_Data.Pan_Gain;
// Due to rounding error in the division calculation above,
// the step may be calculated as zero, which will make it
// impossible to converge on the target when x_error is
// smaller than X_GAIN. To get around this problem, we just
// test for the zero case and set the step size to one.
if(servo_step == 0)
{
servo_step = -1;
}
}
else
{
// if we've fallen through to here, it means that we're
// neither too far to the left or too far to the right
// of the vertical center line of the image and don't
// need to move the servo
servo_step = 0;
}
// add the step to the current servo position, taking into
// account the direction set by the user in tracking.h
temp_pan_servo += ((int)Tracking_Config_Data.Pan_Rotation_Sign * servo_step);
// check the pan servo PWM value for under/overflow
if(temp_pan_servo < (int)Tracking_Config_Data.Pan_Min_PWM)
{
temp_pan_servo = (int)Tracking_Config_Data.Pan_Min_PWM;
}
else if(temp_pan_servo > (int)Tracking_Config_Data.Pan_Max_PWM)
{
temp_pan_servo = (int)Tracking_Config_Data.Pan_Max_PWM;
}
pan_servo_position = (unsigned char)temp_pan_servo;
// update pan servo PWM value
Set_Pan_Servo_Position(pan_servo_position);
Not sure what you mean by “zero point error” but the reasoning for the +11 is that eventually the motor would get to a point (say 133) where it was attempting to move the turret but did not have enough power too. So the +11 turns that into 144 and it moves the turret fine.
After putting Victors on a meter, we’ve found that they center at about 132 instead of 127. Move your center-logic to 132 and your PD solution may work better. It sure helped ours. (Kevin Watson’s PID code from 2005 uses 132 as its center point, by the way.) I’m assuming that your NEUTRAL is currently set to 127. If it isn’t, you can just forget I said anything.
Been there. Done that. All four Victors used for the drive system had identical outputs after calibration, and their zero value was 132. I can’t speak for every Victor in the world, but our gyro autonomous code and our manual PID program both drive straight now.
Just my opinion. Professional driver on closed course. Do not try this at home. Read the manual. Your mileage may vary.
Wow. I’ve been going from the official IFI documentation which says the Victor deadband is 117-137. I never gave it a second thought. But that would perfectly explain the asymmetric PID response I wrestled with a week ago.
I will take a few minutes on Monday to characterize our Victors and see if they show the same center as yours. It’ll definitely make a difference if the true neutral really is 132.
Yes, I verified a year ago that the “neutral” of a factory-calibrated Victor is rather higher than the theoretical 127. I reverified it last week, finding that the yellow light is on from about 124 to 139. I just now changed a bit of code to put the neutral at 131, and it seemed to be running a wee bit smoother than it did before. (I then totally blew away the tuning parameters in the process of trying something new, so I wasn’t able to prove that it worked better.)
OK, my camera STOPPED WORKING!! Why? I checked my wires over and over again, I recharged the backup battery. The LEDS on the camera turn on when I turn on the robot and the camera moves to a set location, slightly up and right of the center. But it stays there! There is no light for the camera to track, and just yesterday it was working fine! I added nothing to the code, and this is kinda freaking me out. All I did today was mount the camera to the robot and I rewired some stuff. The sensor board for the camera is mounted upside down, power is on, everything worked yesterday. Any suggestions?
Add our voice of experience to testify that the “true neutral” we have seen on the Victors is at 132, rather than 127. We repeated this test with many Victors from the last three years and have found all of them to have a true neutral of 132 rather than 127. Similarly, the “deadband” range is actually 125 to 138 (an average of ~132) rather than 117-137 as described by IFI’s documentation.
For PID control, the difference in a “center point” of 132 vs. 127 makes a huge difference. We have confirmed this with many victors from the last few years. For software control, we are certain that you do NOT want to run the IFI “calibration” procedure, but instead should simply use a center point of 132, with a “deadband” of 6-7 units.
A past thread from Mike Betts which provides a graph of some detailed tests he ran to confirm this is in this post from 2005.
We don’t know whether the source of the error (132 vs 127) is due to the PWM signals being generated that way by the RC, or if the problem is in the Victor itself. We don’t have an oscilloscope to track down the source of the issue, but our empirical studies are quite conclusive that 132 is the appropriate center point for PID control loops.