-
Notifications
You must be signed in to change notification settings - Fork 526
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
[Servo] Correct for drift by using previously commanded state instead of current state #2349
Conversation
… of current state
The How about something like this : 1 . Move
// Compute error from last commanded state
joint_position_error = last_commanded_positions_ - current_joint_positions
// Compute the next joint positions based on the joint position deltas
target_joint_positions = current_joint_positions + joint_position_delta + joint_position_error; or
// Compute error from last commanded state
joint_position_error = last_commanded_positions_ - current_joint_positions
// Compute the next joint positions based on the joint position deltas
target_joint_positions = current_joint_positions + joint_position_delta;
if(servo_params_.apply_anti_drift)
target_joint_positions += joint_position_error;
The |
I actually started doing it exactly that way you suggested... but then realized that we actually want to be computing the joint delta from the last commanded state instead of from the current state like in this line. This affects results when responding to twist or pose commands. That said, the suggestion to move away from optionals and stick the last commanded state in |
Codecov ReportPatch coverage:
Additional details and impacted files@@ Coverage Diff @@
## main #2349 +/- ##
==========================================
- Coverage 50.74% 50.71% -0.03%
==========================================
Files 386 386
Lines 31958 31968 +10
==========================================
- Hits 16215 16210 -5
- Misses 15743 15758 +15
☔ View full report in Codecov by Sentry. |
3554b86
to
567469c
Compare
567469c
to
2078dd3
Compare
@@ -126,10 +127,21 @@ class Servo | |||
|
|||
/** | |||
* \brief Smoothly halt at a commanded state when command goes stale. | |||
* @param The last commanded joint states. | |||
* @param halt_state_maybe A std::optional containing the last commanded joint states, if available. |
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.
* @param halt_state_maybe A std::optional containing the last commanded joint states, if available. |
Outdated comment
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 like the type of thing that should be a free function, eh? Transparent inputs and outputs
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 a public API of Servo
which is used by ServoNode
, not sure if making it a free function would make sense contextually even though it can easily be a free function.
@@ -200,6 +212,8 @@ class Servo | |||
std::shared_ptr<const servo::ParamListener> servo_param_listener_; | |||
planning_scene_monitor::PlanningSceneMonitorPtr planning_scene_monitor_; | |||
|
|||
std::optional<KinematicState> last_commanded_state_; |
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.
std::optional<KinematicState> last_commanded_state_; | |
KinematicState last_commanded_state_; |
I think this should not be optional, since last_commanded_state_
should technically always have a value.
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 ok with the optional. Maybe it wouldn't have a value if the program were just started or somebody just called resetLastCommandedState()
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.
Maybe it wouldn't have a value if the program were just started or somebody just called
resetLastCommandedState()
Would it make sense for resetLastCommandedState()
to reset it to the current state rather than a std::nullopt
.
We could then call this same function in the constructor to initialize the last_commanded_state_
.
I am not sure about computing the required joint delta by setting What I think should happen is: |
@@ -74,6 +74,7 @@ class Servo | |||
/** | |||
* \brief Computes the joint state required to follow the given command. | |||
* @param command The command to follow, std::variant type, can handle JointJog, Twist and Pose. | |||
* is used to calculate an error between the current state and the previous commanded state for anti-drift correction. |
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.
Continuing the formatting nitpick theme ;)
* is used to calculate an error between the current state and the previous commanded state for anti-drift correction. | |
* Is used to calculate an error between the current state and the previous commanded state for anti-drift correction. |
@@ -126,10 +127,21 @@ class Servo | |||
|
|||
/** | |||
* \brief Smoothly halt at a commanded state when command goes stale. | |||
* @param The last commanded joint states. | |||
* @param halt_state_maybe A std::optional containing the last commanded joint states, if available. |
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 like the type of thing that should be a free function, eh? Transparent inputs and outputs
@@ -126,10 +127,21 @@ class Servo | |||
|
|||
/** | |||
* \brief Smoothly halt at a commanded state when command goes stale. | |||
* @param The last commanded joint states. | |||
* @param halt_state_maybe A std::optional containing the last commanded joint states, if available. | |||
* @return The next state stepping towards the required halting state. |
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 does the bool
component of the returned value mean?
@@ -200,6 +212,8 @@ class Servo | |||
std::shared_ptr<const servo::ParamListener> servo_param_listener_; | |||
planning_scene_monitor::PlanningSceneMonitorPtr planning_scene_monitor_; | |||
|
|||
std::optional<KinematicState> last_commanded_state_; |
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 ok with the optional. Maybe it wouldn't have a value if the program were just started or somebody just called resetLastCommandedState()
auto initial_state = current_state; | ||
if (servo_params_.apply_anti_drift && last_commanded_state_.has_value()) | ||
{ | ||
robot_state->setJointGroupPositions(joint_model_group, last_commanded_state_.value().positions); |
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.
Since we know last_commanded_state_ has a value
robot_state->setJointGroupPositions(joint_model_group, last_commanded_state_.value().positions); | |
robot_state->setJointGroupPositions(joint_model_group, *last_commanded_state_.positions); |
@@ -423,7 +432,7 @@ KinematicState Servo::getNextJointState(const ServoInput& command) | |||
joint_position_delta *= collision_velocity_scale_; | |||
|
|||
// Compute the next joint positions based on the joint position deltas | |||
target_joint_positions = current_joint_positions + joint_position_delta; | |||
target_joint_positions = initial_joint_positions + joint_position_delta; |
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.
Maybe i missed it but i don't see that current_joint_positions
was modified at all between L410 and here. So why not use current_joint_positions
and don't bother creating initial_joint_positions
?
} | ||
auto& halt_state = last_commanded_state_.value(); | ||
const size_t num_joints = current_state.joint_names.size(); | ||
for (size_t i = 0; i < num_joints; i++) |
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.
nit
for (size_t i = 0; i < num_joints; i++) | |
for (size_t i = 0; i < num_joints; ++i) |
{ | ||
smoother_->reset(current_state.positions); | ||
smoother_->doSmoothing(halt_state.positions); | ||
return std::make_pair(stopped, current_state); |
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.
stopped
appears to be false here, I think it should be true
Guys, I am not sure this ended up helping at all, so I may close this PR. Still need to do some more testing. |
This PR implements the suggestion in #1857 (comment) to try correct drift for robots without great joint tracking control (like the MoveIt Studio Gazebo simulation).
This adds an
apply_anti_drift
parameter to MoveIt Servo, which when enabled will use the previously commanded joint state instead of the current state to compute joint deltas.