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

New tem2 #2

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open

New tem2 #2

wants to merge 12 commits into from

Conversation

cambel
Copy link
Owner

@cambel cambel commented Aug 12, 2022

Continuous trajectory execution feature proposal

Each new request push()-ed to the trajectory execution manager would spawn a new thread for its execution.
The thread would validate and if valid execute the trajectory:

  1. Validate trajectory
    1. Ensure that controllers are active
    2. Check that required controllers are not being used already
    3. Check that the start state of the trajectory matches the current state of the robot. It already considers the case where no such restriction is required.
    4. Collision checking
      1. Check collision against currently active trajectories
      2. Check collision against the current state of the planning scene
  2. Execute trajectories
  3. Monitor execution duration

I wanted to overload the executeThread method but I get an error when attempting that.

If a vector of trajectories is pushed in continuous mode, the trajectories will be executed in sequential mode only, not simultaneously. Additionally, if one trajectory fails, subsequent trajectories will be aborted.
Copy link

@simonschmeisser simonschmeisser left a comment

Choose a reason for hiding this comment

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

I added some first comments

@@ -989,6 +1046,12 @@ void TrajectoryExecutionManager::execute(const ExecutionCompleteCallback& callba
void TrajectoryExecutionManager::execute(const ExecutionCompleteCallback& callback,
const PathSegmentCompleteCallback& part_callback, bool auto_clear)
{
if (allow_continuous_execution_)
{
ROS_WARN_NAMED(LOGNAME, "Calls to execute() are not allowed when using continuous execution.");

Choose a reason for hiding this comment

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

Maybe reformulate a bit more positive. "In continous execution mode push()ed trajectories are started automatically. Ignoring call to execute()."

Copy link
Owner Author

Choose a reason for hiding this comment

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

Okay!

execution_thread_ = std::make_unique<boost::thread>(&TrajectoryExecutionManager::executeThread, this, callback,
part_callback, auto_clear);
execution_thread_ =
std::make_unique<boost::thread>([this](const ExecutionCompleteCallback& c, const PathSegmentCompleteCallback& pc,

Choose a reason for hiding this comment

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

Suggested change
std::make_unique<boost::thread>([this](const ExecutionCompleteCallback& c, const PathSegmentCompleteCallback& pc,
std::make_unique<std::thread>([this](const ExecutionCompleteCallback& c, const PathSegmentCompleteCallback& pc,

this way it fits into one line in github diff view 😉

Copy link
Owner Author

Choose a reason for hiding this comment

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

I will replace boost with standard libraries on all occurrences

trajectories_.clear();
}
else
ROS_ERROR_NAMED(LOGNAME, "Cannot push a new trajectory while another is being executed");
}

void TrajectoryExecutionManager::executeThread(

Choose a reason for hiding this comment

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

Please add a comment explaining which overload is which

Copy link
Owner Author

Choose a reason for hiding this comment

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

Okay!

if (jointTrajPointToRobotState(active_trajectory.joint_trajectory, i, start_state))
{
robotStateToRobotStateMsg(start_state, start_state_msg);
if (!ps->isPathValid(start_state_msg, new_trajectory, new_trajectory.group_name, true))

Choose a reason for hiding this comment

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

Do we want to add a todo to add interpolation here?

Copy link
Owner Author

Choose a reason for hiding this comment

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

I think we do want to improve that later so I will add it

const moveit_msgs::RobotTrajectory& active_trajectory)
{
// Before we start checking collisions, ensure that we have the latest robot state received...
planning_scene_monitor_->waitForCurrentRobotState(ros::Time::now());

Choose a reason for hiding this comment

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

if new_trajectory and active_trajectory cover all joints we could skip waiting for the updated robot state

Copy link
Owner Author

Choose a reason for hiding this comment

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

Do they cover all joints?

Choose a reason for hiding this comment

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

No not generally, but in case they do this could be optimized ... but that's not a high priority

{
ROS_DEBUG_STREAM_NAMED(
LOGNAME,
"Collision found between trajectory with (group_name, duration): "

Choose a reason for hiding this comment

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

Suggested change
"Collision found between trajectory with (group_name, duration): "
"Collision found between incoming trajectory with (group_name, duration): "

or similar

Copy link
Owner Author

Choose a reason for hiding this comment

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

Okay!

return true;
}

bool TrajectoryExecutionManager::checkCollisionsWithCurrentState(const moveit_msgs::RobotTrajectory& trajectory)

Choose a reason for hiding this comment

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

isn't this redundant with the other check?

Copy link
Owner Author

Choose a reason for hiding this comment

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

Maybe, but if there are no active trajectories then the other check wouldn't happen. But this could be done more efficiently

const TrajectoryExecutionContext& context, std::set<moveit_controller_manager::MoveItControllerHandlePtr>& handles)
{
// compute the expected duration of the trajectory and find the part of the trajectory that takes longest to execute
ros::Time current_time = ros::Time::now();

Choose a reason for hiding this comment

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

Suggested change
ros::Time current_time = ros::Time::now();
ros::Time start_time = ros::Time::now();

Copy link
Owner Author

Choose a reason for hiding this comment

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

Okay!

{
if (execution_duration_monitoring_)
{
if (!handle->waitForExecution(expected_trajectory_duration))

Choose a reason for hiding this comment

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

doesn't this potentially wait handles.size()*(expected_trajectory_duration - epsilon) if the first handle finishes just in time, the second takes 2 * duration and so on. I know it's contrived but ...

Suggested change
if (!handle->waitForExecution(expected_trajectory_duration))
if (!handle->waitForExecution(expected_trajectory_duration - (ros::Time::now() - current_time))

Copy link
Owner Author

Choose a reason for hiding this comment

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

Yes, this actually does not makes much sense to me either. It technically waits for the expected trajectory duration time for each handle

Comment on lines +1076 to +1078
std::make_unique<boost::thread>([this](const ExecutionCompleteCallback& c, const PathSegmentCompleteCallback& pc,
bool ac) { executeThread(c, pc, ac); },
callback, part_callback, auto_clear);

Choose a reason for hiding this comment

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

Suggested change
std::make_unique<boost::thread>([this](const ExecutionCompleteCallback& c, const PathSegmentCompleteCallback& pc,
bool ac) { executeThread(c, pc, ac); },
callback, part_callback, auto_clear);
std::make_unique<std::thread>([&]() { executeThread(callback, part_callback, auto_clear);});

or similar

Copy link
Owner Author

Choose a reason for hiding this comment

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

This was necessary to explicitly declare which overloaded method to use. But I think that won't be necessary anymore

}
else
{
ROS_DEBUG_NAMED(LOGNAME, "Execution stopped before starting");

Choose a reason for hiding this comment

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

We can end up here with eg the second trajectory of a bundle of 3. Then this message would be confusing.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Okay, I will change it

@simonschmeisser
Copy link

This does not yet include the "backlog" right? Is that by design or do you intend to add it in this PR as well? I'm starting to understand @v4hn rationale of maybe implementing the "backlog" in higher levels and outside the TEM so it might make sense to finish this PR first? Rejecting trajectories that are temporarily in collision could allow users to change plans and modify trajectories or reorder tasks/goals


if (allow_continuous_execution_)
{
ROS_INFO_NAMED(LOGNAME, "Creating thread");

Choose a reason for hiding this comment

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

I wonder if the validation should happen here already and basically the push being rejected (return false) if the trajectory cannot currently be executed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants