Skip to content
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

Merged
merged 50 commits into from
Apr 22, 2017
Merged

Add RosPositionCommandExecutor #173

merged 50 commits into from
Apr 22, 2017

Conversation

Shushman
Copy link
Contributor

@Shushman Shushman commented Apr 15, 2017

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?

@Shushman Shushman requested review from mkoval and gilwoolee April 15, 2017 21:04
Copy link
Member

@mkoval mkoval left a 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 a ros::Time unless I am wrong about SetPositionGoal lacking a Header.
  • Make jointNames a constructor argument, instead of an argument to execute().
  • 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();
Copy link
Member

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.

Copy link
Contributor Author

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}
);
Copy link
Member

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.

Copy link
Contributor Author

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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

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);
Copy link
Member

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.

Copy link
Contributor Author

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)}
Copy link
Member

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

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().

Copy link
Contributor Author

@Shushman Shushman Apr 17, 2017

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;
Copy link
Member

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?

Copy link
Contributor Author

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

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 }
);

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'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()
Copy link
Member

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.

@mkoval mkoval changed the title Ros barrett hand executor Add RosPositionCommandExecutor Apr 16, 2017
Shushman Choudhury added 8 commits April 17, 2017 11:09
@jslee02 jslee02 added this to the Aikido 0.1.0 milestone Apr 17, 2017
Copy link
Member

@mkoval mkoval left a 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
Copy link
Member

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
Copy link
Member

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.

Copy link
Member

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.
Copy link
Member

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}
Copy link
Member

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.


const auto startTime = Clock::now();
const auto endTime = startTime + timeoutDuration;
auto currentTime = startTime + periodDuration;
Copy link
Member

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

::ros::CallbackQueue& callbackQueue,
TimeoutDuration timeoutDuration = std::chrono::milliseconds{ 1000 },
PeriodDuration periodDuration = std::chrono::milliseconds{ 10 }
)
Copy link
Member

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.

{
std::stringstream message;
message << "The size of goalPositions ("<<goalPositions.size()<<
") must be the same as jointNames ("<<jointNames.size()<<"!" ;
Copy link
Member

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);
Copy link
Member

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.

Copy link
Member

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

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.

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 removed the const as well after looking up std::move

Copy link
Member

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?
Copy link
Member

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;
Copy link
Member

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);
Copy link
Member

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

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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not resolved.

Copy link
Member

@mkoval mkoval left a 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!

Shushman Choudhury and others added 5 commits April 21, 2017 00:02
- Use find module for pr_control_msgs
- Fix unmatched function signature in Conversions
- Fix function termination without return value
- Fix unordered initialization list
@coveralls
Copy link

Coverage Status

Coverage decreased (-1.2%) to 79.163% when pulling 7474bea on rosBarrettHandExecutor into 2af5c55 on master.

@gilwoolee gilwoolee merged commit 5d19317 into master Apr 22, 2017
@gilwoolee gilwoolee deleted the rosBarrettHandExecutor branch April 22, 2017 18:37
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