Subscribe to custom message

For future readers, if you want to know how to use a custom message with the CORE2 go to this answer:

Hello,

So I made a custom message on one CORE2-ROS which publishes that message to a topic. I want to subscribe to that topic on another CORE2-ROS. I have bot CORE2-ROS connected to the same ROS master. How can one CORE2 subscribe to a topic from another CORE2-ROS which has custom messages?

Kind regards,
Mike

Hi M11,

If both your CORE2-ROS are connected to the same ROS master you just need to write this subscriber for second CORE2-ROS and run on first device:

/opt/husarion/tools/rpi-linux/ros-core2-client /dev/ttyCORE2

on second device, run:

/opt/husarion/tools/rpi-linux/ros-core2-client /dev/ttyCORE2 __name:=serial_node1

It should work perfectly fine. Please lat me know the results.

Best regards,
Hubert Zwiercan

Hi Hubert,

I am talking about subscribing to a custom message on a topic from the CORE2 which I programmed in the cloud. The connection is fine.

Hi M11,

That’s what I’m talking about, but I don’t know what’s the problem?

Best regards,
Hubert Zwiercan

I can’t compile the code.

I need to subscribe to the topic /VehicleControl, doing that I have to tell the CORE2 what message type will be sent over the topic:

void initVehicleControlSubscriber() {
    ros::Subscriber<msg::VehicleControl> *vehicle_control_sub = new ros::Subscriber<msg::VehicleControl>("/VehicleControl", &vehicleControlCallback);
    nh.subscribe(*vehicle_control_sub);
}

I created a new header file in the cloud named VehicleControl.h and added the same stuff in there as the custom message which was defined on the other CORE2-ROS, so the code on the CORE2 know what message it is expecting to receive. But that doesn’t work.

I just don’t know how to subscribe to a topic with custom messages from the CORE2 (cloud)

Also, how can I define a custom message in the cloud for the CORE2 to use. And use that message to publish over a topic?

Hi Mike,

Please send us errors that you get during compilation, main.cpp file and file where you define VehicleControl.

Best regards,
Hubert Zwiercan

Hi Hubert,

Here is the main.cpp file:

#include "hFramework.h"
#include "hCloudClient.h"
#include "ros.h"
#include "VehicleControl.h"

#include <stdio.h>


using namespace hFramework;


ros::NodeHandle nh;

int publish_counter = 0;

void vehicleControlCallback(const &msg) {
   
}

void initVehicleControlSubscriber() {
    ros::Subscriber vehicle_control_sub = nh.subscribe("/VehicleControl",vehicleControlCallback);
}


void hMain() {
    /* Initializes communication with the Raspberry Pi */
    RPi.init(500000);
    platform.begin(&RPi);
    nh.getHardware()->initWithDevice(&platform.LocalSerial);
    nh.initNode();
	
	uint32_t t = sys.getRefTime();
	sys.setLogDev(&Serial);
	
	/* INIT PUBLISHERS */
	
	/* INIT SUBSCRIBERS */
	initVehicleControlSubscriber();

	/* CREATE TASKS */

	while(true)	{
		nh.spinOnce();
		publish_counter++;
		if (publish_counter > 10) {
		    /* Execute simple code here, but rather in their specific tasks */
		    
		    
			publish_counter = 0;
		}

		sys.delaySync(t, 10);
	}
}

This is on one of the CORE2.

(I put the error code in here, but it was totally not relevant so I deleted it for future readers of this topic, to prevent confusion)

I honestly don’t know:

  • How can I create a custom message on the CORE2, so a node on the Raspberry Pi 3 of the same CORE2-ROS for example can read that?
  • How can the CORE2 read the message of a topic on the Raspberry Pi 3 of the same CORE2-ROS?

Hi Mike,

First thing is you didn’t include VehicleControl.h in your main.cpp.

Please send me also VehicleControl.h.

Best regards,
Hubert Zwiercan

Hi Hubert,

I deleted that since I didn’t think that would be useful anymore.

It looked like this:

// VehicleControl.msg
string Direction
int32 Distance
string Unit

But I don’t think this gives you useful information.

Maybe I should ask the question in a different way:

  • Is it possible to create a custom message in the cloud for the CORE2, to be used to publish to a topic, to be subscribed to from a different node in the same ROS network?

Also the main file I just provided you is different than the one which should work with VehicleControl. But I’m really curious about the answer of the above question. Sorry for the unclear explanation.

Hello Mike,

It is possible to create custom message to exchange data between CORE2 and other ROS nodes.

I will explain it based on package created for this post, we will name this package custom_pkg.

First part is to build node for SBC side:

Begin with creating the package:

cd ~ros_workspace/src
catkin_create_pkg custom_pkg roscpp std_msgs

Then open CMakeLists.txt and edit it as below:

cmake_minimum_required(VERSION 2.8.3)
project(custom_pkg)

add_compile_options(-std=c++11)

find_package(catkin REQUIRED COMPONENTS
  message_generation
  roscpp
  std_msgs
)

add_message_files(
  FILES
  VehicleControl.msg
)

generate_messages(
  DEPENDENCIES
  std_msgs
)

catkin_package(
 CATKIN_DEPENDS
)

include_directories(
include
  ${catkin_INCLUDE_DIRS}
)

add_executable(${PROJECT_NAME}_node src/custom_pkg_node.cpp)
add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

target_link_libraries(${PROJECT_NAME}_node
  ${catkin_LIBRARIES}
)

In package directory create msg folder and message file. Name it VehicleControl.msg and paste contents:

Header header
std_msgs/String Direction
std_msgs/UInt32 Distance
std_msgs/String Unit    

You can use message as any other ROS message:

#include "ros/ros.h"
#include <custom_pkg/VehicleControl.h>

custom_pkg::VehicleControl vehicleControl;

int main(int argc, char **argv)
{
    ros::init(argc, argv, "custom_node");
    ros::NodeHandle n;

    ros::Publisher vehicle_pub = n.advertise<custom_pkg::VehicleControl>("vehicle_control", 1);
    ros::Rate loop_rate(10);

    vehicleControl.header.frame_id = "base_link";
    vehicleControl.Direction.data = "forward";
    vehicleControl.Distance.data = 1;
    vehicleControl.Unit.data = "m";
    while (ros::ok())
    {
        vehicle_pub.publish(vehicleControl);
        ros::spinOnce();
        loop_rate.sleep();
    }
    return 0;
}

Please note that we created only VehicleControl.msg file, while we are including custom_pkg/VehicleControl.h. Corresponding header file for message will be created during catkin_make.

Build it and you will get a ROS node that publishes your custom message.

Second part will be building message for CORE2 side:

For communication between CORE2 and other ROS components we are using rosserial. Header files for rosserial are suited for controllers like STM32 boards or Arduino.

We can generate headers for rosserial, it must be done on SBC side, make sure that message is defined properly:

rosmsg show custom_pkg/VehicleControl

You should get output like below:

std_msgs/Header header
  uint32 seq
  time stamp
  string frame_id
std_msgs/String Direction
  string data
std_msgs/UInt32 Distance
  uint32 data
std_msgs/String Unit
  string data

We can generate rosserial headers:

cd ~/ros_worskpace
mkdir rosserial_lib
rosrun rosserial_client make_libraries rosserial_lib/

This will generate headers for all messages in system. Our file will be in ~/ros_worskpace/rosserial_lib/ros_lib/custom_pkg/. Copy file VehicleControl.h from that directory to cloud IDE.

VeicleControl message may be used as any other ROS message:

#include "hFramework.h"
#include "hCloudClient.h"
#include "ros.h"
#include "VehicleControl.h"

using namespace hFramework;

ros::NodeHandle nh;

void controlCallback(const custom_pkg::VehicleControl &control)
{
    int new_speed = control.Distance.data;
    if(new_speed == 1){
        LED2.toggle();
    }
}

void hMain()
{
	RPi.init(500000);
	platform.begin(&RPi);
	nh.getHardware()->initWithDevice(&platform.LocalSerial);
	nh.initNode();
	ros::Subscriber<custom_pkg::VehicleControl> *control_sub = new ros::Subscriber<custom_pkg::VehicleControl>("/vehicle_control", &controlCallback);
	nh.subscribe(*control_sub);
	while (true)
	{
	    LED1.toggle();
		nh.spinOnce();
		sys.delay(10);
	}
}

In separate terminal windows start:

  • roscore
  • /opt/husarion/tools/rpi-linux/ros-core2-client /dev/ttyCORE2
  • rosrun custom_pkg custom_pkg_node

LED2 on ROSbot back panel will blink with every message received.

Regards,
Łukasz

Hey Lukasz,

Really appreciate the effort!

I have done step 1 correct already, step 2 is new for me. I am getting stuck at:

rosrun rosserial_client make_libraries rosserial_lib/

It doesn’t find rosserial_client, I only have rosserial_msgs and rosserial_python.

Then you need to install this pakage:

sudo apt install ros-kinetic-rosserial-client

Regards,
Łukasz

1 Like

Excellent, that worked!

You have saved me a ton of time trying to figure that out. Sorry if I have asked stupid/confusing questions.

Regards,
Mike

By the way, what’s the reason to use std_msgs/UInt32 Distance instead of just uint32_t Distance in the VehicleControl message?

Data types are based on one of your previous posts.
Consider it as an example, there is no need to use these exact types.
Modify it to your requirements.

Regards,
Łukasz

Hi Łukasz

Could you add this example to the tutorials. I think it is also interesting for others (like me :wink:)

Thanks for your great work!

Michael

Hi Michael,

It is a good idea. I will add it soon.

Regards,
Łukasz

I am now getting more errors whenever I am trying to connect the CORE2 to the roscore on a different PC, did you guys experience this as well?

husarion@husarion:~/Desktop$ /opt/husarion/tools/rpi-linux/ros-core2-client /dev/ttyCORE2 
[INFO] [1558619508.844366]: ROS Serial Python Node
[INFO] [1558619508.883777]: Connecting to /dev/ttyCORE2 at 500000 baud
[ERROR] [1558619511.020978]: Creation of publisher failed: 'module' object has no attribute 'Feedback'
[ERROR] [1558619511.146625]: Creation of subscriber failed: ARVI_GUI
ROS path [0]=/opt/ros/kinetic/share/ros
ROS path [1]=/home/husarion/ros-workspace/src
ROS path [2]=/opt/ros/kinetic/share

I set up the master and local address right.

Does this have to do with that my colleague who created the custom message of that subscriber did not use std_msgs/ before every attribute of the message?

I have generated the necessary header files.

Hi Mike,

All devices in ROS system must have exactly the same definitions for messages.

Regards,
Łukasz