-
Notifications
You must be signed in to change notification settings - Fork 825
Cascade PID Controller Implementation #554
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…vs ID custom controllers based on the actuator_user field that is defined per actuator. `user="1"` would trigger activating an ID controller where the gainprm are interpreted as Kp, Td, ema_smoothing_term, respectively.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
understood what's going on now, we shall extend unit tests to compare pid and cascaded pid to check the expected benefits.
mujoco_py/mjpid.pyx
Outdated
| # Save errors | ||
| d.userdata[id * NUM_USER_DATA_PER_ACT + IDX_CAS_LAST_ERROR] = pos_output.errors.error | ||
| d.userdata[id * NUM_USER_DATA_PER_ACT + IDX_CAS_INTEGRAL_ERROR] = pos_output.errors.integral_error | ||
| des_vel = Kp_cas * (pos_output.errors.error + pos_output.errors.integral_error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why des_vel only has PI no D terms? also I don't fully understand the physical meaning of des_vel now (it should be the force with "Newton" unit in PID), but on in the cascaed PID, it seems to mean velocity now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this setup of cascaded PID, we're only using the PI components. There are effectively two PI controllers. First controller tracks position and outputs a velocity. Second controller tracks the velocity reference from the first controller and outputs a torque.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also had the question: theoretically, if we needed/wanted, could these be PIDs, or is there a reason that's a bad idea? (also gainprm limitation is there, so we'd move all params to actuator_user, which is a bigger refactor)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also I think that des_vel is just the same as pos_output.otput
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point. I've updated this line as such
| EMA smoothing constant is set to 0.97, and velocity limit is 3 rad/s | ||
| """ | ||
| random.seed(30) | ||
| xml = MODEL_XML.format(actuator=CASCADED_PID_ACTUATOR, nuser_actuator=1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shall we add some tests to compare cascaded pid with regular pid to check the expected benefits?? e.g. the max velocity should be smaller or something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added one for the cascaded PID (that checks force limit, however, qvel limit applies as a constraint between the two controllers, so I can't check for that directly). I can also extend the existing PID test (now that I set seed, we could ideally test for trajectories, but didn't want to do that here since it's quite a lot of data)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is the max_torque for pid only controller here? can we just run both PID and cascaded PID in the test, and compare some metrics? max_torque check here is applied through "force range" which is shared with regular PID controller. it would be great to see in the unit tests the advantages of cascaded PID controls here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
adding @rubendsa: can we set a PID with only PI terms set, and compared against cascaded with extra velocity constraints, is that a unit test we could add?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ilge Yeah, we can run that test. In this context with both loops running at the same frequency, the biggest gain we have with this cascaded approach is having the ability to apply velocity limits independent of torque constraints.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I couldn't find a good way to test PIDs that have similar Kp/Ti terms for the position control as per for the cascade case, the position controller part is acting to trace a velocity setpoint ant it'll inherently have a very different transfer function compared to the single PID. let me know if the individual tests don't look sufficient, though.
| integral_error_term = integral_error / integral_time_const | ||
| vel_output = _pid(parameters=PIDParameters( | ||
| dt_seconds=dt_in_sec, | ||
| setpoint=smoothed_vel_setpoint, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this seems a very complex controller: PI output from the first PID, then exp moving avg, then second PID. I am a bit concern about ema about the pid output, would it introduce the "undesired" behavior of the controller?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The biggest issue with the EMA is the delay it introduces on the original position reference signal tracking, other than that, the performance quite good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is perfectly fine and beneficial for have EMA on controller inputs (like pos, vels, etc), but here we are applying EMA to the first PID output. is it common in cascaded PID controller?
|
|
||
| cdef double integral_error_term = 0.0 | ||
| if parameters.integral_time_const != 0: | ||
| integral_error_term = integral_error / parameters.integral_time_const |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure you don't want to clamp after integral_error / parameters.integral_time_const ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not changing the implementation in this PR. Maybe @bayesian has context?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
integral_time_const is a constant, clamp before or after multiplied by a constant is equivalent, it only affects the clamp range. It is likely this logic is from our c++ controller.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Except that one is easier to think about than the other.
@bayesian The benefit is that you are able to control the velocity of the robot. This is not possible without a cascaded controller. The test should be "does it exist or not." I'm not sure what else you want to test. |
|
|
||
| cdef double integral_error_term = 0.0 | ||
| if parameters.integral_time_const != 0: | ||
| integral_error_term = integral_error / parameters.integral_time_const |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
integral_time_const is a constant, clamp before or after multiplied by a constant is equivalent, it only affects the clamp range. It is likely this logic is from our c++ controller.
Introducing a cascaded PI mode that also refactors the existing one. The new mode overloads the use of
gainprmand is activated by settinguser="1"in the general type actuator definition.Currently, the cascaded controller supports PI mode for both the position and the velocity controllers and therefore requires Kp, Ti and max_clamp_integral parameters to be specified for both. Additionally, an exponential moving average smoothing is applied to the velocity component for added stability, and the controller is gravity compensated via the
qfrc_biasterm.These are provided as part of gainprm in the following order:
gainprm="Kp_pos Ti_pos max_clamp_pos Kp_vel Ti_vel max_clamp_vel smooth_factor max_vel", where smooth_factor denotes the EMA smoothing factor and max_vel is a velocity constraint applied to the velocity setpoint.