I created ROS Service with a client and server node. I created a ROS Service that pass the IMU sensors values from the Server to Client. And Im able to call the server and client node and get the values. But when call them with the launch file I got zero
Here the server node
#include "ros/ros.h"
#include <sensor_msgs/Imu.h>
#include "imu_service/ImuValue.h"
ros::ServiceServer service;
double current_x_orientation_s;
double get_imu_orientation_x;
bool get_val(imu_service::ImuValue::Request &req, imu_service::ImuValue::Response &res)
{
ROS_INFO("sending back response");
res.current_x_orientation_s = get_imu_orientation_x;
//.. same for the other IMU values
}
void imuCallback(const sensor_msgs::ImuConstPtr& msg)
{
current_x_orientation_s= msg->orientation.x;
get_imu_orientation_x=current_x_orientation_s;
// ..same for other IMU values
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "imu_status_server");
ros::NodeHandle n;
ros::Subscriber sub = n.subscribe("/thrbot/imu", 10, imuCallback);
service = n.advertiseService("imu_status_server", get_val);
ROS_INFO("Starting server...");
ros::spin();
return 0;
}
Client
#include "ros/ros.h"
#include "ros_services/ImuValue.h"
#include <cstdlib>
ros::ServiceClient client;
int main(int argc, char **argv)
{
ros::init(argc,argv,"imu_client_node");
ros::NodeHandle n;
ros::NodeHandle nh_;
//ros::Subscriber joy_sub_ = nh_.subscribe<sensor_msgs::Joy>("/thrbot/joy", 10, joystick_callback);
client = n.serviceClient<ros_services::ImuValue>("imu_status_server");
ros_services::ImuValue srv;
client.call(srv);
std::cout << "Got accel x: " << srv.response.current_x_orientation_s << std::endl;
return 0;
}
And the launch file
<?xml version="1.0"?>
<launch>
<node name="ImuServerService" pkg="ros_services" type="ImuServerService" output="screen">
</node>
<node name="ImuClientService" pkg="ros_services" type="ImuClientService" output="screen"/>
</launch>
I got 0 as response.
[ INFO] [1631800449.207350420]: Starting server...
[ INFO] [1631800449.212336478]: sending back response
Got accel x: 0
But when manually run the Server and the Client with
rosrun ros_services ImuServerService and rosrun ros_services ImuClientService the value is correct one
Any help?
The reason you're getting 0 back is because the client immediately calls the service on startup. Since it also immediately returns the last cached value and they're both started at almost the same time via roslaunch this means there's essentially no way a message will be received on the topic by the service is called. This works with rosrun because having to manually launch the nodes gives it enough time to actually receive something on the topic. You can observe it by adding a delay to the start of your client like so:
#include "ros/ros.h"
#include "ros_services/ImuValue.h"
#include <cstdlib>
ros::ServiceClient client;
int main(int argc, char **argv)
{
ros::init(argc,argv,"imu_client_node");
ros::NodeHandle n;
ros::NodeHandle nh_;
//ros::Subscriber joy_sub_ = nh_.subscribe<sensor_msgs::Joy>("/thrbot/joy", 10, joystick_callback);
client = n.serviceClient<ros_services::ImuValue>("imu_status_server");
ros_services::ImuValue srv;
ros::Duration(5).sleep(); //Sleep for 5 seconds
client.call(srv);
std::cout << "Got accel x: " << srv.response.current_x_orientation_s << std::endl;
return 0;
}
Related
My question is that is the callback thread-safe? For multiple callbacks that may access and potentially modify shared data, is adding mutex locks a good practice?
I am testing the behavior of running two threads with two callback functions that access and modify shared data.
I have found a similar post here, but in my simple experiments, I am expecting something such as race condition happening, but it did not happen.
I wrote a publisher node which can publish two String messages in two threads and each message will be pubished for one second with different frequency.
#include <boost/thread.hpp>
#include <ros/ros.h>
#include <std_msgs/String.h>
int main(int argc, char **argv)
{
ros::init(argc, argv, "AB_topic_pub");
ros::NodeHandle nh;
ros::Publisher pub_a = nh.advertise<std_msgs::String>("msg_a", 200);
ros::Publisher pub_b = nh.advertise<std_msgs::String>("msg_b", 200);
int COUNT_A = 0, COUNT_B = 0;
ros::Duration(2.0).sleep();
boost::thread pub_thread_a(
[&]()
{
ROS_INFO("Publishing A for one second.");
ros::Time start_time = ros::Time::now();
ros::Rate freq(1000);
while (ros::Time::now() - start_time < ros::Duration(1.0)) {
std_msgs::String MSG_A;
MSG_A.data = "A" + std::to_string(COUNT_A);
pub_a.publish(MSG_A);
freq.sleep();
COUNT_A++;
}
}
);
boost::thread pub_thread_b(
[&]()
{
ROS_INFO("Publishing B for one second.");
ros::Time start_time = ros::Time::now();
ros::Rate freq(200);
while (ros::Time::now() - start_time < ros::Duration(1.0)) {
std_msgs::String MSG_B;
MSG_B.data = "B" + std::to_string(COUNT_B);
pub_b.publish(MSG_B);
freq.sleep();
COUNT_B++;
}
}
);
pub_thread_a.join();
pub_thread_b.join();
std::cout << "A COUNT: " << COUNT_A << std::endl;
std::cout << "B COUNT: " << COUNT_B << std::endl;
}
I wrote a subscriber node with two callback queues. In the following code, I want to count the how many times the callbacks are called in total. I defined two variables COUNT_WO_LOCK without mutex guarding and COUNT_W_LOCK with a mutex guarding.
#include <iostream>
#include <boost/function.hpp>
#include <boost/atomic/atomic.hpp>
#include <boost/thread.hpp>
#include <ros/callback_queue.h>
#include <ros/ros.h>
#include <std_msgs/String.h>
int main(int argc, char **argv)
{
ros::init(argc, argv, "callback_lock_test");
ros::NodeHandle nh_a;
ros::NodeHandle nh_b;
ros::CallbackQueue cq_a, cq_b;
nh_a.setCallbackQueue(&cq_a);
nh_b.setCallbackQueue(&cq_b);
int COUNT_WO_LOCK;
COUNT_WO_LOCK = 0;
int COUNT_W_LOCK;
COUNT_W_LOCK = 0;
boost::mutex LOCK;
boost::function<void(const std_msgs::String::ConstPtr &msg)> cb_a =
[&](const std_msgs::StringConstPtr &msg)
{
LOCK.lock();
COUNT_W_LOCK++;
LOCK.unlock();
COUNT_WO_LOCK++;
ROS_INFO("[Thread ID: %s] I am A, heard: [%s]", boost::lexical_cast<std::string>(boost::this_thread::get_id()).c_str() , msg->data.c_str());
};
boost::function<void(const std_msgs::String::ConstPtr &msg)> cb_b =
[&](const std_msgs::StringConstPtr &msg)
{
LOCK.lock();
COUNT_W_LOCK++;
LOCK.unlock();
COUNT_WO_LOCK++;
ROS_WARN("\t\t[Thread ID: %s] I am B, heard: [%s]", boost::lexical_cast<std::string>(boost::this_thread::get_id()).c_str() , msg->data.c_str());
};
// A pub for one second at 1000Hz
ros::Subscriber sub_a = nh_a.subscribe<std_msgs::String>("msg_a", 200,
cb_a, ros::VoidConstPtr(), ros::TransportHints().tcpNoDelay(true));
// B pub for one second at 200Hz
ros::Subscriber sub_b = nh_b.subscribe<std_msgs::String>("msg_b", 200,
cb_b, ros::VoidConstPtr(), ros::TransportHints().tcpNoDelay(true));
boost::thread spin_thread_a(
[&]()
{
ROS_ERROR("\t\t\t\t\t [Spinner Thead ID: %s]", boost::lexical_cast<std::string>(boost::this_thread::get_id()).c_str());
while (!sub_a.getNumPublishers()) { }
while (ros::ok())
cq_a.callAvailable(ros::WallDuration());
}
);
boost::thread spin_thread_b(
[&]()
{
ROS_ERROR("\t\t\t\t\t [Spinner Thead ID: %s]", boost::lexical_cast<std::string>(boost::this_thread::get_id()).c_str());
while (!sub_b.getNumPublishers()) { }
while (ros::ok())
cq_b.callAvailable(ros::WallDuration());
}
);
spin_thread_a.join();
spin_thread_b.join();
if (ros::isShuttingDown()) {
std::cout << "LOCKED COUNT: " << COUNT_W_LOCK << std::endl;
std::cout << "UNLOCKED COUNT: " << COUNT_WO_LOCK << std::endl;
}
}
I first launched the subscriber node and then launched the publisher node. I am expecting that COUNT_W_LOCK is 1200 and COUNT_WO_LOCK is <1200, but in fact they are all 1200.
As mentioned in a comment callbacks are thread safe in ROS. I think the issue is what you're describing vs what you're expecting might be a little different. The short answer is that for a single callback, even if you have multiple messages published at once, there will only every be one execution of that callback at a given time; i.e. 2 threads will not execute that callback at the same time. This is because on the backend ROS subscribers use a queue. So as callbacks are executed the last message is popped off the queue.
Do note that there are potential thread safety issues with accessing that data before the threads return. It's not something your code does, but issues can pop up if your main thread is editing or accessing data at the same time as the callback.
I am using the PUB/SUB model in ZeroMQ inside ROS.
The SUB-subscriber is allowed to stop just by pressing a Ctrl+C in the terminal.
However, every time, when I actually press the Ctrl+C, it stops by throwing the following error:
^Cterminate called after throwing an instance of 'zmq::error_t'
what(): Interrupted system call
Aborted (core dumped)
Below is the code snippet:
#include <ros/ros.h>
#include <zmq.hpp>
int main(int argc, char **argv)
{
ros::init(argc, argv, "node_name", ros::init_options::AnonymousName);
ros::NodeHandle nh;
ros::Publisher pub;
// Prepare context and publisher
zmq::context_t zmq_context(1);
zmq::socket_t zmq_socket(zmq_context, ZMQ_SUB);
zmq_socket.connect("tcp://192.168.1.20:9001");
std::string TOPIC = "";
zmq_socket.setsockopt(ZMQ_SUBSCRIBE, TOPIC.c_str(), TOPIC.length()); // allow all messages
int timeout = 1000; // Timeout to get out of the while loop since recv is blocking
zmq_socket.setsockopt(ZMQ_RCVTIMEO, &timeout, sizeof(timeout));
while (ros::ok())
{
zmq::message_t msg;
int rc = zmq_socket.recv(&msg);
if (rc)
{
//receive data and prepare it for publishing
pub.publish(data);
ros::spinOnce();
}
}
// Clean up the socket and context here
zmq_socket.close();
zmq_context.close();
return 0;
}
How to avoid the error so as to shut down the subscriber properly?
Without details about how the Ctrl+C was being trapped and handled, I would always add ( C++ binding details may differ version to version ):
int main(int argc, char **argv)
{
zmq_socket.connect( "tcp://192.168.1.20:9001" );
zmq_socket.setsockopt( ZMQ_LINGER, 0 ); // ALWAYS
...
while( ROS::ok() )
{
...
}
std::cout << "SIG:: will .close() after ROS::ok()-loop exit" << std::flush;
zmq_socket.close();
std::cout << "SIG:: will .term() after a Socket()-instance .close()'d" << std::flush;
zmq_context.close();
std::cout << "SIG:: will return 0 after a Context()-instance .term()'d" << std::flush;
return 0;
}
I realized that the issue is caused by int rc = zmq_socket.recv(&msg) hence I did following improvements-
I used try and catch block
Set ZMQ_LINGER as suggested by #user3666197
Below is the code snippet-
int linger = 0; // Proper shutdown ZeroMQ
zmq_socket.setsockopt(ZMQ_LINGER, &linger, sizeof(linger));
std::string socket_address = "tcp://192.168.1.20:9001";
zmq_socket.connect(socket_address.c_str());
ros::Duration duration(0.1); // in seconds (100 ms)
while (ros::ok())
{
zmq::message_t msg;
int rc = 0;
try
{
rc = zmq_socket.recv(&msg);
}
catch (zmq::error_t& e)
{
ROS_DEBUG_STREAM("ZMQ Error. " << e.what());
}
if (rc)
{
unsigned char* byte_ptr = static_cast<unsigned char*>(msg.data());
const int msg_length = msg.size();
// receive data and prepare it for publishing
pub.publish(data);
ros::spinOnce();
}
else
{
ROS_DEBUG_STREAM("Pointcloud recv() returned 0");
duration.sleep();
}
}
Thanks
I have a follow-up to How to implement Pub-Sub Network with a Proxy by using XPUB and XSUB in ZeroMQ(C++)?
That question requested a C++ proxy using XSUB and XPUB. The answer given is essentially the proxy main() function quoted below.
I extended this proxy to a full working example including a publisher and subscriber. The catch is that my code only works with dealer / router options (as shown in comments below). With the actual (uncommented) XPUB / XSUB options below, subscribers don't get messages. What's going wrong? Is there a tweak to get messages to arrive?
Proxy not working with XPUB/XSUB (working dealer / router in comments)
#include <zmq.hpp>
int main(int argc, char* argv[]) {
zmq::context_t ctx(1);
zmq::socket_t frontend(ctx, /*ZMQ_ROUTER*/ ZMQ_XSUB);
zmq::socket_t backend(ctx, /*ZMQ_DEALER*/ ZMQ_XPUB);
frontend.bind("tcp://*:5570");
backend.bind("tcp://*:5571");
zmq::proxy(frontend, backend, nullptr);
return 0;
}
Subscriber not working with ZMQ_SUB (working dealer / router option in comments)
#include <iostream>
#include <zmq.hpp>
std::string GetStringFromMessage(const zmq::message_t& msg) {
char* tmp = new char[msg.size()+1];
memcpy(tmp,msg.data(),msg.size());
tmp[msg.size()] = '\0';
std::string rval(tmp);
delete[] tmp;
return rval;
}
int main(int argc, char* argv[]) {
zmq::context_t ctx(1);
zmq::socket_t socket(ctx, /*ZMQ_DEALER*/ ZMQ_SUB);
socket.connect("tcp://localhost:5571");
while (true) {
zmq::message_t identity;
zmq::message_t message;
socket.recv(&identity);
socket.recv(&message);
std::string identityStr(GetStringFromMessage(identity));
std::string messageStr(GetStringFromMessage(message));
std::cout << "Identity: " << identityStr << std::endl;
std::cout << "Message: " << messageStr << std::endl;
}
}
Publisher not working with ZMQ_PUB (working dealer / router option in comments)
#include <unistd.h>
#include <sstream>
#include <zmq.hpp>
int main (int argc, char* argv[])
{
// Context
zmq::context_t ctx(1);
// Create a socket and set its identity attribute
zmq::socket_t socket(ctx, /*ZMQ_DEALER*/ ZMQ_PUB);
char identity[10] = {};
sprintf(identity, "%d", getpid());
socket.setsockopt(ZMQ_IDENTITY, identity, strlen(identity));
socket.connect("tcp://localhost:5570");
// Send some messages
unsigned int counter = 0;
while (true) {
std::ostringstream ss;
ss << "Message #" << counter << " from PID " << getpid();
socket.send(ss.str().c_str(),ss.str().length());
counter++;
sleep(1);
}
return 0;
}
In subscriber code you haven't subscribed to receive messages from the publisher. Try adding the line:
socket.setsockopt(ZMQ_SUBSCRIBE, "", 0);
before/after the line:
socket.connect("tcp://localhost:5571");
in your Subscriber code
broker example
#include <zmq.hpp>
int main(int argc, char* argv[]) {
void* ctx = zmq_ctx_new();
assert(ctx);
void* frontend = zmq_socket(ctx, ZMQ_XSUB);
assert(frontend);
void* backend = zmq_socket(ctx, ZMQ_XPUB);
assert(backend);
int rc = zmq_bind(frontend, "tcp://*:5570");
assert(rc==0);
rc = zmq_bind(backend, "tcp://*:5571");
assert(rc==0);
zmq_proxy_steerable(frontend, backend, nullptr, nullptr);
zmq_close(frontend);
zmq_close(backend);
rc = zmq_ctx_term(ctx);
return 0;
}
pub example
#include <zmq.hpp>
#include <bits/stdc++.h>
using namespace std;
using namespace chrono;
int main(int argc, char* argv[])
{
void* context = zmq_ctx_new();
assert (context);
/* Create a ZMQ_SUB socket */
void *socket = zmq_socket (context, ZMQ_PUB);
assert (socket);
/* Connect it to the host
localhost, port 5571 using a TCP transport */
int rc = zmq_connect (socket, "tcp://localhost:5570");
assert (rc == 0);
while (true)
{
int len = zmq_send(socket, "hello", 5, 0);
cout << "pub len = " << len << endl;
this_thread::sleep_for(milliseconds(1000));
}
}
sub example
#include <iostream>
#include <zmq.hpp>
using namespace std;
int main(int argc, char* argv[])
{
void* context = zmq_ctx_new();
assert (context);
/* Create a ZMQ_SUB socket */
void *socket = zmq_socket (context, ZMQ_SUB);
assert (socket);
/* Connect it to the host localhost, port 5571 using a TCP transport */
int rc = zmq_connect (socket, "tcp://localhost:5571");
assert (rc == 0);
rc = zmq_setsockopt(socket, ZMQ_SUBSCRIBE, "", 0);
assert (rc == 0);
while (true)
{
char buffer[1024] = {0};
int len = zmq_recv(socket, buffer, sizeof(buffer), 0);
cout << "len = " << len << endl;
cout << "buffer = " << buffer << endl;
}
}
I'm asking you if there is a way to have a precedence between two ROS nodes. In particular, i have a ROS node that makes an output that is a text file with 60 data in it, and it recreates it every time because the data are changing. Then i have a node that has to analyze that text file. Basically, what i need is to make some changes to have a mechanism that stops the analyzer node when the writer node is running, then it has to send a signal to the analyzer node to make it able to run and analyze the text file. And then the writer node has to return let's say "in charge" to be able to re-write the text file again. So, in simple words, is a loop. Someone told me that a possible solution can be something like a "semaphore" topic in which the writer node writes, for example, a boolean value of 1 when is doing the opening, the writing and the closing of the text file, so the analyzer node knows that cannot do its elaboration, since the file is not ready yet. And, when the writer has finished and closed the text file, it has to be published a value 0 that permits the analysis by the analyzer node. I searched for the publishing of boolean values and i found a code that can be something like this:
ros::Publisher pub = n.advertise<std_msgs::Bool>("semaphore", 1000);
std_msgs::Bool state;
state.data = 1;
I don't know if i have only to use the publisher in the writer node and the subscriber in the analyzer node. Maybe i have to use both of them in the two nodes, something like: writer put a 1 in the topic semaphore so the analyzer knows that cannot access the text file, makes the text file and then put a 0 in the topic and subscribe to the topic waiting again a 1; the analyzer does something similar but in reverse. I put the two codes below, because i don't have any idea where to put the publisher and the the subscriber and how to make them working well. If possible, i have to keep this structure of working flow in my codes.
NOTE: a new text file is created almost every 10 seconds, since in the text file are written data coming from another ROS topic and the code in the writer has a mechanism to do this kind of elaboration.
Thank you in advance!!!
EDIT: Now the codes are corrected with a topic based solution as i explain in my last comment.
Writer code:
#include "ros/ros.h"
#include "std_msgs/String.h"
#include "std_msgs/Bool.h"
#include "../include/heart_rate_monitor/wfdb.h"
#include <stdio.h>
#include <sstream>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <algorithm>
#include <deque>
#include "heart_rate_monitor/analyse_heart_rate.h"
using namespace std;
static std::deque<std::string> queue_buffer;
static int entries_added_since_last_write = 0;
ros::Publisher pub;
void write_data_to_file()
{
// open file;
std::ofstream data_file("/home/marco/catkin_ws/src/heart_rate_monitor/my_data_file.txt");
if (data_file.is_open())
{
for (int i = 0; i < queue_buffer.size(); ++i)
{
data_file << queue_buffer[i] << std::endl;
}
}
else
{
std::cout << "Error - Cannot open file." << std::endl;
exit(1);
}
data_file.close();
std_msgs::Bool state;
state.data = 0;
pub.publish(state);
}
void process_message(const std_msgs::String::ConstPtr& string_msg)
{
std_msgs::Bool state;
state.data = 1;
pub.publish(state);
// if buffer has already 60 entries, throw away the oldest one
if (queue_buffer.size() == 60)
{
queue_buffer.pop_front();
}
// add the new data at the end
queue_buffer.push_back(string_msg->data);
// check if 10 elements have been added and write to file if so
entries_added_since_last_write++;
if (entries_added_since_last_write >= 10
&& queue_buffer.size() == 60)
{
// write data to file and reset counter
write_data_to_file();
entries_added_since_last_write = 0;
}
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "writer");
ros::NodeHandle n;
ros::Subscriber sub = n.subscribe("/HeartRateInterval", 1000, process_message);
pub = n.advertise<std_msgs::Bool>("/semaphore", 1000);
ros::spin();
return 0;
}
Analyzer code:
#include "ros/ros.h"
#include "std_msgs/String.h"
#include "std_msgs/Bool.h"
#include "../include/heart_rate_monitor/wfdb.h"
#include <stdio.h>
#include <sstream>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <algorithm>
#include <deque>
#include "heart_rate_monitor/analyse_heart_rate.h"
void orderCallback(const std_msgs::Bool::ConstPtr& msg)
{
if (msg->data == 0)
{
chdir("/home/marco/catkin_ws/src/heart_rate_monitor");
system("get_hrv -R my_data_file.txt >doc.txt");
}
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "analyzer");
ros::NodeHandle n;
ros::Subscriber sub = n.subscribe("/semaphore", 1000, orderCallback);
ros::spin();
return 0;
}
This could be done simply using ROS services. Basically, when your node A gets the message, it does what it needs (write file) and then asks for a serice from node B (analyse the file).
The only con I see is that node A will have to wait for node B service to finish. If B dosen't need too much time, it wouldn't raise a problem.
Code Snippet :
Srv :
create a service named "analyse_heart_rate.srv" in the srv folder of your package (I supposed it's name "heart_rate_monitor").
specify the request/response of your service structure in the file:
string filename
---
bool result
CMakeLists :
add the following lines :
add_service_files(
FILES
analyse_heart_rate.srv
)
Service Server :
#include "ros/ros.h"
#include "heart_rate_monitor/analyse_heart_rate.h"
bool analyse(heart_rate_monitor::analyse_heart_rate::Request &req,
heart_rate_monitor::analyse_heart_rate::Response &res)
{
res.result = analyse_text_file(req.filename);
return true;
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "heart_rate_analyser_server");
ros::NodeHandle n;
ros::ServiceServer service = n.advertiseService("heart_rate_analyser", analyse);
ROS_INFO("Ready to analyse requests.");
ros::spin();
return 0;
}
Service Client
#include "ros/ros.h"
#include "heart_rate_monitor/analyse_heart_rate.h"
void process_message(const std_msgs::String::ConstPtr& string_msg)
{
std::string output_filename;
do_staff_with_message();
write_data_to_file_(output_filename);
heart_rate_monitor::analyse_heart_rate srv;
srv.filename = output_filename ;
if (client.call(srv))
{
ROS_INFO("Result: %d", (bool)srv.response.result);
}
else
{
ROS_ERROR("Failed to call service heart_rate_analyser");
}
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "add_two_ints_client");
ros::NodeHandle n;
ros::ServiceClient client = n.serviceClient<heart_rate_monitor::analyse_heart_rate>("heart_rate_analyser");
ros::Subscriber sub = n.subscribe("/HeartRateInterval", 1000, process_message);
return 0;
}
This way, whenever a message comes in the node "Service Client", It will process it and eventually write it to the file. Then it asks the "Service Server" to process the file created previously...
Of course, this is just a snippet, costumize it to your needs.
Cheers.
How to make a subscriber and publisher in ROS on C++ in one file? I tried this and publisher works but subscriber callback function is not called
#include <ros/ros.h>
#include <iostream>
#include <std_msgs/UInt16.h>
#include <math.h>
int error = 0;
void error_sub(const std_msgs::UInt16::ConstPtr& msg)
{
ROS_INFO("I heard: [%d]", msg->data);
error = msg->data;
}
int main(int argc, char** argv)
{
ros::init(argc, argv, "lighter");
ros::NodeHandle nh;
ros::Publisher connected =nh.advertise<std_msgs::UInt16>("/robot/sonar/head_sonar/lights/set_lights",1);
ros::Subscriber sub = nh.subscribe("/plc/error", 1000, error_sub);
std_msgs::UInt16 msg;
while(ros::ok())
{
if(error >= 0)
{
msg.data = 36863;
connected.publish(msg);
}
ros::spinOnce();
}
}
I does not work because of the bad type of the message. It should be Int8 instead of UInt16 in callback function.