ros-controls / ros_control

Generic and simple controls framework for ROS
http://wiki.ros.org/ros_control
BSD 3-Clause "New" or "Revised" License
476 stars 307 forks source link

Override Hardware Interface #129

Open davetcoleman opened 10 years ago

davetcoleman commented 10 years ago

I'd like to propose a new feature that I might implement for ros_control that allows controllers to go into an "override" mode where their setpoints are automatically updated to be based on the current state of the robot rather than some user setpoint. This override mode would be flipped on whenever the robot is disabled - an estop is hit, the robot is disabled, or in the case of Baxter, the cuff is squeezed such that Baxter goes into compliant mode. This override mode would then be switched off whenever the robot is re-enabled, etc.

This is useful so that when the robot is switched back on, it does not "jerk" or jump back to its previous set-point expectantly, but rather waits for a new command to move it.

Thinking about his just now, I could also probably integrate this into the controller_mode_inteface that I just added - instead of just having MODE_POSITION, MODE_ACCELERATION, etc - I could also add something like MODE_COMPLIANT.

Anyone have experience with this feature?

Thanks!

sachinchitta commented 10 years ago

We have done this before - e.g. a trajectory controller could check where it is and not take an input that expects it to be somewhere else right away or it could smoothly move to the expected starting position before executing what was commanded. The other way to do this is (at least for position/trajectory control) is to have an intermediate "proxy" which tracks some point between the desired and actual.

I am not sure about this being implemented as a separate feature though the way you have described it though - a good controller should be designed to never do something crazy when given bad input.

yamokosk commented 10 years ago

We've spent a lot of effort on this problem - managing anything that might cause a discrete jump in the command being sent down to the actuators... Gain changes, changing the point of resolution, control modes, etc.

The best approach we found was to instruct the controller to modify its reference command such that the output command being sent down to the actuators before the change equalled the command being sent down after the change. While this creates a ficticious reference point, it didn't much matter. Trajectory generation worked from the current state of the actuators and not the desired state. So once a user sent down a new desired point, it would smoothly transition to their reference.

On 11/08/2013 04:21 PM, Dave Coleman wrote:

I'd like to propose a new feature that I might implement for ros_control that allows controllers to go into an "override" mode where their setpoints are automatically updated to be based on the current state of the robot rather than some user setpoint. This override mode would be flipped on whenever the robot is disabled - an estop is hit, the robot is disabled, or in the case of Baxter, the cuff is squeezed such that Baxter goes into compliant mode. This override mode would then be switched off whenever the robot is re-enabled, etc.

This is useful so that when the robot is switched back on, it does not "jerk" or jump back to its previous set-point expectantly, but rather waits for a new command to move it.

Thinking about his just now, I could also probably integrate this into the controller_mode_inteface that I just added - instead of just having MODE_POSITION, MODE_ACCELERATION, etc - I could also add something like MODE_COMPLIANT.

Anyone have experience with this feature?

Thanks!

— Reply to this email directly or view it on GitHubhttps://github.com/ros-controls/ros_control/issues/129.

wmeeusse commented 10 years ago

What a robot should do when the E-stop is pressed, is very specific to the robot itself. Having the controller repeat the last setpoint is only one possible behavior that could apply to some robots, but it's definitely not the one mode that applies to all robots. So I don't think the 'override' mode is something we can have a default behavior for.

For mode switches, on e.g.Baxter when you grep the wrist, the robot could start up a whole different set of controllers, and shut down the current set of controllers.

If you care about a fast realtime reaction to an E-stop, you should build in that logic in the realtime loop, and simple stop the entire controller manager. Once the E-stop is released, you can re-start all controller in the controller manager. I believe the controller manager used to have some kind of a reset() function to trigger the starting() function of all controllers in the next cycle.

To allow controllers to start up cleanly, even after they have been disabled for a while, each controller has a starting() method. In this method you need to implement whatever is needed to start up cleanly from whatever the current robot state is.

adolfo-rt commented 10 years ago

Many things to comment about.

Override

For mode switches, on e.g.Baxter when you grep the wrist, the robot could start up a whole different set of controllers, and shut down the current set of controllers.

+1. The override mode could be achieved with a combination of a position-holding controller (which is constantly updating the current position) plus a call to switch_controllers, if you can afford the latency of two (persistent) service calls. So something like:

Avoiding discrete jumps

First of all, it's highly advisable to have joint limits enforcing (position, velocity, effort) in the robot hardware abstraction. Being controller-independent, you have a good last line of defense against aggressive commands and buggy controllers.

Then, I agree that controllers should implement sane starting behaviors. For example, the joint_trajectory_controller enters position hold mode, and allows you to specify a stop_trajectory_duration, so that if the controller is started with nonzero joint velocities, a gradual halt can be realized. Even if stop_trajectory_duration is set to zero, the lower-level joint limits enforcing should prevent discrete jumps. A trajectory segment implementation leveraging Reflexxes would be even better, but it has not yet been integrated.

E-stop

As @wmeeusse stated, E-stop behavior is very robot-specific; and yes, the controller_manager allows to reset all controllers in a given control cycle before the actual update. See the reset_controllers parameter here. You can for example reset controllers upon releasing the e-stop. A controller reset (stop+start) should result in sane conditions like canceling previous goals and holding position (among other strategies), so things like 'jerk or jump back to its previous set-point' should not happen.

A point worth mentioning is that pressing an e-stop should trigger a response that limit the actuator capabilities in some way (eg. limit max effort/current). Example scenarios: an encoder malfunction starts producing very-far-away readings, which are interpreted as requiring a strong control action; something or someone getting trapped between the robot and a wall.