0
$\begingroup$

Rosanswers logo

Hi everybody, I'm working on a state_machine right now and I have the following problem: I have a ROS timer running on a timerCallback which supervises the current states and depending on the state does different things. I need this, because I'm waiting for different messages on other subscriber callbacks at the same time and this was (I think) the best possibility to manage those subscribers (Maybe an async spinner could have worked, but anyway, I now have a timer). Since this is only a single part of a larger state-machine I now need to know, when the timer has stopped since this whole system is supposed to be wrapped into one single actionserver, which returns, when the whole task is completed. So now to me actual question: Does anybody know, if there is a possibility to let the timer and all other callbacks run, while the actual execute function of the actionserver waits for the timer to be stopped?

A small example (maybe it helps):

class Foo {
    void startTimer(){
         timer_ = nh_->createTimer(ros::Duration(0.1), &timerCB, this);
    }
    void timerCB(const ros::TimerEvent& timer_event){
        //Do something depending on state and stop timer if finished
    }
    void secondCB(const custom_msg::Msg msg){
        //Change state if necessary
    }
}

class Bar {
    executeCB(const actionlib_msgs::ExampleGoalConstPtr& goal){
        foo.startTimer();
        //Wait for timer to stop
        return true;
    }
}

Originally posted by LeoE on ROS Answers with karma: 196 on 2019-04-20

Post score: 1

$\endgroup$

1 Answer 1

0
$\begingroup$

Rosanswers logo

Ok, I found a solution to the problem. AsyncSpinner work for this as well. The AsyncSpinner needs its custom queue and needs to be started before and stopped after a while loop, which waits for the timer. So to use the example above:

class Foo {

finished_;
ros::CallbackQueue* queue_;
ros::NodeHandle nh_;
ros::Timer timer_;

Foo(ros::NodeHandle* nh, ros::CallbackQueue* queue) : queue_(queue), nh_(nh){
        ros::TimerOptions timer_options(ros::Duration(0.1), &timerCB, queue_);
        timer_ = nh_->createTimer(timer_options);

        finished_ = false;

        ros::SubscribeOptions subscriber_options = ros::SubscribeOptions::create<custom_msgs::Msg>
            ("example/topic", 1, &secondCB, ros::VoidPtr(), queue_);
    }

    void startTimer(){
         timer_.start();
    }
    void timerCB(const ros::TimerEvent& timer_event){
        //Do something depending on state and stop timer if finished
        if(finishing_condition_met){
            timer_.stop();
            finished_ = true;
        }
    }
    void secondCB(const custom_msg::Msg msg){
        //Change state if necessary
    }
}

class Bar {
    ros::CallbackQueue queue_;
    ros::NodeHandle* nh_;
    Foo* foo;
    ros::AsyncSpinner* async_spinner_;

    Bar bar(ros::NodeHandle* nh) : nh_(nh){
        foo = new Foo(nh_, &queue_);
        async_spinner_ = new ros::AsyncSpinner(4, &state_queue_);
    }

    executeCB(const actionlib_msgs::ExampleGoalConstPtr& goal){
        foo = new Foo(nh_, &queue_);
        async_spinner->start();
        foo.startTimer();
        while(ros::ok() && !foo->finished_{
            //Wait for Foo to finish
        }
        async_spinner->stop();
        return true;
    }
}

I hope it helps someone out there and I would really love to hear from you guys, if there is a better way to do it! Btw, this is just an example so please don't hang yourself up on small mistakes, it's not exactly the way I implemented it. If you find mistakes however, please let me know, I will change them, so maybe someone else doesn't need to fight his/ her way through my wrong code ;)


Originally posted by LeoE with karma: 196 on 2019-04-20

This answer was ACCEPTED on the original site

Post score: 2

$\endgroup$

Your Answer

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