0
$\begingroup$

Rosanswers logo

Hey there,

I have written a C++ RViz custom panel. The implementation roughly follows this example link.

The panel subscribe to a specific topic PointStamped type, and fills a list that gets displayed inside the panel as x and y coordinates.

Now, I've created a push button and implemented an actionlib move_base goal function. The purpose is, the robot to go from one point to another. The problem is while i succesfully send the goals, RViz Visualization is blocked/freezed until the move is complete probably because ac.waitForResult() is a blocking function.

How can i overcome this and let RViz keep visualizing robot's position while the robot moves to a point, get the result and then move to another point in the list. What i was thinking is probably about blocking GUI thread, so i good idead proably is to spin a new thread, but how can i accomplish this? Correct me. if I am wrong, and please if you need more info just let me know.

Here is a block of code that i am using right now and is blocking:

void Waypoints::moveTo() {
//tell the action client that we want to spin a thread by default
MoveBaseClient ac("move_base",true);
//wait for the action server to come up
while(!ac.waitForServer(ros::Duration(5.0))){
    ROS_INFO("Waiting for the move_base action server to come up");
}
ROS_INFO("Move_base action server has come up");

move_base_msgs::MoveBaseGoal goal;

for (size_t x = 0; x < mBestPathNodes.size() - 1; x++) {
   // we'll send a goal to the robot to move 1 meter forward
    goal.target_pose.header.frame_id = "map";
    goal.target_pose.header.stamp = ros::Time::now();

    goal.target_pose.pose.position.x = mWaypoints[mBestPathNodes[x]].point.x;
    goal.target_pose.pose.position.y = mWaypoints[mBestPathNodes[x]].point.y;
    goal.target_pose.pose.orientation.w = 1.0;

    ROS_INFO("Sending goal");

    ac.sendGoal(goal);
    ac.waitForResult();
    bool finished_before_timeout = ac.waitForResult(ros::Duration(30.0));

      if (finished_before_timeout)
      {
        actionlib::SimpleClientGoalState state = ac.getState();
        ROS_INFO("Action finished: %s",state.toString().c_str());
      }
      else
        ROS_INFO("Action did not finish before the time out.");

}

Originally posted by xkaraman on ROS Answers with karma: 23 on 2020-05-21

Post score: 1

$\endgroup$

2 Answers 2

0
$\begingroup$

Rosanswers logo

You need to spin up another thread to wait and throw back a result once its complete. Or optionally not wait for a result since all you're doing is printing to screen. Since you're not using the result or tracking progress, there's not a bunch of value in waiting around, unless that print statement is really important to you. In that case, you should just run another thread that is waiting for the result and printing the completion status.

If you want to thread it, std::threads is what you want for the most basic implementation https://en.cppreference.com/w/cpp/thread/thread


Originally posted by stevemacenski with karma: 8272 on 2020-05-21

This answer was ACCEPTED on the original site

Post score: 1


Original comments

Comment by xkaraman on 2020-05-22:
I' am actually printing to see it's working because RViz freezes and can't see my robot moving around. Even so, i would need the result in order to see what's happening, and if it's a point is a reached THEN move to another one. If i have 3 points to go through, if i don't have the waitForResult, the for loop will just start for a moment the movement to 1st point, then stop it almost immediately, begin course for 2nd point, stop and then go for the 3rd point. I could implement another way, if you have anything in mind but the waitForResult i think it should be there.

Comment by stevemacenski on 2020-05-22:
Answer still stands- you need to spin up a background thread to process it.

Comment by xkaraman on 2020-05-23:
OK i understand that. How can i spin a background thread then? The link is not that helpful without an example unfortunately.

Comment by stevemacenski on 2020-05-24:
I think that's something you should look up yourself. That's not really a ROS question but a basic C++ question. That documentation link should be sufficient to use, but there are other C++ threading tutorials that may be better suited to introducing the concept to you.

Comment by xkaraman on 2020-05-25:
OK thanks for your answer man! :) Have a good day!

$\endgroup$
0
$\begingroup$

Rosanswers logo

I have a similar issue. I haven't resolved it completly yet, but to put you on track, I basically went though the moveit code to try to understand how the team does it. I have managed to make it work with:

this header:

#include moveit/background_processing/background_processing.h>

declaring the following object in MyPanel class:

moveit::tools::BackgroundProcessing background_process_;

After, I put all the moveit code in a function

void MyPanel::plan(){ /** code**/}

and call the function with:

background_process_.addJob(boost::bind(&MyPanel::plan, this), "plan");

May be necessary to add this to the MyPanel destructor:

background_process_.clear();


Originally posted by AlexisGaziello with karma: 11 on 2020-05-21

This answer was NOT ACCEPTED on the original site

Post score: 1


Original comments

Comment by xkaraman on 2020-05-22:
This would require MoveIt framework if I'm not mistaken right? I would like not to involve yet other libraries rather than ROS and maybe boost!

Comment by stevemacenski on 2020-05-22:
Its just spinning up a background worker like my answer suggested. They just wrote a nice tool for it. I didn’t want to overcomplicate it for you - if you’re not familiar just using std::thread is fine.

Comment by demorise on 2022-04-13:
I faced a similar issue and this solution worked for me. I just had to omit background_process_.clear(); from my destructor because it was throwing a free(): double free detected in tcache 2 error

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.