-
Notifications
You must be signed in to change notification settings - Fork 938
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
Floating Joint Support in CurrentStateMonitor #748
Floating Joint Support in CurrentStateMonitor #748
Conversation
Previously this was limited to the root link of the robot.
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.
Nice improvement.
What do you think about changing the joint_time_
map, such that it uses JointModel ptrs instead of joint names? Former ones should be more faster comparable.
if (tf_ && tf_connection_) | ||
{ | ||
tf_->removeTransformsChangedListener(*tf_connection_); | ||
tf_connection_ = nullptr; |
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.
Better use tf_connection_.reset()
?
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.
nitpick :P
tf::StampedTransform transf; | ||
bool ok = false; | ||
if (tf_->getLatestCommonTime(parent_frame, child_frame, tm, &err) == tf::NO_ERROR) | ||
if (!tf_->getLatestCommonTime(parent_frame, child_frame, tm, &err) == tf::NO_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.
Better write as != NO_ERROR
|
||
const std::vector<std::string>& joint_vars = joint->getVariableNames(); | ||
assert(joint_vars.size() > 0); | ||
if (joint_time_[joint_vars[0]] != tm) |
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 think this should use the joint name instead of joint's variable name(s). This also resolves ambiguity, which one to use - why did you choose joint_vars[0]
?
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.
Is it safe to read-access joint_time_
without locking? A writing thread may change the map meanwhile...
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.
of course you are right about locking.. fixed.
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 adjusted the map as you proposed. Nice idea 👍
The previous implementation was correct though.
joint_vars[0] represents the first dof of the joint including the joint name prefix, e.g. joint_name/trans_x
. I chose the first one as a representation for all dof of this joint.
It's much better to just store the time per joint instead and apparently it doesn't break anything else in MoveIt.
const std::vector<std::string>& vars = robot_model_->getRootJoint()->getVariableNames(); | ||
for (std::size_t j = 0; j < vars.size(); ++j) | ||
joint_time_[vars[j]] = tm; | ||
for (const std::string& var : joint_vars) |
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.
Here it suffices to use the joint name as well. If there are several floating joints, their joint vars will be identical and hence, the map will not be unique anymore...
if (joint_time_[joint_vars[0]] != tm) | ||
{ | ||
// only lock if we actually update something | ||
boost::mutex::scoped_lock _(state_update_lock_); |
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.
Instead of locking the state multiple times, I suggest to accumulate all TF updates in a map and apply them together.
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.
makes sense, implemented.
|
||
void planning_scene_monitor::CurrentStateMonitor::tfCallback() | ||
{ | ||
bool update = false; |
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 don't see a difference between update
and changes
.
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 implementation of the monitor always triggers the update signal at the end of the JointState callback, because some thread might be waiting for the joint states at the current time.
But it calls the update_callbacks_
only if something actually changed (see here).
With the tf callback we can't even be sure the time of any joint updated and we don't want to trigger the notify unless we actually updated something.
This is represented in bool update
.
bool changes
represents whether something actually changed.
Because Multi-DOF joints tend to be rather noisy, I decided to use a threshold instead of just comparing the values.
Afair the update callbacks in MoveIt mark the planning scene as changed which can trigger safety stops in currently executing plans, re-validation of current plans, and publishing of the monitored_planning_scene topic. So unnecessary update callbacks can cause a lot of overhead.
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.
Sorry, still don't get the difference: I guess you update something only if it has changed, don't you?
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.
Got it now from reading the code: If there is only a tiny change, you apply this change, but you don't want to call the callbacks.
remove unused private method
doesn't matter really...
Thanks @rhaschke . |
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.
Isn't it overkill to have four similar implementations of haveCompleState()
?
Thanks for the review.
I agree, but they are exposed API. |
@v4hn if i am to understand this correctly, the work flow is:
If so this, isn't working for us. I just wanted to make sure there is no other setup necessary besides floating joints and a tf publisher. We have a solution that updates the robot_description parameter and then forces moveit to update its internal model but we would like to use floating joints and TF. |
Although this is merged, it's not yet released. Are you using a MoveIt source build? |
That's the workflow, although you can actually have the floating joint anywhere, not just between base and world. If you still encounter problems, please file questions at answers.ros.org |
MoveIt supports Floating and Planar joints throughout the pipeline... almost throughout the pipeline.
Whenever someone actually tried to use it, they encountered problems with how to get the current state information into the MoveIt system. For over at least 4(!!!) years.
See among others here and here.
This works (rather hacked) for floating joints as root joint of the robot, but they are also important for online calibration procedures and mobile objects that are inherent to the setup and should be part of the urdf.
Turns out most things that are required to get this to work in general have been done a long time ago.
I simply implement a proposal by @hersh and add a tf callback that reads the state of all multi-dof joints from TF. This still does not allow to get velocities/effort readings into moveit, but it covers most everyday use-cases for multi-dof joints.
Also because it uses TF updates, it "just works" in practice and you don't have to explain the difference between transforms and joint states of floating joints to users. There simply isn't any.
This is mostly a generalization of the previous code. The only behavior that is supposed to change is that joint states for multi-dof joints are updated even if no
JointState
messages are received and are updated whenever a transform is published instead.Please note that the class already subscribes to TF anyway (it is passed a tf-listener) and that I only lock the state if an actual update happens, so that most TF callbacks don't block the RobotState.
This breaks ABI, so it will not be back-ported to indigo.
Lastly please note the proposed code intentionally supports compiling on indigo.