ROS communication programming in Ubuntu 16.04

Keywords: Ubuntu server slam

Basic knowledge learning

🌟 The difference between topic and service

-topic of conversationservice
Synchronizationasynchronoussynchronization
communication model Publish / subscribeServer / client
Underlying protocolROSTCP/ROSUDPROSTCP/ROSUDP
feedback mechanismnothinghave
bufferhavenothing
Real timeweakstrong
Node relationshipMany to manyOne to many
Applicable scenariodata transmissionLogical processing

Field ROS communication demo

1, Create a workspace

  1. Create a workspace named ros
mkdir -p ~/ros/src
  1. Enter the src folder where the workspace was created
cd ~/ros/src
  1. Generate workspace
catkin_init_workspace
  1. At this time, the workspace is empty and can be compiled
//Enter the workspace
cd ~/ros/
//compile
catkin_make
  1. Register the workspace in bash
//bash registration
source devel/setup.bash
//verification
echo $ROS_PACKAGE_PATH
//If you can see the file path of your workspace, it indicates that the workspace is created successfully

2, Create a ROS project package

  1. Switch to our workspace
cd ~/ros/src
  1. Using catkin_ create_ The PKG command creates a package called comm (Communication), which relies on std_msgs,roscpp,rospy
catkin_create_pkg comm std_msgs rospy roscpp
  1. Compile the project package in the workspace
//Enter the workspace
cd ~/ros/
//compile
catkin_make

3, Create transmitting and receiving nodes for communication

  1. Switch the directory to our comm project package
cd ~/ros/src/comm
  1. Enter src subdirectory
cd src
  1. Create a talker.cpp file in the src directory and write a Publisher node
touch talker.cpp

Open talker.cpp and replace the contents with the following:

#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
int main(int argc, char **argv)
{
  ros::init(argc, argv, "talker");
  ros::NodeHandle n;
  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
  ros::Rate loop_rate(10);
  int count = 0;
  while (ros::ok())
  {
    std_msgs::String msg;
    std::stringstream ss;
    ss << "hello world " << count;
    msg.data = ss.str();
    ROS_INFO("%s", msg.data.c_str());
    chatter_pub.publish(msg);
    ros::spinOnce();
    loop_rate.sleep();
    ++count;
  }
  return 0;
}
  1. Create a listener.cpp file in the src directory and write a Subscriber node
touch listener.cpp
#include "ros/ros.h"
#include "std_msgs/String.h"
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
  ROS_INFO("I heard: [%s]", msg->data.c_str());
}
int main(int argc, char **argv)
{
  ros::init(argc, argv, "listener");
  ros::NodeHandle n;
  ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
  ros::spin();
  return 0;
}
  1. Edit the Cmakelist.txt file (Note: it is the CMakelist file under the comm project package)
//Add the following code at the end of the file
include_directories(include ${catkin_INCLUDE_DIRS})
add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
add_dependencies(talker comm_generate_messages_cpp)
add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
add_dependencies(listener comm_generate_messages_cpp)

Note: there should be no interval between the above adjacent codes, that is, do not leave a blank line. Be sure to be adjacent to each other, otherwise an error will be reported when compiling later
6. Switch the directory to the workspace directory and execute catkin_make run command

//Enter the workspace
cd ~/ros/
//compile
catkin_make

4, Correctness of test procedure

  1. Open a new terminal and start the ROS core program roscore
roscore
  1. Before starting to run our program, register the program at the original terminal
//Switch to workspace
cd ~/ros
//Program registration
source ./devel/setup.bash
  1. Running the talker node
rosrun comm talker
  1. Create a new terminal and run the listener node
//Back to the workspace
cd ~/ros
//Program registration
source ./devel/setup.bash
//Run the listener node
rosrun comm listener

Seeing the publish and subscribe of the two terminals proves successful!

Image ROS communication demo

The steps for creating a workspace are the same as for field communication

  1. image_publisher.cpp
#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <opencv2/highgui/highgui.hpp>
#include <cv_bridge/cv_bridge.h>
 
int main(int argc, char** argv)
{
  ros::init(argc, argv, "image_publisher");
  ros::NodeHandle nh;
  image_transport::ImageTransport it(nh);
  image_transport::Publisher pub = it.advertise("camera/image", 1);
 
  cv::Mat image = cv::imread(argv[1], CV_LOAD_IMAGE_COLOR);
  sensor_msgs::ImagePtr msg = cv_bridge::CvImage(std_msgs::Header(), "bgr8", image).toImageMsg();
 
  ros::Rate loop_rate(5);
  while (nh.ok()) {
    pub.publish(msg);
    ros::spinOnce();
    loop_rate.sleep();
  }
}
  1. image_subscrber.cpp
#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <opencv2/highgui/highgui.hpp>
#include <cv_bridge/cv_bridge.h>
 
void imageCallback(const sensor_msgs::ImageConstPtr& msg)
{
  try
  {
    cv::imshow("view", cv_bridge::toCvShare(msg, "bgr8")->image);
  }
  catch (cv_bridge::Exception& e)
  {
    ROS_ERROR("Could not convert from '%s' to 'bgr8'.", msg->encoding.c_str());
  }
}
 
int main(int argc, char **argv)
{
  ros::init(argc, argv, "image_listener");
  ros::NodeHandle nh;
  cv::namedWindow("view");
  cv::startWindowThread();
  image_transport::ImageTransport it(nh);
  image_transport::Subscriber sub = it.subscribe("camera/image", 1, imageCallback);
  ros::spin();
  cv::destroyWindow("view");
}
  1. package.xml
<?xml version="1.0"?>
<package format="2">
  <name>ros_cv_image</name>
  <version>0.0.0</version>
  <description>The ros_cv_image package</description>
  <buildtool_depend>catkin</buildtool_depend>
  <build_depend>cv_bridge</build_depend>
  <build_depend>image_transport</build_depend>
  <build_depend>roscpp</build_depend>
  <build_depend>rospy</build_depend>
  <build_depend>std_msgs</build_depend>
  <build_depend>opencv2</build_depend>
 
  <build_export_depend>cv_bridge</build_export_depend>
  <build_export_depend>image_transport</build_export_depend>
  <build_export_depend>roscpp</build_export_depend>
  <build_export_depend>rospy</build_export_depend>
  <build_export_depend>std_msgs</build_export_depend>
  <build_export_depend>opencv2</build_export_depend> 
 
  <exec_depend>cv_bridge</exec_depend>
  <exec_depend>image_transport</exec_depend>
  <exec_depend>roscpp</exec_depend>
  <exec_depend>rospy</exec_depend>
  <exec_depend>std_msgs</exec_depend>
  <exec_depend>opencv2</exec_depend>
 
  <!-- The export tag contains other, unspecified, tags -->
  <export>
  </export>
</package>
  1. CMakeList.xml
cmake_minimum_required(VERSION 2.8.3)
project(ros_cv_image)
 
find_package(catkin REQUIRED COMPONENTS
  cv_bridge
  image_transport
  roscpp
  rospy
  std_msgs
)
#Add this sentence
find_package(OpenCV REQUIRED)
 
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES ros_cv_image
#  CATKIN_DEPENDS cv_bridge image_transport roscpp rospy std_msgs
#  DEPENDS system_lib
)
 
#Add ${OpenCV_INCLUDE_DIRS}
include_directories(
 ./include
  ${catkin_INCLUDE_DIRS}
  ${OpenCV_INCLUDE_DIRS}
)
 
## Add cmake target dependencies of the library
## as an example, code may need to be generated before libraries
## either from message generation or dynamic reconfigure
# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
 
 
## Add cmake target dependencies of the executable
## same as for the library above
# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
 
 
## Add folders to be run by python nosetests
# catkin_add_nosetests(test)
 
add_executable(image_publisher src/image_publisher)
target_link_libraries(image_publisher ${catkin_LIBRARIES} ${OpenCV_LIBRARIES})
 
add_executable(image_subscriber src/image_subscriber)
target_link_libraries(image_subscriber ${catkin_LIBRARIES} ${OpenCV_LIBRARIES})

⚠️ During running publisher, you need to add a parameter: rosrun comm publisher xxx.jpg

Video ROS communication demo

The steps for creating a workspace are the same as for field communication

  1. imagepub.cpp
#include<ros/ros.h>
#include<cv_bridge/cv_bridge.h>
#include<sensor_msgs/image_encodings.h>
#include<image_transport/image_transport.h>

#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>

#include<stdio.h>

using namespace cv;
using namespace std;

int main(int argc, char** argv)
{
    // ROS node initialization
    ros::init(argc, argv, "image_publisher");
    ros::NodeHandle n; 
    ros::Time time = ros::Time::now();
    ros::Rate loop_rate(5);
    
     // Define node handle   
    image_transport::ImageTransport it(n);
    image_transport::Publisher pub = it.advertise("video_image", 1);
    sensor_msgs::ImagePtr msg;
        
    // opencv ready to read video
    cv::VideoCapture video;
    video.open("/home/vlt/Pictures/1.mp4");  

    if( !video.isOpened() )
    {
        ROS_INFO("Read Video failed!\n");
        return 0;
    }
    Mat frame;
    int count = 0;
    while(1)
    {
        video >> frame;
        if( frame.empty() )
            break;
        count++;
        
        msg = cv_bridge::CvImage(std_msgs::Header(), "bgr8", frame).toImageMsg();
        pub.publish(msg);
        
        ROS_INFO( "read the %dth frame successfully!", count );
        loop_rate.sleep();
        ros::spinOnce();
    }
    video.release();
    
    return 0;
}
  1. imagesub.cpp
#include<ros/ros.h>
#include<cv_bridge/cv_bridge.h>
#include<sensor_msgs/image_encodings.h>
#include<image_transport/image_transport.h>

#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>

#include<stdio.h>
#include<math.h>
#include<vector>

void imageCalllback(const sensor_msgs::ImageConstPtr& msg)
{
	ROS_INFO("Received \n");
	try{
        cv::imshow( "video", cv_bridge::toCvShare(msg, "bgr8")->image );
        cv::waitKey(30);
    }
    catch( cv_bridge::Exception& e )
    {
        ROS_ERROR( "Could not convert from '%s' to 'bgr8'.", msg->encoding.c_str() );
    }
}

int main(int argc, char** argv)
{
	ros::init(argc, argv, "image_listener");
	ros::NodeHandle n;
    cv::namedWindow("video");
    cv::startWindowThread();

    image_transport::ImageTransport it(n);
    image_transport::Subscriber sub = it.subscribe( "video_image", 1, imageCalllback );

	
	ros::spin();
    cv::destroyWindow("video");
	return 0;
}
  1. package.xml
<?xml version="1.0"?>
<package format="2">
  <name>ros_cv_image</name>
  <version>0.0.0</version>
  <description>The ros_cv_image package</description>
  <buildtool_depend>catkin</buildtool_depend>
  <build_depend>cv_bridge</build_depend>
  <build_depend>image_transport</build_depend>
  <build_depend>roscpp</build_depend>
  <build_depend>rospy</build_depend>
  <build_depend>sensor_msgs</build_depend>
  <build_depend>std_msgs</build_depend>
  <build_depend>opencv2</build_depend>
 
  <build_export_depend>cv_bridge</build_export_depend>
  <build_export_depend>image_transport</build_export_depend>
  <build_export_depend>roscpp</build_export_depend>
  <build_export_depend>rospy</build_export_depend>
  <build_export_depend>sensor_msgs</build_export_depend>
  <build_export_depend>std_msgs</build_export_depend>
  <build_export_depend>opencv2</build_export_depend> 
 
  <exec_depend>cv_bridge</exec_depend>
  <exec_depend>image_transport</exec_depend>
  <exec_depend>roscpp</exec_depend>
  <exec_depend>rospy</exec_depend>
  <exec_depend>std_msgs</exec_depend>
  <exec_depend>opencv2</exec_depend>
 
  <!-- The export tag contains other, unspecified, tags -->
  <export>
  </export>
</package>
  1. CMakeList.xml
cmake_minimum_required(VERSION 2.8.3)
project(ros_cv_image)
 
find_package(catkin REQUIRED COMPONENTS
  cv_bridge
  image_transport
  roscpp
  rospy
  sensor_msgs
  std_msgs
)
#Add this sentence
find_package(OpenCV REQUIRED)
 
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES ros_cv_image
#  CATKIN_DEPENDS cv_bridge image_transport roscpp rospy std_msgs
#  DEPENDS system_lib
)
 
#Add ${OpenCV_INCLUDE_DIRS}
include_directories(
 ./include
  ${catkin_INCLUDE_DIRS}
  ${OpenCV_INCLUDE_DIRS}
)
 
## Add cmake target dependencies of the library
## as an example, code may need to be generated before libraries
## either from message generation or dynamic reconfigure
# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
 
 
## Add cmake target dependencies of the executable
## same as for the library above
# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
 
 
## Add folders to be run by python nosetests
# catkin_add_nosetests(test)
add_executable(imagepub src/imagepub.cpp)
target_link_libraries(imagepub ${catkin_LIBRARIES} ${OpenCV_LIBRARIES})
add_executable(imagesub src/imagesub.cpp)
target_link_libraries(imagesub ${catkin_LIBRARIES} ${OpenCV_LIBRARIES})

Multi machine ROS communication

Configure ip and hostname

sudo gedit /etc/hosts
//Add the ip and hostname between the two hosts to be communicated, for example:
192.168.3.172	hero2
192.168.3.203	ivip-To-be-filled-by-O-E-M

Two or more hosts need to add ip and hostname

Reference link:
[1] ROS learning [2] - ROS communication programming (topic programming) in Ubuntu 16.04 link.
[2] ROS write, subscribe and publish pictures link.
[3] Subscribe and publish image messages in videos in ROS link.
[4] ROS official tutorial: link.

Posted by Lv-Kris on Sat, 23 Oct 2021 02:04:06 -0700