-
Notifications
You must be signed in to change notification settings - Fork 54
Iterative Chassis PID - Give the chassis some error and it will do 1 step of PID #303
Comments
I"d like to help on this; do you have strong opinions on implementation details? |
I was hoping @theol0403 could comment but I don"t have any opinions on implementation details at this time. I haven"t touched this code in a while. Why don"t you start by designing the API first? |
Similar to @theol0403 "s original but in looking into the details a bit, what I"d suggest is:
Something similar for turnAngleIterative, which is a simpler case. |
Hey, sorry for the late reply. Throwback to my first github issue ever 😅 I"m not actually sure how this can be cleanly implemented. Since the chassis control runs in a asynchronous task, there would essentially need a statemachine to keep track of the user command, which might get messy, especially when considering concurrency issues and the iterative nature of the command. In reality, the implementation of that could almost be identical to just repeatedly calling I also don"t really like that API, I think it should be something as simple as Here is one proposed functionality: void moveDistanceAsync(iangle) {
// reset PID
// set mode to distance
// set target distance
}
void turnAngleAsync(iangle) {
// reset PID
// set mode to angle
// set target angle
}
void moveDistanceIterative(ierror) {
// if previous mode != distanceIterative
// then reset PID
// set mode to distanceIterative
// set pid target to 0
// set distance error
}
void turnAngleIterative(ierror) {
// if previous mode != angleIterative
// then reset PID
// set mode to angleIterative
// set pid target to 0
// set angle error
}
// main task
case distance:
distancePid->step(currentDistance);
anglePid->step(currentAngle);
case angle:
turnPid->step(currentAngle);
case distanceIterative:
distancePid->step(-distanceError); // target is at 0
anglePid->step(currentAngle);
case angleIterative:
turnPid->step(-angleError);
here is another proposal, which I favor for reliability reasons: void moveDistanceIterative(ierror) {
// if previous mode != distanceIterative
// then reset PID
// set mode to distanceIterative
// pause internal task
// do all the PID calculations right here, then apply to motors
}
void turnAngleIterative(ierror) {
// if previous mode != angleIterative
// then reset PID
// set mode to angleIterative
// pause internal task
// do all the PID calculations right here, then apply to motors
} Hopefully that makes sense. Either way example usage would be: do {
chassis->turnAngleIterative(targetAngle - odom.theta);
pros::delay(20);
} while(!chassis->isSettled()); |
I can see where you"re going with that thought. I understand allowing the user to specify only the error is simpler, but I"m not sure how it would work if the user is not allowed to set the target in this iterative mode. Nor, too, how the user would run consecutive iterative movements where they would want to reset the PIDs. Taking a step back, I think a goal here that we both recognize is a desire for users to use something other than the encoders (either motor or tracking wheels) to control the movement of the robot. Within
as:
(terrible name, admittedly), and then the call to:
as:
|
Currently, there are two pairs of movement functions.
moveDistance
/moveDistanceAsync
andturnAngle
/turnAngleAsync
.These each set the target of the chassis relative to current position then execute the motion.
However, I want to be able to define my own error calculation for the chassis to do PID on.
What I mean is to be able to use the chassis in a way similar to an
IterativePIDController
where you can specify the target and then step. However, the implementation might be different for a chassis.This will be useful for
Lets say for example we have Odometry. We are able to read the absolute chassis angle at any time.
Using the above functions, if we wanted to turn to face 0 degrees, we would have to do something along the lines of
robotChassis.turnAngle(0_deg - chassisOdom.theta);
If chassis theta is -90 degrees, this will then set the target of the chassis to +90 degrees.
The robot will then turn to face 0 degrees.
However, if the robot slips, or something goes wrong with the turn, the target will become messed up and the turn will be inaccurate. To attempt to hone in to the 0 degrees, you would have to run the function again and hope that it will reach the target.
However, all this time the chassisTheta was kept accurate.
This is the request - to be able to specify the value to calculate the error from.
This is then what you could do to hone in to 0 degrees.
This way it does PID on the calculation we used to determine the wanted angle instead of calculating once and then doing PID on that static target.
Another way to do this would be
Then it will only do PID when the button is pressed.
This might be useful for vision alignment or anything where you want the chassis to use PID to react to external values.
You would also be able to specify a dynamic variable as the target and move the target around.
So as a recap, instead of calculating and executing the whole movement as one action, it instead does one step of PID towards the target and then re-calculates the target.
I think the best way of doing this is by manually calculating the error, but there may be other ways such as setting the target with an input.
The text was updated successfully, but these errors were encountered: