├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── cmake └── FindZeroMQ.cmake ├── package.xml ├── scripts ├── listener_zmq.py └── talker_zmq.py └── src ├── listener_zmq.cpp └── talker_zmq.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore vscode config files 2 | .vscode/ 3 | 4 | # Prerequisites 5 | *.d 6 | 7 | # Compiled Object files 8 | *.slo 9 | *.lo 10 | *.o 11 | *.obj 12 | 13 | # Precompiled Headers 14 | *.gch 15 | *.pch 16 | 17 | # Compiled Dynamic libraries 18 | *.so 19 | *.dylib 20 | *.dll 21 | 22 | # Fortran module files 23 | *.mod 24 | *.smod 25 | 26 | # Compiled Static libraries 27 | *.lai 28 | *.la 29 | *.a 30 | *.lib 31 | 32 | # Executables 33 | *.exe 34 | *.out 35 | *.app 36 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.3) 2 | project(ros_zeromq_tutorial) 3 | 4 | set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}") 5 | set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake CACHE INTERNAL "" FORCE) 6 | 7 | find_package(ZeroMQ) 8 | find_package(catkin REQUIRED COMPONENTS roscpp) 9 | 10 | catkin_package() 11 | include_directories(include ${catkin_INCLUDE_DIRS} ${ZeroMQ_INCLUDE_DIRS}) 12 | 13 | add_executable(talker_zmq src/talker_zmq.cpp) 14 | target_link_libraries(talker_zmq ${catkin_LIBRARIES} ${ZeroMQ_LIBRARIES}) 15 | 16 | add_executable(listener_zmq src/listener_zmq.cpp) 17 | target_link_libraries(listener_zmq ${catkin_LIBRARIES} ${ZeroMQ_LIBRARIES}) 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Ravi Prakash Joshi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ROS ZeroMQ Tutorial 2 | 3 | This tutorial shows how to use [ZeroMQ](http://zeromq.org) with ROS for publishing and subscribing to messages. The following two languages are supported: 4 | 5 | * CPP 6 | * Python (see [thanks](#thanks) section) 7 | 8 | 9 | ## Dependencies 10 | 1. [ZeroMQ](http://zeromq.org/): Install ZeroMQ using following command: 11 | ``` 12 | sudo apt-get install libzmq3-dev 13 | ``` 14 | _It should be easy to install newer versions of ZeroMQ, and this repository should be compatible with them. However, please note that this repository is only for demonstration purposes. Therefore, we have not tested it thoroughly. In such cases, please feel free to open a new [issue](#issue) to inform the changes to authors._ 15 | 16 | 17 | ## Compilation 18 | 1. Make sure to download complete repository. Use `git clone` or download zip as per convenience. 19 | 1. Invoke catkin tool inside ros workspace i.e., `catkin_make` 20 | 21 | 22 | ## Steps to run 23 | 1. Start ROS Core by using the following command: 24 | ``` 25 | roscore 26 | ``` 27 | 1. Invoke the publisher by using the following command: 28 | ``` 29 | rosrun ros_zeromq_tutorial talker_zmq 30 | ``` 31 | Alternatively, the python version of talker can be started by using the following command: 32 | ``` 33 | rosrun ros_zeromq_tutorial talker_zmq.py 34 | ``` 35 | 1. The published data can be seen by using the following command: 36 | ``` 37 | rosrun ros_zeromq_tutorial listener_zmq 38 | ``` 39 | Alternatively, the python version of listener can be started by using the following command: 40 | ``` 41 | rosrun ros_zeromq_tutorial listener_zmq.py 42 | ``` 43 | 44 | 45 | ## Issue 46 | Please check [here](https://github.com/ravijo/ros_zeromq_tutorial/issues) and create issues accordingly. 47 | 48 | 49 | ## Thanks 50 | The following authors are sincerely acknowledged for the improvements of this package: 51 | * [Md Rakin Sarder](https://github.com/tunchunairarko): For providing python nodes 52 | -------------------------------------------------------------------------------- /cmake/FindZeroMQ.cmake: -------------------------------------------------------------------------------- 1 | ##============================================================================= 2 | ## 3 | ## Copyright (c) Kitware, Inc. 4 | ## All rights reserved. 5 | ## See LICENSE.txt for details. 6 | ## 7 | ## This software is distributed WITHOUT ANY WARRANTY; without even 8 | ## the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 9 | ## PURPOSE. See the above copyright notice for more information. 10 | ## 11 | ##============================================================================= 12 | # - Try to find ZeroMQ headers and libraries 13 | # 14 | # Usage of this module as follows: 15 | # 16 | # find_package(ZeroMQ) 17 | # 18 | # Variables used by this module, they can change the default behaviour and need 19 | # to be set before calling find_package: 20 | # 21 | # ZeroMQ_ROOT_DIR Set this variable to the root installation of 22 | # ZeroMQ if the module has problems finding 23 | # the proper installation path. 24 | # 25 | # Variables defined by this module: 26 | # 27 | # ZeroMQ_FOUND System has ZeroMQ libs/headers 28 | # ZeroMQ_LIBRARIES The ZeroMQ libraries 29 | # ZeroMQ_INCLUDE_DIR The location of ZeroMQ headers 30 | # ZeroMQ_VERSION The version of ZeroMQ 31 | 32 | find_path(ZeroMQ_ROOT_DIR 33 | NAMES include/zmq.h 34 | ) 35 | 36 | if(MSVC) 37 | #add in all the names it can have on windows 38 | if(CMAKE_GENERATOR_TOOLSET MATCHES "v140" OR MSVC14) 39 | set(_zmq_TOOLSET "-v140") 40 | elseif(CMAKE_GENERATOR_TOOLSET MATCHES "v120" OR MSVC12) 41 | set(_zmq_TOOLSET "-v120") 42 | elseif(CMAKE_GENERATOR_TOOLSET MATCHES "v110_xp") 43 | set(_zmq_TOOLSET "-v110_xp") 44 | elseif(CMAKE_GENERATOR_TOOLSET MATCHES "v110" OR MSVC11) 45 | set(_zmq_TOOLSET "-v110") 46 | elseif(CMAKE_GENERATOR_TOOLSET MATCHES "v100" OR MSVC10) 47 | set(_zmq_TOOLSET "-v100") 48 | elseif(CMAKE_GENERATOR_TOOLSET MATCHES "v90" OR MSVC90) 49 | set(_zmq_TOOLSET "-v90") 50 | endif() 51 | 52 | set(_zmq_versions 53 | "4_1_5" "4_1_4" "4_1_3" "4_1_2" "4_1_1" "4_1_0" 54 | "4_0_8" "4_0_7" "4_0_6" "4_0_5" "4_0_4" "4_0_3" "4_0_2" "4_0_1" "4_0_0" 55 | "3_2_5" "3_2_4" "3_2_3" "3_2_2" "3_2_1" "3_2_0" "3_1_0") 56 | 57 | set(_zmq_release_names) 58 | set(_zmq_debug_names) 59 | foreach( ver ${_zmq_versions}) 60 | list(APPEND _zmq_release_names "libzmq${_zmq_TOOLSET}-mt-${ver}") 61 | endforeach() 62 | foreach( ver ${_zmq_versions}) 63 | list(APPEND _zmq_debug_names "libzmq${_zmq_TOOLSET}-mt-gd-${ver}") 64 | endforeach() 65 | 66 | #now try to find the release and debug version 67 | find_library(ZeroMQ_LIBRARY_RELEASE 68 | NAMES ${_zmq_release_names} zmq libzmq 69 | HINTS ${ZeroMQ_ROOT_DIR}/bin 70 | ${ZeroMQ_ROOT_DIR}/lib 71 | ) 72 | 73 | find_library(ZeroMQ_LIBRARY_DEBUG 74 | NAMES ${_zmq_debug_names} zmq libzmq 75 | HINTS ${ZeroMQ_ROOT_DIR}/bin 76 | ${ZeroMQ_ROOT_DIR}/lib 77 | ) 78 | 79 | if(ZeroMQ_LIBRARY_RELEASE AND ZeroMQ_LIBRARY_DEBUG) 80 | set(ZeroMQ_LIBRARY 81 | debug ${ZeroMQ_LIBRARY_DEBUG} 82 | optimized ${ZeroMQ_LIBRARY_RELEASE} 83 | ) 84 | elseif(ZeroMQ_LIBRARY_RELEASE) 85 | set(ZeroMQ_LIBRARY ${ZeroMQ_LIBRARY_RELEASE}) 86 | elseif(ZeroMQ_LIBRARY_DEBUG) 87 | set(ZeroMQ_LIBRARY ${ZeroMQ_LIBRARY_DEBUG}) 88 | endif() 89 | 90 | else() 91 | find_library(ZeroMQ_LIBRARY 92 | NAMES zmq libzmq 93 | HINTS ${ZeroMQ_ROOT_DIR}/lib 94 | ) 95 | endif() 96 | 97 | find_path(ZeroMQ_INCLUDE_DIR 98 | NAMES zmq.h 99 | HINTS ${ZeroMQ_ROOT_DIR}/include 100 | ) 101 | 102 | function(extract_version_value value_name file_name value) 103 | file(STRINGS ${file_name} val REGEX "${value_name} .") 104 | string(FIND ${val} " " last REVERSE) 105 | string(SUBSTRING ${val} ${last} -1 val) 106 | string(STRIP ${val} val) 107 | set(${value} ${val} PARENT_SCOPE) 108 | endfunction(extract_version_value) 109 | 110 | extract_version_value("ZMQ_VERSION_MAJOR" ${ZeroMQ_INCLUDE_DIR}/zmq.h MAJOR) 111 | extract_version_value("ZMQ_VERSION_MINOR" ${ZeroMQ_INCLUDE_DIR}/zmq.h MINOR) 112 | extract_version_value("ZMQ_VERSION_PATCH" ${ZeroMQ_INCLUDE_DIR}/zmq.h PATCH) 113 | 114 | set(ZeroMQ_VER "${MAJOR}.${MINOR}.${PATCH}") 115 | 116 | #We are using the 2.8.10 signature of find_package_handle_standard_args, 117 | #as that is the version that ParaView 5.1 && VTK 6/7 ship, and inject 118 | #into the CMake module path. This allows our FindModule to work with 119 | #projects that include VTK/ParaView before searching for Remus 120 | include(FindPackageHandleStandardArgs) 121 | find_package_handle_standard_args( 122 | ZeroMQ 123 | REQUIRED_VARS ZeroMQ_LIBRARY ZeroMQ_INCLUDE_DIR 124 | VERSION_VAR ZeroMQ_VER 125 | ) 126 | 127 | set(ZeroMQ_FOUND ${ZEROMQ_FOUND}) 128 | set(ZeroMQ_INCLUDE_DIRS ${ZeroMQ_INCLUDE_DIR}) 129 | set(ZeroMQ_LIBRARIES ${ZeroMQ_LIBRARY}) 130 | set(ZeroMQ_VERSION ${ZeroMQ_VER}) 131 | 132 | mark_as_advanced( 133 | ZeroMQ_ROOT_DIR 134 | ZeroMQ_LIBRARY 135 | ZeroMQ_LIBRARY_DEBUG 136 | ZeroMQ_LIBRARY_RELEASE 137 | ZeroMQ_INCLUDE_DIR 138 | ZeroMQ_VERSION 139 | ) 140 | -------------------------------------------------------------------------------- /package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | ros_zeromq_tutorial 4 | 0.0.0 5 | The ros_zeromq_tutorial package 6 | Ravi Joshi 7 | Ravi Joshi 8 | MIT 9 | catkin 10 | roscpp 11 | rospy 12 | roscpp 13 | rospy 14 | 15 | -------------------------------------------------------------------------------- /scripts/listener_zmq.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import zmq 4 | import rospy 5 | 6 | 7 | def listener(): 8 | rospy.init_node("listener_zmq", anonymous=True) 9 | 10 | context = zmq.Context() 11 | socket = context.socket(zmq.SUB) 12 | 13 | TOPIC = b"" 14 | socket.setsockopt(zmq.SUBSCRIBE, TOPIC) 15 | 16 | linger = 0 17 | socket.setsockopt(zmq.LINGER, linger) 18 | socket.connect("tcp://localhost:6666") 19 | 20 | while not rospy.is_shutdown(): 21 | string = socket.recv() 22 | # topic, messagedata = string.split() 23 | rospy.loginfo("I heard %s", string) 24 | 25 | socket.close() 26 | context.close() 27 | 28 | 29 | if __name__ == "__main__": 30 | listener() 31 | -------------------------------------------------------------------------------- /scripts/talker_zmq.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import rospy 4 | import zmq 5 | 6 | 7 | def talker(): 8 | rospy.init_node("talker_zmq", anonymous=True) 9 | rate = rospy.Rate(10) # 10hz 10 | 11 | context = zmq.Context() 12 | socket = context.socket(zmq.PUB) 13 | socket.bind("tcp://*:6666") 14 | 15 | while not rospy.is_shutdown(): 16 | msg_str = "hello_world_%s" % rospy.get_time() 17 | rospy.loginfo(msg_str) 18 | socket.send_string(msg_str) 19 | rate.sleep() 20 | 21 | 22 | if __name__ == "__main__": 23 | try: 24 | talker() 25 | except rospy.ROSInterruptException: 26 | pass 27 | -------------------------------------------------------------------------------- /src/listener_zmq.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * listener_zmq.cpp 3 | * Author: Ravi Joshi 4 | * Date: 2018/01/18 5 | */ 6 | 7 | #include 8 | 9 | #include 10 | 11 | int main(int argc, char** argv) { 12 | ros::init(argc, argv, "listener_zmq", ros::init_options::AnonymousName); 13 | 14 | zmq::context_t context(1); 15 | zmq::socket_t subscriber(context, ZMQ_SUB); 16 | 17 | std::string TOPIC = ""; 18 | subscriber.setsockopt(ZMQ_SUBSCRIBE, TOPIC.c_str(), TOPIC.length()); // allow all messages 19 | 20 | int linger = 0; // Proper shutdown ZeroMQ 21 | subscriber.setsockopt(ZMQ_LINGER, &linger, sizeof(linger)); 22 | 23 | subscriber.connect("tcp://localhost:6666"); 24 | 25 | while (ros::ok()) { 26 | zmq::message_t message; 27 | int rc = subscriber.recv(&message); 28 | if (rc) { 29 | std::string recv_string; 30 | 31 | std::istringstream iss(static_cast(message.data())); 32 | iss >> recv_string; 33 | ROS_INFO_STREAM("I heard " << recv_string); 34 | } 35 | } 36 | 37 | // Clean up your socket and context here 38 | subscriber.close(); 39 | context.close(); 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /src/talker_zmq.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * talker_zmq.cpp 3 | * Author: Ravi Joshi 4 | * Date: 2018/01/18 5 | */ 6 | 7 | #include 8 | 9 | #include 10 | 11 | int main(int argc, char** argv) { 12 | ros::init(argc, argv, "talker_zmq", ros::init_options::AnonymousName); 13 | 14 | ros::Time::init(); // Workaround since we are not using NodeHandle 15 | ros::Rate loop_rate(10); 16 | 17 | // Prepare our context and publisher 18 | zmq::context_t context(1); 19 | zmq::socket_t publisher(context, ZMQ_PUB); 20 | publisher.bind("tcp://*:6666"); 21 | 22 | while (ros::ok()) { 23 | std::stringstream msg_str_stream; 24 | msg_str_stream << "hello_world_" << ros::Time::now(); 25 | std::string msg_str = msg_str_stream.str(); 26 | 27 | zmq::message_t message(msg_str.length()); 28 | memcpy(message.data(), msg_str.c_str(), msg_str.length()); 29 | 30 | ROS_INFO_STREAM(msg_str); 31 | publisher.send(message); 32 | loop_rate.sleep(); 33 | } 34 | // Clean up your socket and context here 35 | publisher.close(); 36 | context.close(); 37 | 38 | return 0; 39 | } 40 | --------------------------------------------------------------------------------