-
Notifications
You must be signed in to change notification settings - Fork 30
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
Add RosPositionCommandExecutor #173
Conversation
…rsonalrobotics/aikido into SimBarrettHandCommandExecutor
Duplicate changes in BarrettHandKinematicSimulationPositionCommandExecutor.
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.
Major requests:
- Eliminate the "duration" template arguments on the constructor (see my comment for a nuance here).
- Inherit from the
PositionCommandExecutor
interface added in Adding an abstract BarrettHandPositionCommandExecutor class #166. - Eliminate the
execute()
overload that accepts aros::Time
unless I am wrong aboutSetPositionGoal
lacking aHeader
. - Make
jointNames
a constructor argument, instead of an argument toexecute()
. - Move
waitForServer
to a helper function (this probably should have been done when we first implemented, to be honest).
I also left a few nitpick comments.
const DurationB& connectionPollingPeriod = std::chrono::milliseconds{20} | ||
); | ||
|
||
~RosBarrettHandPositionCommandExecutor(); |
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.
Either make this virtual
or mark the class as final
. In this case, I'd prefer the former.
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.
Made virtual
const std::string& serverName, | ||
const DurationA& connectionTimeout = std::chrono::milliseconds{1000}, | ||
const DurationB& connectionPollingPeriod = std::chrono::milliseconds{20} | ||
); |
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: I don't think there is any value in templateing DurationA
and DurationB
here, since we immediately store these values in std::chrono::milliseconds
member variables. To make this work, we would have to template the entire class on these two types - which seems like it is distinctly not worth it.
I believe @jslee02, @gilwoolee, and I discussed this in a previous PR. Tagging them to see if they have anything to 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.
Removed template params and changed to std::chrono::milliseconds
/// Sends positions to ROS server for execution. | ||
/// \param[in] goalPositions Vector of 3 finger positions and 1 spread position | ||
/// \param[in] jointNames Vector of 4 joint names for fingers | ||
std::future<void> execute(Eigen::VectorXd& goalPositions,std::vector<std::string>& jointNames); |
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.
- Take
goalPositions
byconst &
. - Make
jointNames
a constructor argument, instead of making it an argument here. This is necessary to comply with thePositionCommandExecutor
interface that @gilwoolee added in Adding an abstract BarrettHandPositionCommandExecutor class #166.
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.
Done both
namespace ros { | ||
|
||
/// This class sends commands for the hand position to the ROS server | ||
class RosBarrettHandPositionCommandExecutor |
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 should inherit from
PositionCommandExecutor
that is added in Adding an abstract BarrettHandPositionCommandExecutor class #166. - This class is not specific to the BarrettHand, so it needs to be renamed. I suggest
RosPositionCommandExecutor
to mimicRosTrajectoryExecutor
.
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.
Changed name and is now inheriting
std::future<void> execute( | ||
Eigen::VectorXd& goalPositions, | ||
std::vector<std::string>& jointNames, | ||
const ::ros::Time& startTime); |
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 pr_control_msgs/SetPosition
action doesn't have a time parameter, so this argument is not necessary. We should remove this function and roll everything into the execute(const Eigen::VectorXd&)
overload.
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.
Removed - only a single execute
method now
, mConnectionTimeout{ | ||
std::chrono::duration_cast<milliseconds>(connectionTimeout)} | ||
, mConnectionPollingPeriod{ | ||
std::chrono::duration_cast<milliseconds>(connectionPollingPeriod)} |
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.
See my comment above about this cast. I'd prefer to eliminate the template parameters entirely and force the user to perform this conversion, if necessary.
If we do decide to keep the template parameters, then this implementation needs to be moved into a header file. By convention, it would go into a file named src/control/ros/detail/RosBarrettHandPositionCommandExecutor-impl.cpp
.
std::vector<std::string>& jointNames, | ||
const ::ros::Time& startTime) | ||
{ | ||
if (goalPositions.size() != 4) |
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.
Replace the hard-coded value 4
with jointNames.size()
.
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.
Actually delegated the check to the toJointState
message in conversions
// Convert goal positions and joint names to jointstate | ||
goal.command = toJointState(goalPositions,jointNames); | ||
|
||
goal.command.header.stamp = startTime; |
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 think SetPositionGoal
has a header
. Are you sure this compiles?
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.
Removed as we no longer need startTime
. But in general the command
which is JointState
does have a header.
|
||
//============================================================================= | ||
// TODO : This is directly reused from RosTrajectoryExecutor.cpp | ||
// Anyway to reuse this? (assuming we want this 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.
I agree! Code duplication sucks. 😁
It should be straightforward to move this to a helper function:
template <class ActionSpec, class TimeoutDuration, class PeriodDuration>
bool waitForActionServer(
actionlib::ActionClient<ActionSpec>& actionClient,
ros::CallbackQueue* callbackQueue,
TimeoutDuration timeoutDuration = std::chrono::seconds{ 1 },
PeriodDuration periodDuration = std::chronos::milliseconds{ 10 }
);
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've moved this to aikido/include/control/ros/util.hpp
and am calling this directly with templates in execute
.
|
||
//============================================================================= | ||
// TODO : This is also basically copied from RosTrajectoryExecutor | ||
void RosBarrettHandPositionCommandExecutor::step() |
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 that's fine in for now. We may want to write a base class for actionnlib
-based executors in the future, but there really isn't all that much duplicated code once we move waitForServer
to a helper function.
…cutor in HandPositionCommandExecutor. Adapted from https://github.com/personalrobotics/libherb/pull/20.
Make test_BarrettFinger* compile (although actual execution seems to fail). Make part of test_BarrettHand compile, although introducing `robot` as a parameter seems like it will make testing this difficult.
Merge remote-tracking branch 'origin/SimBarrettHandCommandExecutor' into rosBarrettHandExecutor
…ecutor; moved jointNames to constructor, made it inherit from PositionCommandExecutor
Merge branch 'master' into rosBarrettHandExecutor
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 generally looks great! One last round of very minor comments and I am happy to merge this:
- Write a docstring for
waitForActionServer
. - Move the implementation of
waitForActionServer
to a separate header file. - Fix the bug I commented on in
waitForActionServer
. - Improve the docstring for
RosPositionCommandExecutor
.
👍
@@ -28,6 +29,14 @@ std::unique_ptr<aikido::trajectory::Spline> toSplineJointTrajectory( | |||
trajectory_msgs::JointTrajectory toRosJointTrajectory( | |||
const aikido::trajectory::TrajectoryPtr& trajectory, double timestep); | |||
|
|||
/// Converts Eigen VectorXd and joint names to JointState | |||
/// \param[in] goalPositions The required positions for the fingers |
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: This is not specific to finger joints! 😉
Also, we should add "position" to the name of this function, since we may very well need equivalent functions for velocities and/or efforts. Perhaps positionsToJointState
?
namespace control { | ||
namespace ros { | ||
|
||
/// This class sends commands for the hand position to the ROS server |
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: This comment is not very helpful. At a minimum, we should specify that this class uses actionlib
to command a pr_control_msgs/SetPosition
action.
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 is not resolved.
public: | ||
/// Constructor | ||
/// \param[in] node ROS node handle for action client. | ||
/// \param[in] serverName Name of the server to send traejctory to. |
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.
Typo: "traejctory "
const std::string& serverName, | ||
const std::vector<std::string>& jointNames, | ||
const std::chrono::milliseconds connectionTimeout = std::chrono::milliseconds{1000}, | ||
const std::chrono::milliseconds connectionPollingPeriod = std::chrono::milliseconds{20} |
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: Const is meaningless on a parameter passed by value in a function declaration.
include/aikido/control/ros/util.hpp
Outdated
|
||
const auto startTime = Clock::now(); | ||
const auto endTime = startTime + timeoutDuration; | ||
auto currentTime = startTime + periodDuration; |
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 be initialized to startTime
.
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 based it off this :
https://github.com/personalrobotics/aikido/blob/master/src/control/ros/RosTrajectoryExecutor.cpp#L157
Can you help me figure it out? @gilwoolee any comments?
include/aikido/control/ros/util.hpp
Outdated
::ros::CallbackQueue& callbackQueue, | ||
TimeoutDuration timeoutDuration = std::chrono::milliseconds{ 1000 }, | ||
PeriodDuration periodDuration = std::chrono::milliseconds{ 10 } | ||
) |
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 function needs a docstring. Also, it should only be declared in the util.hpp
file. The implementation should be #included
from a detail/util-impl.hpp
file to match the convention we follow inn the rest of Aikido.
src/control/ros/Conversions.cpp
Outdated
{ | ||
std::stringstream message; | ||
message << "The size of goalPositions ("<<goalPositions.size()<< | ||
") must be the same as jointNames ("<<jointNames.size()<<"!" ; |
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.
There are mismatched parens in this error message.
|
||
sensor_msgs::JointState jointState; | ||
|
||
jointState.name = std::move(jointNames); |
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: It is not possible to std::move
out of jointNames
because it was passed by const
reference. You should either remove the std::move
or modify the function to take jointNames
by value. I'd slightly prefer the latter.
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 is now resolved.
RosPositionCommandExecutor::RosPositionCommandExecutor( | ||
::ros::NodeHandle node, | ||
const std::string& serverName, | ||
const std::vector<std::string>& jointNames, |
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: Take jointNames
by value and std::move
it below.
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 removed the const
as well after looking up std::move
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 looks like this is still not resolved.
RosPositionCommandExecutor::~RosPositionCommandExecutor() | ||
{ | ||
// Do nothing. | ||
// TODO: Should we wait for the current trajectory to finish executing? |
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: This comment was copied and pasted from RosTrajectoryExecutor
. There are no trajectories in this file! 😁
|
||
const auto startTime = Clock::now(); | ||
const auto endTime = startTime + timeoutDuration; | ||
auto currentTime = startTime + periodDuration; |
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 should not have periodDuration
added onto it. Otherwise, the first iteration will have twice the expected period.
|
||
sensor_msgs::JointState jointState; | ||
|
||
jointState.name = std::move(jointNames); |
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 is now resolved.
RosPositionCommandExecutor::RosPositionCommandExecutor( | ||
::ros::NodeHandle node, | ||
const std::string& serverName, | ||
const std::vector<std::string>& jointNames, |
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 looks like this is still not resolved.
namespace control { | ||
namespace ros { | ||
|
||
/// This class sends commands for the hand position to the ROS server |
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 is not resolved.
…obotics/aikido into rosBarrettHandExecutor
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.
LGTM. Thanks for making those changes @Shushman!
- Use find module for pr_control_msgs - Fix unmatched function signature in Conversions - Fix function termination without return value - Fix unordered initialization list
This PR introduces a ROS executor for commands to the Barrett Hand through
aikido/control/ros/RosBarrettHandPositionCommandExecutor.hpp-cpp
.A point to note is that there is a lot of code (and logic) reuse between this and
RosTrajectoryExecutor
. Any way to make this more succinct?