├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── package.xml └── src ├── examples ├── chatter │ ├── CMakeLists.txt │ ├── Makefile │ ├── README.md │ └── main │ │ ├── CMakeLists.txt │ │ ├── component.mk │ │ ├── esp_chatter.cpp │ │ ├── include │ │ └── esp_chatter.h │ │ └── main.c └── echo │ ├── CMakeLists.txt │ ├── Makefile │ ├── README.md │ └── main │ ├── CMakeLists.txt │ ├── component.mk │ ├── esp_echo.cpp │ ├── include │ └── esp_echo.h │ └── main.c ├── ros_lib ├── CMakeLists.txt ├── ESP32Hardware.h ├── Kconfig ├── esp_ros_wifi.c ├── esp_ros_wifi.h └── ros.h └── rosserial_esp32 └── make_libraries.py /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | bin/ 3 | lib/ 4 | msg_gen/ 5 | srv_gen/ 6 | msg/*Action.msg 7 | msg/*ActionFeedback.msg 8 | msg/*ActionGoal.msg 9 | msg/*ActionResult.msg 10 | msg/*Feedback.msg 11 | msg/*Goal.msg 12 | msg/*Result.msg 13 | msg/_*.py 14 | 15 | # Generated by dynamic reconfigure 16 | *.cfgc 17 | /cfg/cpp/ 18 | /cfg/*.py 19 | 20 | # Ignore generated docs 21 | *.dox 22 | *.wikidoc 23 | 24 | # eclipse stuff 25 | .project 26 | .cproject 27 | 28 | # qcreator stuff 29 | CMakeLists.txt.user 30 | 31 | srv/_*.py 32 | *.pcd 33 | *.pyc 34 | qtcreator-* 35 | *.user 36 | 37 | /planning/cfg 38 | /planning/docs 39 | /planning/src 40 | 41 | *~ 42 | 43 | # Emacs 44 | .#* 45 | 46 | # Catkin custom files 47 | CATKIN_IGNORE 48 | 49 | # IDF specific files 50 | sdkconfig 51 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.3) 2 | project(rosserial_esp32) 3 | 4 | ## Compile as C++11, supported in ROS Kinetic and newer 5 | # add_compile_options(-std=c++11) 6 | 7 | ## Find catkin macros and libraries 8 | ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) 9 | ## is used, also find other catkin packages 10 | find_package(catkin REQUIRED COMPONENTS 11 | message_generation 12 | ) 13 | 14 | ## System dependencies are found with CMake's conventions 15 | # find_package(Boost REQUIRED COMPONENTS system) 16 | 17 | 18 | ## Uncomment this if the package has a setup.py. This macro ensures 19 | ## modules and global scripts declared therein get installed 20 | ## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html 21 | # catkin_python_setup() 22 | 23 | ################################################ 24 | ## Declare ROS messages, services and actions ## 25 | ################################################ 26 | 27 | ## To declare and build messages, services or actions from within this 28 | ## package, follow these steps: 29 | ## * Let MSG_DEP_SET be the set of packages whose message types you use in 30 | ## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). 31 | ## * In the file package.xml: 32 | ## * add a build_depend tag for "message_generation" 33 | ## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET 34 | ## * If MSG_DEP_SET isn't empty the following dependency has been pulled in 35 | ## but can be declared for certainty nonetheless: 36 | ## * add a exec_depend tag for "message_runtime" 37 | ## * In this file (CMakeLists.txt): 38 | ## * add "message_generation" and every package in MSG_DEP_SET to 39 | ## find_package(catkin REQUIRED COMPONENTS ...) 40 | ## * add "message_runtime" and every package in MSG_DEP_SET to 41 | ## catkin_package(CATKIN_DEPENDS ...) 42 | ## * uncomment the add_*_files sections below as needed 43 | ## and list every .msg/.srv/.action file to be processed 44 | ## * uncomment the generate_messages entry below 45 | ## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) 46 | 47 | ## Generate messages in the 'msg' folder 48 | # add_message_files( 49 | # FILES 50 | # Message1.msg 51 | # Message2.msg 52 | # ) 53 | 54 | ## Generate services in the 'srv' folder 55 | # add_service_files( 56 | # FILES 57 | # Service1.srv 58 | # Service2.srv 59 | # ) 60 | 61 | ## Generate actions in the 'action' folder 62 | # add_action_files( 63 | # FILES 64 | # Action1.action 65 | # Action2.action 66 | # ) 67 | 68 | ## Generate added messages and services with any dependencies listed here 69 | generate_messages( 70 | # DEPENDENCIES 71 | # rosserial_msgs 72 | ) 73 | 74 | ################################################ 75 | ## Declare ROS dynamic reconfigure parameters ## 76 | ################################################ 77 | 78 | ## To declare and build dynamic reconfigure parameters within this 79 | ## package, follow these steps: 80 | ## * In the file package.xml: 81 | ## * add a build_depend and a exec_depend tag for "dynamic_reconfigure" 82 | ## * In this file (CMakeLists.txt): 83 | ## * add "dynamic_reconfigure" to 84 | ## find_package(catkin REQUIRED COMPONENTS ...) 85 | ## * uncomment the "generate_dynamic_reconfigure_options" section below 86 | ## and list every .cfg file to be processed 87 | 88 | ## Generate dynamic reconfigure parameters in the 'cfg' folder 89 | # generate_dynamic_reconfigure_options( 90 | # cfg/DynReconf1.cfg 91 | # cfg/DynReconf2.cfg 92 | # ) 93 | 94 | ################################### 95 | ## catkin specific configuration ## 96 | ################################### 97 | ## The catkin_package macro generates cmake config files for your package 98 | ## Declare things to be passed to dependent projects 99 | ## INCLUDE_DIRS: uncomment this if your package contains header files 100 | ## LIBRARIES: libraries you create in this project that dependent projects also need 101 | ## CATKIN_DEPENDS: catkin_packages dependent projects also need 102 | ## DEPENDS: system dependencies of this project that dependent projects also need 103 | catkin_package( 104 | # INCLUDE_DIRS include 105 | # LIBRARIES rosserial_esp32 106 | CATKIN_DEPENDS message_runtime 107 | # DEPENDS system_lib 108 | ) 109 | 110 | ########### 111 | ## Build ## 112 | ########### 113 | 114 | ## Specify additional locations of header files 115 | ## Your package locations should be listed before other locations 116 | include_directories( 117 | # include 118 | ${catkin_INCLUDE_DIRS} 119 | ) 120 | 121 | ## Declare a C++ library 122 | # add_library(${PROJECT_NAME} 123 | # src/${PROJECT_NAME}/rosserial_esp32.cpp 124 | # ) 125 | 126 | ## Add cmake target dependencies of the library 127 | ## as an example, code may need to be generated before libraries 128 | ## either from message generation or dynamic reconfigure 129 | # add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) 130 | 131 | ## Declare a C++ executable 132 | ## With catkin_make all packages are built within a single CMake context 133 | ## The recommended prefix ensures that target names across packages don't collide 134 | # add_executable(${PROJECT_NAME}_node src/rosserial_esp32_node.cpp) 135 | 136 | ## Rename C++ executable without prefix 137 | ## The above recommended prefix causes long target names, the following renames the 138 | ## target back to the shorter version for ease of user use 139 | ## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node" 140 | # set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "") 141 | 142 | ## Add cmake target dependencies of the executable 143 | ## same as for the library above 144 | # add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) 145 | 146 | ## Specify libraries to link a library or executable target against 147 | # target_link_libraries(${PROJECT_NAME}_node 148 | # ${catkin_LIBRARIES} 149 | # ) 150 | 151 | ############# 152 | ## Install ## 153 | ############# 154 | 155 | # all install targets should use catkin DESTINATION variables 156 | # See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html 157 | 158 | ## Mark executable scripts (Python etc.) for installation 159 | ## in contrast to setup.py, you can choose the destination 160 | # install(PROGRAMS 161 | # scripts/my_python_script 162 | # DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} 163 | # ) 164 | 165 | ## Mark executables and/or libraries for installation 166 | # install(TARGETS ${PROJECT_NAME} ${PROJECT_NAME}_node 167 | # ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} 168 | # LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} 169 | # RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} 170 | # ) 171 | 172 | ## Mark cpp header files for installation 173 | # install(DIRECTORY include/${PROJECT_NAME}/ 174 | # DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} 175 | # FILES_MATCHING PATTERN "*.h" 176 | # PATTERN ".svn" EXCLUDE 177 | # ) 178 | 179 | ## Mark other files for installation (e.g. launch and bag files, etc.) 180 | install(DIRECTORY 181 | src/ros_lib 182 | # myfile2 183 | DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/src 184 | ) 185 | 186 | catkin_install_python( 187 | PROGRAMS src/${PROJECT_NAME}/make_libraries.py 188 | DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} 189 | ) 190 | 191 | ############# 192 | ## Testing ## 193 | ############# 194 | 195 | ## Add gtest based cpp test target and link libraries 196 | # catkin_add_gtest(${PROJECT_NAME}-test test/test_rosserial_esp32.cpp) 197 | # if(TARGET ${PROJECT_NAME}-test) 198 | # target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) 199 | # endif() 200 | 201 | ## Add folders to be run by python nosetests 202 | # catkin_add_nosetests(test) 203 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD License 2 | ----------- 3 | 4 | Copyright (c) 2019 Sachin Parekh 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without modification, 8 | are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, this 14 | list of conditions and the following disclaimer in the documentation and/or 15 | other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 21 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## rosserial_esp32 2 | 3 | This package is based on [rosserial](http://wiki.ros.org/rosserial) to enable communication between ROS and ESP32 using ESP-IDF. 4 | 5 | Supports rosserial communication over **UART** and **WiFi** 6 | 7 | ### Generate ROS libraries 8 | Follow the steps below in order to generate and include ROS libraries 9 | (This will create a component in IDF_PATH and need to generate it only once) 10 | 11 | ``` 12 | $ cd path/to/catkin_ws/src/ 13 | $ git clone https:/www.github.com/sachin0x18/rosserial_esp32.git 14 | $ rosrun rosserial_esp32 make_libraries.py $IDF_PATH/components/ 15 | ``` 16 | 17 | After execution of above commands, all the necessary ROS files would have been generated in `$IDF_PATH/components/rosserial_esp32/` 18 | 19 | ### Examples 20 | * [chatter](src/examples/chatter) 21 | * [echo](src/examples/echo) 22 | -------------------------------------------------------------------------------- /package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | rosserial_esp32 4 | 1.0.0 5 | rosserial_client for ESP32 on ESP-IDF 6 | 7 | 8 | 9 | 10 | Sachin Parekh 11 | 12 | 13 | 14 | 15 | 16 | BSD 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | catkin 43 | 44 | message_generation 45 | 46 | message_runtime 47 | rospy 48 | rosserial_client 49 | rosserial_msgs 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/examples/chatter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The following lines of boilerplate have to be in your project's 2 | # CMakeLists in this exact order for cmake to work correctly 3 | cmake_minimum_required(VERSION 3.5) 4 | 5 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 6 | project(chatter) 7 | -------------------------------------------------------------------------------- /src/examples/chatter/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This is a project Makefile. It is assumed the directory this Makefile resides in is a 3 | # project subdirectory. 4 | # 5 | 6 | PROJECT_NAME := chatter 7 | 8 | include $(IDF_PATH)/make/project.mk 9 | -------------------------------------------------------------------------------- /src/examples/chatter/README.md: -------------------------------------------------------------------------------- 1 | ## Chatter 2 | 3 | This code publishes data on the topic `chatter` 4 | 5 | ### Build and Flash 6 | 7 | Generate the ROS libraries prior to building this example as instructed in the [README](../../../README.md) of root directory 8 | 9 | Default mode of rosserial communication is over UART. 10 | 11 | To use WiFi: 12 | 1. Enable rosserial over WiFi 13 | 14 | `idf.py menuconfig` -> `Component config` -> `rosserial` ->`rosserial over WiFi using TCP` 15 | 16 | 2. Enter WiFi and server details 17 | 18 | ``` 19 | $ export ESPPORT=/dev/ttyUSB0 20 | $ idf.py build flash 21 | ``` 22 | 23 | On a new terminal 24 | 25 | ``` 26 | $ roscore 27 | ``` 28 | 29 | On another new terminal 30 | 31 | -- UART 32 | ``` 33 | $ rosrun rosserial_python serial_node.py _baud:=11520 34 | ``` 35 | -- WiFi 36 | ``` 37 | $ rosrun rosserial_python serial_node.py tcp 38 | ``` 39 | 40 | On another new terminal 41 | 42 | ``` 43 | $ rostopic echo chatter 44 | ``` 45 | -------------------------------------------------------------------------------- /src/examples/chatter/main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | idf_component_register(SRCS "main.c" 2 | "esp_chatter.cpp" 3 | INCLUDE_DIRS "include") 4 | -------------------------------------------------------------------------------- /src/examples/chatter/main/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # "main" pseudo-component makefile. 3 | # 4 | # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) 5 | 6 | -------------------------------------------------------------------------------- /src/examples/chatter/main/esp_chatter.cpp: -------------------------------------------------------------------------------- 1 | #include "ros.h" 2 | #include "std_msgs/String.h" 3 | #include "esp_chatter.h" 4 | 5 | ros::NodeHandle nh; 6 | 7 | std_msgs::String str_msg; 8 | ros::Publisher chatter("chatter", &str_msg); 9 | 10 | char hello[13] = "hello world!"; 11 | 12 | void rosserial_setup() 13 | { 14 | // Initialize ROS 15 | nh.initNode(); 16 | nh.advertise(chatter); 17 | } 18 | 19 | void rosserial_publish() 20 | { 21 | str_msg.data = hello; 22 | // Send the message 23 | chatter.publish(&str_msg); 24 | nh.spinOnce(); 25 | } 26 | -------------------------------------------------------------------------------- /src/examples/chatter/main/include/esp_chatter.h: -------------------------------------------------------------------------------- 1 | #ifndef ESP_CHATTER_H 2 | #define ESP_CHATTER_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | void rosserial_setup(); 9 | 10 | void rosserial_publish(); 11 | 12 | #ifdef __cplusplus 13 | } 14 | #endif 15 | 16 | #endif /* ESP_CHATTER_H */ 17 | -------------------------------------------------------------------------------- /src/examples/chatter/main/main.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | #include "esp_chatter.h" 3 | #include "freertos/FreeRTOS.h" 4 | #include "freertos/task.h" 5 | 6 | int app_main() 7 | { 8 | rosserial_setup(); 9 | while(1) { 10 | rosserial_publish(); 11 | vTaskDelay(100); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/examples/echo/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The following lines of boilerplate have to be in your project's 2 | # CMakeLists in this exact order for cmake to work correctly 3 | cmake_minimum_required(VERSION 3.5) 4 | 5 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 6 | project(echo) 7 | -------------------------------------------------------------------------------- /src/examples/echo/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This is a project Makefile. It is assumed the directory this Makefile resides in is a 3 | # project subdirectory. 4 | # 5 | 6 | PROJECT_NAME := echo 7 | 8 | include $(IDF_PATH)/make/project.mk 9 | -------------------------------------------------------------------------------- /src/examples/echo/README.md: -------------------------------------------------------------------------------- 1 | ## Echo 2 | 3 | This code subscribes to `echo` and publishes on `ack` 4 | The data received on `echo` will be published on `ack` 5 | 6 | ### Build and Flash 7 | 8 | Generate the ROS libraries prior to building this example as instructed in the [README](../../../README.md) of root directory (If done already, ignore) 9 | 10 | Default mode of rosserial communication is over UART. 11 | 12 | To use WiFi: 13 | 1. Enable rosserial over WiFi 14 | 15 | `idf.py menuconfig` -> `Component config` -> `rosserial` ->`rosserial over WiFi using TCP` 16 | 17 | 2. Enter WiFi and server details 18 | 19 | ``` 20 | $ export ESPPORT=/dev/ttyUSB0 21 | $ idf.py build flash 22 | ``` 23 | 24 | On a new terminal 25 | 26 | ``` 27 | $ roscore 28 | ``` 29 | 30 | On another new terminal 31 | 32 | -- UART 33 | ``` 34 | $ rosrun rosserial_python serial_node.py _baud:=11520 35 | ``` 36 | -- WiFi 37 | ``` 38 | $ rosrun rosserial_python serial_node.py tcp 39 | ``` 40 | 41 | On another new terminal 42 | ``` 43 | $ rostopic echo ack 44 | ``` 45 | 46 | On another new terminal 47 | ``` 48 | rostopic pub echo std_msgs/String "Hello World\!" --once 49 | ``` 50 | -------------------------------------------------------------------------------- /src/examples/echo/main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | idf_component_register(SRCS "main.c" 2 | "esp_echo.cpp" 3 | INCLUDE_DIRS "include") 4 | -------------------------------------------------------------------------------- /src/examples/echo/main/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # "main" pseudo-component makefile. 3 | # 4 | # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) 5 | 6 | -------------------------------------------------------------------------------- /src/examples/echo/main/esp_echo.cpp: -------------------------------------------------------------------------------- 1 | #include "ros.h" 2 | #include "std_msgs/String.h" 3 | #include "esp_echo.h" 4 | 5 | ros::NodeHandle nh; 6 | 7 | std_msgs::String str_msg; 8 | ros::Publisher ack("ack", &str_msg); 9 | 10 | void messageCb( const std_msgs::String& msg){ 11 | ack.publish(&msg); 12 | } 13 | 14 | ros::Subscriber echo("echo", &messageCb); 15 | 16 | void rosserial_setup() 17 | { 18 | // Initialize ROS 19 | nh.initNode(); 20 | nh.subscribe(echo); 21 | nh.advertise(ack); 22 | } 23 | 24 | void rosserial_spinonce() 25 | { 26 | nh.spinOnce(); 27 | } 28 | -------------------------------------------------------------------------------- /src/examples/echo/main/include/esp_echo.h: -------------------------------------------------------------------------------- 1 | #ifndef ESP_SUBSCRIBER_H 2 | #define ESP_SUBSCRIBER_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | void rosserial_setup(); 9 | 10 | void rosserial_spinonce(); 11 | 12 | #ifdef __cplusplus 13 | } 14 | #endif 15 | 16 | #endif /* ESP_SUBSCRIBER_H */ 17 | -------------------------------------------------------------------------------- /src/examples/echo/main/main.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | #include "esp_echo.h" 3 | #include "freertos/FreeRTOS.h" 4 | #include "freertos/task.h" 5 | 6 | int app_main() 7 | { 8 | rosserial_setup(); 9 | 10 | while(1) { 11 | rosserial_spinonce(); 12 | vTaskDelay(100); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/ros_lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set (srcs 2 | "duration.cpp" 3 | "time.cpp") 4 | 5 | if(CONFIG_ROSSERIAL_OVER_WIFI) 6 | list(APPEND srcs "esp_ros_wifi.c") 7 | endif() 8 | 9 | 10 | idf_component_register(SRCS "${srcs}" 11 | INCLUDE_DIRS "include" 12 | REQUIRES vfs nvs_flash) 13 | -------------------------------------------------------------------------------- /src/ros_lib/ESP32Hardware.h: -------------------------------------------------------------------------------- 1 | #ifndef ROS_ESP32_HARDWARE_H_ 2 | #define ROS_ESP32_HARDWARE_H_ 3 | 4 | extern "C" { 5 | #include "sdkconfig.h" 6 | #include "stdio.h" 7 | #include "esp_err.h" 8 | #include "esp_timer.h" 9 | #include 10 | #include "esp_ros_wifi.h" 11 | } 12 | 13 | #define ROS_SERVER_IP CONFIG_ROSSERVER_IP 14 | #define ROS_SERVER_PORT CONFIG_ROSSERVER_PORT 15 | 16 | #define UART_PORT UART_NUM_0 17 | #define UART_TX_PIN GPIO_NUM_1 18 | #define UART_RX_PIN GPIO_NUM_3 19 | 20 | class ESP32Hardware 21 | { 22 | protected: 23 | uint8_t rx_buf[1024]; 24 | 25 | public: 26 | ESP32Hardware() 27 | { 28 | } 29 | 30 | // Initialization code for ESP32 31 | void init() 32 | { 33 | #ifdef CONFIG_ROSSERIAL_OVER_WIFI 34 | esp_ros_wifi_init(); 35 | ros_tcp_connect(ROS_SERVER_IP, ROS_SERVER_PORT); 36 | #else 37 | uart_driver_install(UART_PORT, 1024, 1024, 0, NULL, 0); 38 | 39 | //Changing the baudrate will change the baudrate of serial monitor as well 40 | //uart_set_baudrate(UART_PORT, 57600); 41 | #endif 42 | } 43 | 44 | // read a byte from the serial port. -1 = failure 45 | int read() 46 | { 47 | int read_len; 48 | #ifdef CONFIG_ROSSERIAL_OVER_WIFI 49 | read_len = ros_tcp_read(rx_buf, 1); 50 | #else 51 | read_len = uart_read_bytes(UART_PORT, (uint8_t *)rx_buf, 1, 0); 52 | #endif 53 | if (read_len == 1) { 54 | return rx_buf[0]; 55 | } else { 56 | return -1; 57 | } 58 | } 59 | 60 | // write data to the connection to ROS 61 | void write(uint8_t* data, int length) 62 | { 63 | #ifdef CONFIG_ROSSERIAL_OVER_WIFI 64 | ros_tcp_send(data, length); 65 | #else 66 | uart_write_bytes(UART_PORT, (char*)data, (size_t)length); 67 | #endif 68 | } 69 | 70 | // returns milliseconds since start of program 71 | unsigned long time() 72 | { 73 | return esp_timer_get_time() / 1000; 74 | } 75 | }; 76 | #endif 77 | -------------------------------------------------------------------------------- /src/ros_lib/Kconfig: -------------------------------------------------------------------------------- 1 | menu "rosserial" 2 | 3 | config ROSSERIAL_OVER_WIFI 4 | bool "rosserial over WiFi using TCP" 5 | default n 6 | help 7 | Use rosserial over WiFi using TCP 8 | 9 | config ROSSERVER_AP 10 | string "WiFi SSID" 11 | default "myssid" 12 | depends on ROSSERIAL_OVER_WIFI 13 | help 14 | SSID (Access point name) of WiFi to connect 15 | 16 | config ROSSERVER_PASS 17 | string "WiFi Password" 18 | default "mypass" 19 | depends on ROSSERIAL_OVER_WIFI 20 | help 21 | Password of the WiFi 22 | 23 | config ROSSERVER_IP 24 | string "IP address of ROS server (roscore)" 25 | default "192.168.0.1" 26 | depends on ROSSERIAL_OVER_WIFI 27 | help 28 | IP address of machine which is running rosserial server 29 | 30 | config ROSSERVER_PORT 31 | int "Port number of ROS server" 32 | default 11411 33 | depends on ROSSERIAL_OVER_WIFI 34 | help 35 | Port number of rosserial server 36 | 37 | Port number is printed on terminal running rosserial_python 38 | 39 | endmenu 40 | -------------------------------------------------------------------------------- /src/ros_lib/esp_ros_wifi.c: -------------------------------------------------------------------------------- 1 | /* 2 | * WiFi initialization for setting up ROS communication over TCP sockets 3 | */ 4 | 5 | #include 6 | #include "freertos/FreeRTOS.h" 7 | #include "freertos/task.h" 8 | #include "freertos/event_groups.h" 9 | #include "esp_system.h" 10 | #include "esp_wifi.h" 11 | #include "esp_event_loop.h" 12 | #include "esp_log.h" 13 | #include "nvs_flash.h" 14 | #include "sdkconfig.h" 15 | 16 | #include "lwip/err.h" 17 | #include "lwip/sockets.h" 18 | #include "lwip/sys.h" 19 | #include 20 | 21 | #define MAXIMUM_RETRY 5 22 | 23 | #define ROS_SERVER_AP CONFIG_ROSSERVER_AP 24 | #define ROS_SERVER_PASS CONFIG_ROSSERVER_PASS 25 | 26 | static EventGroupHandle_t wifi_event_group; 27 | 28 | const int IPV4_GOTIP_BIT = BIT0; 29 | 30 | static const char *TAG = "esp-ros-wifi"; 31 | 32 | static int s_retry_num = 0; 33 | 34 | static char addr_str[128]; 35 | static int addr_family; 36 | static int ip_protocol; 37 | static int sock; 38 | 39 | static esp_err_t event_handler(void *ctx, system_event_t *event) 40 | { 41 | switch(event->event_id) { 42 | case SYSTEM_EVENT_STA_START: 43 | esp_wifi_connect(); 44 | break; 45 | case SYSTEM_EVENT_STA_GOT_IP: 46 | ESP_LOGI(TAG, "got ip:%s", 47 | ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip)); 48 | s_retry_num = 0; 49 | xEventGroupSetBits(wifi_event_group, IPV4_GOTIP_BIT); 50 | break; 51 | case SYSTEM_EVENT_STA_DISCONNECTED: 52 | { 53 | if (s_retry_num < MAXIMUM_RETRY) { 54 | esp_wifi_connect(); 55 | xEventGroupClearBits(wifi_event_group, IPV4_GOTIP_BIT); 56 | s_retry_num++; 57 | ESP_LOGI(TAG,"Retrying connection to AP"); 58 | } 59 | ESP_LOGE(TAG,"Failed to connect to AP"); 60 | break; 61 | } 62 | default: 63 | break; 64 | } 65 | return ESP_OK; 66 | } 67 | 68 | void esp_ros_wifi_init() 69 | { 70 | nvs_flash_init(); 71 | 72 | wifi_event_group = xEventGroupCreate(); 73 | 74 | tcpip_adapter_init(); 75 | ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL) ); 76 | 77 | wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); 78 | ESP_ERROR_CHECK(esp_wifi_init(&cfg)); 79 | wifi_config_t wifi_config = { 80 | .sta = { 81 | .ssid = ROS_SERVER_AP, 82 | .password = ROS_SERVER_PASS, 83 | }, 84 | }; 85 | 86 | ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); 87 | ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) ); 88 | ESP_ERROR_CHECK(esp_wifi_start()); 89 | 90 | ESP_LOGI(TAG, "Waiting for AP connection..."); 91 | xEventGroupWaitBits(wifi_event_group, IPV4_GOTIP_BIT, false, true, portMAX_DELAY); 92 | ESP_LOGI(TAG, "Connected to AP"); 93 | } 94 | 95 | void ros_tcp_connect(const char* host_ip, int port_num) 96 | { 97 | struct sockaddr_in destAddr; 98 | destAddr.sin_addr.s_addr = inet_addr(host_ip); 99 | destAddr.sin_family = AF_INET; 100 | destAddr.sin_port = htons(port_num); 101 | addr_family = AF_INET; 102 | ip_protocol = IPPROTO_IP; 103 | inet_ntoa_r(destAddr.sin_addr, addr_str, sizeof(addr_str) - 1); 104 | 105 | sock = socket(addr_family, SOCK_STREAM, ip_protocol); 106 | if (sock < 0) { 107 | ESP_LOGE(TAG, "Unable to create socket: errno %d", errno); 108 | } 109 | 110 | /* Set sock to non-blocking mode (ASYNC) 111 | * "Lost sync with device, restarting.." error occurs if socket is blocking 112 | */ 113 | fcntl(sock, F_SETFL, O_NONBLOCK); 114 | 115 | int err = connect(sock, (struct sockaddr *)&destAddr, sizeof(destAddr)); 116 | if (err != 0 && errno != 119) { 117 | ESP_LOGE(TAG, "Socket unable to connect: errno %d", errno); 118 | } 119 | ESP_LOGI(TAG, "Successfully connected"); 120 | } 121 | 122 | void ros_tcp_send(uint8_t* data, int length) 123 | { 124 | int err = send(sock, data, length, 0); 125 | if (err < 0) { 126 | ESP_LOGE(TAG, "Error occured during sending: errno %d", errno); 127 | } 128 | } 129 | 130 | int ros_tcp_read(uint8_t* buf, int length) 131 | { 132 | int len = recv(sock, buf, length, 0); 133 | if (len < 0 && errno != 11) { 134 | ESP_LOGE(TAG, "Error receiving data: errno %d", errno); 135 | return -1; 136 | } 137 | return len; 138 | } 139 | -------------------------------------------------------------------------------- /src/ros_lib/esp_ros_wifi.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void esp_ros_wifi_init(); 4 | 5 | void ros_tcp_connect(const char* host_ip, int port_num); 6 | 7 | void ros_tcp_send(uint8_t* data, int length); 8 | 9 | int ros_tcp_read(uint8_t* buf, int length); 10 | -------------------------------------------------------------------------------- /src/ros_lib/ros.h: -------------------------------------------------------------------------------- 1 | #ifndef _ROS_H_ 2 | #define _ROS_H_ 3 | 4 | #include "ros/node_handle.h" 5 | #include "ESP32Hardware.h" 6 | 7 | namespace ros 8 | { 9 | typedef NodeHandle_ NodeHandle; // default 25, 25, 512, 512 10 | } 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /src/rosserial_esp32/make_libraries.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Software License Agreement (BSD License) 4 | # 5 | # Copyright (c) 2019, Sachin Parekh 6 | # All rights reserved. 7 | # 8 | # Redistribution and use in source and binary forms, with or without 9 | # modification, are permitted provided that the following conditions 10 | # are met: 11 | # 12 | # * Redistributions of source code must retain the above copyright 13 | # notice, this list of conditions and the following disclaimer. 14 | # * Redistributions in binary form must reproduce the above 15 | # copyright notice, this list of conditions and the following 16 | # disclaimer in the documentation and/or other materials provided 17 | # with the distribution. 18 | # 19 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 22 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 23 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 24 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 25 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 29 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | # POSSIBILITY OF SUCH DAMAGE. 31 | 32 | import rospkg 33 | import rosserial_client 34 | from rosserial_client.make_library import * 35 | 36 | THIS_PACKAGE = "rosserial_esp32" 37 | 38 | __usage__ = """ 39 | make_libraries.py generates the ESP32 rosserial library files for ESP32 (ESP-IDF). 40 | It requires the location of your esp-idf/components folder. 41 | 42 | rosrun rosserial_esp32 make_libraries.py $IDF_PATH/components 43 | """ 44 | 45 | # for copying files 46 | import shutil 47 | 48 | ROS_TO_EMBEDDED_TYPES = { 49 | 'bool' : ('bool', 1, PrimitiveDataType, []), 50 | 'byte' : ('int8_t', 1, PrimitiveDataType, []), 51 | 'int8' : ('int8_t', 1, PrimitiveDataType, []), 52 | 'char' : ('char', 1, PrimitiveDataType, []), 53 | 'uint8' : ('uint8_t', 1, PrimitiveDataType, []), 54 | 'int16' : ('int16_t', 2, PrimitiveDataType, []), 55 | 'uint16' : ('uint16_t', 2, PrimitiveDataType, []), 56 | 'int32' : ('int32_t', 4, PrimitiveDataType, []), 57 | 'uint32' : ('uint32_t', 4, PrimitiveDataType, []), 58 | 'int64' : ('int64_t', 8, PrimitiveDataType, []), 59 | 'uint64' : ('uint64_t', 8, PrimitiveDataType, []), 60 | 'float32' : ('float', 4, PrimitiveDataType, []), 61 | 'float64' : ('double', 8, PrimitiveDataType, []), 62 | 'time' : ('ros::Time', 8, TimeDataType, ['ros/time']), 63 | 'duration': ('ros::Duration', 8, TimeDataType, ['ros/duration']), 64 | 'string' : ('char*', 0, StringDataType, []), 65 | 'Header' : ('std_msgs::Header', 0, MessageDataType, ['std_msgs/Header']) 66 | } 67 | 68 | # need correct inputs 69 | if (len(sys.argv) < 2): 70 | print __usage__ 71 | exit() 72 | 73 | # get output path 74 | path = sys.argv[1] 75 | 76 | if path[-1] == "/": 77 | path = path[0:-1] 78 | print "\nExporting to %s" % path 79 | 80 | rospack = rospkg.RosPack() 81 | 82 | # Create rosserial_esp32 component folder if it doesn't exists 83 | if not os.path.exists(path+"/rosserial_esp32/"): 84 | os.makedirs(path+"/rosserial_esp32/include/") 85 | with open(path+"/rosserial_esp32/component.mk", "w") as file: 86 | pass 87 | 88 | # copy ros_lib stuff in 89 | rosserial_esp32_dir = rospack.get_path(THIS_PACKAGE) 90 | files = os.listdir(rosserial_esp32_dir+"/src/ros_lib") 91 | for f in files: 92 | if os.path.isfile(rosserial_esp32_dir+"/src/ros_lib/"+f): 93 | if f.endswith(".h"): 94 | shutil.copy(rosserial_esp32_dir+"/src/ros_lib/"+f, path+"/rosserial_esp32/include/") 95 | else: 96 | shutil.copy(rosserial_esp32_dir+"/src/ros_lib/"+f, path+"/rosserial_esp32/") 97 | 98 | rosserial_client_copy_files(rospack, path+"/rosserial_esp32/include/") 99 | 100 | # generate messages 101 | rosserial_generate(rospack, path+"/rosserial_esp32/include/", ROS_TO_EMBEDDED_TYPES) 102 | 103 | # Move source files to parent directory 104 | src_files = os.listdir(path+"/rosserial_esp32/include/") 105 | for f in src_files: 106 | if f.endswith(".cpp"): 107 | shutil.move(path+"/rosserial_esp32/include/"+f, path+"/rosserial_esp32/") 108 | --------------------------------------------------------------------------------