ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
0

How to continuously publish to a topic using classses?

asked 2018-09-10 00:40:47 -0500

J. J. gravatar image

Hello I have the working code below. It basically gets an input from my joystick button to act as a on and off switch (a single press will turn it on and the second press will turn it off). However, the output I get from this code are the following:

1st press:

data: True
data: False

2nd press:

data: False
data: False

I want to continuously see the output of the topic and not only when I press the button. Here is my code:

#include <ros/ros.h>
#include <std_msgs/Float32.h>
#include <sensor_msgs/Joy.h>
#include <std_msgs/Bool.h>

class Override
{
public:
    Override();

private:

    void joyCallback(const sensor_msgs::Joy::ConstPtr& joy);
    ros::NodeHandle nh_;
    ros::Publisher override_pub;
    ros::Subscriber joy_sub_;
    bool currentReading;
    bool lastReading;
    bool flag;
};

Override::Override()
{

  override_pub = nh_.advertise<std_msgs::Bool>("override_status", 1);
  joy_sub_ = nh_.subscribe<sensor_msgs::Joy>("joy", 10, &Override::joyCallback, this);

}



void Override::joyCallback(const sensor_msgs::Joy::ConstPtr& joy)
{

  std_msgs::Bool override_status;

  if (joy->buttons[4] == 0.0){
    currentReading = false;

  }else currentReading = true;

  if (currentReading && !lastReading) {
    flag=!flag;
    if (flag) {
      override_status.data = true;
    }
    else {
      override_status.data = false;
    }
  }
  lastReading = currentReading;
  override_pub.publish(override_status);
}

int main(int argc, char** argv)
{
  ros::init(argc, argv, "override_node");
  Override override;
  ROS_INFO("Running");
  ros::spin();
}

I tried putting while(ros::ok()) but I don't know where to insert it.

edit retag flag offensive close merge delete

Comments

You mean that you have the output only when the button is pressed ? Normally a joystick is continously publishing its data, can you tell us what is the publishing rate of the topic joy ? ( rostopic hz /joy)

Delb gravatar image Delb  ( 2018-09-10 01:09:48 -0500 )edit

But what you can do is :

  • Create a thread in the constructor of the class

    boost::thread t = boost::thread(boost::bind(&spinthread));

  • Use the thread to spin

    void spinthread() { ros::spin() }

  • Create a global variable in the callback and publish it in the main

Delb gravatar image Delb  ( 2018-09-10 01:16:28 -0500 )edit

(publishing inside a while(ros::ok()) loop)

Delb gravatar image Delb  ( 2018-09-10 01:17:34 -0500 )edit

I can see joy publishing perfectly with rostopic echo joy. But I want to continuously output the state of the button where it is pressed once (ON state = True) or pressed a second time (Off state = False).

J. J. gravatar image J. J.  ( 2018-09-10 01:18:11 -0500 )edit

3 Answers

Sort by » oldest newest most voted
1

answered 2018-09-10 01:46:36 -0500

Delb gravatar image

updated 2018-09-10 02:13:31 -0500

You can do it like that :

//You libraries here
#include <boost/bind.hpp>
#include <tile_planner/reach_goals.h>

//Create a thread only for ros spin
void spinthread()
{
    ros::spin();
}

//Deifne a global variable
std_msgs::Bool override_status;

//Construcor
Override::Override()
{
//Define sub and publishers and start the thread
  boost::thread t = boost::thread(boost::bind(&spinthread));
}

//Callback
void Override::joyCallback(const sensor_msgs::Joy::ConstPtr& joy)
{ 
//Your callback routine here where you set override_status 
}

int main(int argc, char** argv)
{
  ros::init(argc, argv, "override_node");
  Override override;
  //Set rate at 10Hz 
  ros::Rate r(10);
  while(ros::ok())
  {
    override_pub.publish(override_status);
    r.sleep();
  }
}

You will be continously publishing the value of override_status which will be changed each time the callback is called. You can also add a timer and change the publishing rate as you want using ros.sleep()

Creating a thread allows you to collect the data continously in the background so that if you have time consuming functions you don't miss messages that couldn't have been received since the program was still in the function.

edit flag offensive delete link more

Comments

+1 for showing an example.

Can you clarify for future readers why you call ros::spinOnce() in a separate thread? Would AsyncSpinner not work here (but even that seems not needed)?

gvdhoorn gravatar image gvdhoorn  ( 2018-09-10 01:57:46 -0500 )edit

Also: please add a ros::Rate::sleep() in there. This example utilises 100% CPU even when it's doing "nothing".

gvdhoorn gravatar image gvdhoorn  ( 2018-09-10 01:58:11 -0500 )edit

I added a little precision but I'm not familiar with AsyncSpinner so I can't say how it works. (but I would be glad to know if you can explain it to me)

Delb gravatar image Delb  ( 2018-09-10 02:11:23 -0500 )edit

Take a look at roscpp/Overview/Callbacks and Spinning. AsyncSpinner does just about what you do here manually.

gvdhoorn gravatar image gvdhoorn  ( 2018-09-10 02:14:51 -0500 )edit

So is it better to use it rather than create the thread manually ?

Delb gravatar image Delb  ( 2018-09-10 02:37:26 -0500 )edit
1

My suggestion would be to always use standard functionality -- if it is available. It is less work for you, recognisable for others and follows conventions.

gvdhoorn gravatar image gvdhoorn  ( 2018-09-10 02:40:20 -0500 )edit

Note btw: if you go for multithreaded spinning that any callback you register for a topic must be threadsafe.

gvdhoorn gravatar image gvdhoorn  ( 2018-09-10 02:40:55 -0500 )edit
0

answered 2018-09-10 19:35:25 -0500

J. J. gravatar image

Thanks to @Delb and @gvdhoom. Here is my working solution. I didn't implement the spin thread since it would consume a lot of cpu resource.

#include <ros/ros.h>
#include <std_msgs/Float32.h>
#include <sensor_msgs/Joy.h>
#include <std_msgs/Bool.h>


bool flag;


class Override
{
public:
    Override();
  void joyCallback(const sensor_msgs::Joy::ConstPtr& joy);
  void Publisher();
    std_msgs::Bool override_status;

private:
    ros::NodeHandle nh_;
    ros::Publisher override_pub;
  ros::Subscriber joy_sub_;
  bool currentReading;
    bool lastReading;
  std_msgs::Float32 button_status;

};

Override::Override()
{

  override_pub = nh_.advertise<std_msgs::Bool>("override_status", 1);
  joy_sub_ = nh_.subscribe<sensor_msgs::Joy>("joy", 10, &Override::joyCallback, this);


}

void Override::joyCallback(const sensor_msgs::Joy::ConstPtr& joy)
{
   button_status.data=joy->buttons[4];

  if (button_status.data == 0.0){
    currentReading = false;
  }else currentReading = true;

  if (currentReading && !lastReading) {
    flag=!flag;
    if (flag) {
      override_status.data = true;
    }
    else {
      override_status.data = false;
    }
  }
  lastReading = currentReading;

}

void Override::Publisher()
{
  override_pub.publish(override_status);
}




int main(int argc, char** argv)
{
  ros::init(argc, argv, "override_node");
  ROS_INFO("Node Started...");
  Override override;
  ros::Rate r(10);
  while (ros::ok()){
    override.Publisher();
    ros::spinOnce();    
  }
}
edit flag offensive delete link more

Comments

Well you also use 100% of the CPU like that since you're not sleeping. Defining a rate doesn't apply it, you have to add r.sleep(); after spinOnce().

Delb gravatar image Delb  ( 2018-09-11 01:38:58 -0500 )edit
0

answered 2018-09-10 00:56:20 -0500

Hamid Didari gravatar image

Hi you can use ros Timer and publish your msg continuously

example code:

ros::Timer timer = nh_.createTimer(ros::Duration(0.1), timerCallback);

.
.
.

void callback(const ros::TimerEvent& event)
{
  override_pub.publish(override_status);
}
edit flag offensive delete link more

Comments

can I just insert this in the code as another member function?

J. J. gravatar image J. J.  ( 2018-09-10 01:03:09 -0500 )edit

Question Tools

1 follower

Stats

Asked: 2018-09-10 00:40:47 -0500

Seen: 1,988 times

Last updated: Sep 10 '18