Skip to content

Conversation

@ilge
Copy link
Contributor

@ilge ilge commented Jul 15, 2020

Introducing a cascaded PI mode that also refactors the existing one. The new mode overloads the use of gainprm and is activated by setting user="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_bias term.

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.

ilge and others added 8 commits July 7, 2020 14:10
…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.
@ilge ilge changed the title Ilge ruben/cascade Cascade PID Controller Implementation Jul 15, 2020
@ilge ilge requested a review from bayesian July 15, 2020 02:16
@ilge ilge marked this pull request as ready for review July 15, 2020 18:15
Copy link
Contributor

@bayesian bayesian left a 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.

# 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)
Copy link
Contributor

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.

Copy link
Contributor

@rubendsa rubendsa Jul 15, 2020

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.

Copy link
Contributor Author

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)

Copy link
Contributor

@bayesian bayesian Jul 15, 2020

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

Copy link
Contributor Author

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)
Copy link
Contributor

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.

Copy link
Contributor Author

@ilge ilge Jul 15, 2020

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)

Copy link
Contributor

@bayesian bayesian Jul 15, 2020

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.

Copy link
Contributor Author

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?

Copy link
Contributor

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.

Copy link
Contributor Author

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,
Copy link
Contributor

@bayesian bayesian Jul 15, 2020

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?

Copy link
Contributor

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.

Copy link
Contributor

@bayesian bayesian Jul 15, 2020

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

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 ?

Copy link
Contributor Author

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?

Copy link
Contributor

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.

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.

@arthurpetron
Copy link

understood what's going on now, we shall extend unit tests to compare pid and cascaded pid to check the expected benefits.

@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.

@ilge ilge mentioned this pull request Jul 15, 2020

cdef double integral_error_term = 0.0
if parameters.integral_time_const != 0:
integral_error_term = integral_error / parameters.integral_time_const
Copy link
Contributor

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.

@ilge ilge merged commit fe8373d into master Jul 16, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants