ROS 进阶学习笔记(12) - Communication with ROS through USART Serial Port
Communication with ROS through USART Serial Port
We always need to communicate with ROS through serial port as we have many devices like sensors, touch-screen, actuators to be controlled through USART serial protocol.
After some investigation, I found several ways that can make ROS work with the serial-port-devices:
- Use the package: rosserial. It seems like only the "connected rosserial-enabled device" can work upon that, including Aduino, Windows, XBee, etc.(ROS
community said: rosserial is used with mcus that have rosserial code running on them.) - Use the driver package: serial. It seems like a serial port driver for ROS programming. This should be the most free way but I didn't find out how to use it.
- Use the package: cereal_port, a serial port library for ROS, you can find it in theserial_communication stack, it's easy to use.
- The package:rosbridgemay also suit your needs (full disclosure, author of rosbridge here). Check outthis
video of using rosbridge with an Arduino (though the principles apply to any uController). - A simple approach is to write a ROS node that can read/write text messages exchanged with the microcontroller over a serial port and convert these serial messages to ROS style std_msgs/String messages.Here we are going to share this way first.
- Kevin: a service given by Kevin. It seems to work pretty good. This works well cuz a lot of our serial stuff is sending a message and receiving a response back, instead of separate publish/subscribes.reference
web
A simple approach is to write a ROS node that can read/write text messages exchanged with the microcontroller over a serial port and convert these serial messages to ROS style std_msgs/String messages. Here we are going to share this way first. ref:reference
web
In that page, Bart says:
"A simple approach is to write a ROS node that can read/write text messages exchanged with the microcontroller over a serial port and convert these serial messages to ROS style std_msgs/String messages. A separate ROS node can then be written to convert
the simple text messages to specific ROS message formats (cmd_vel, odom, etc) based on whatever message protocol was defined for the exchange with the microcontroller.
Attached below is the source for code that I used for this purpose. There is nothing original in the code, but it may be helpful to someone new to ROS and Unix/Linux serial communication. Posting this type of a listing may be a bit unconventional
for this site as short answers are generally preferred. Hopefully no one is offended. I would be interested in hearing if there are other successful approaches to the problem."
Let's implement this approach:
Enter the catkin workspace, build the package: (tutorial page)
$ cd ~/catkin_ws/src
$ catkin_create_pkg r2serial_driver std_msgs rospy roscpp
$ cd ~/catkin_ws
$ catkin_make
To add the workspace to your ROS environment you need to source the generated setup file:
$ . ~/catkin_ws/devel/setup.bash
$ cd ~/catkin_ws/src/r2serial_driver/src
Add a file: "r2serial.cpp", Source code:
/*
* Copyright (c) 2010, Willow Garage, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the Willow Garage, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/ //r2serial.cpp // communicate via RS232 serial with a remote uController.
// communicate with ROS using String type messages.
// subscribe to command messages from ROS
// publish command responses to ROS // program parameters - ucontroller# (0,1), serial port, baud rate //Thread main
// Subscribe to ROS String messages and send as commands to uController
//Thread receive
// Wait for responses from uController and publish as a ROS messages #include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h> #define DEFAULT_BAUDRATE 19200
#define DEFAULT_SERIALPORT "/dev/ttyUSB0" //Global data
FILE *fpSerial = NULL; //serial port file pointer
ros::Publisher ucResponseMsg;
ros::Subscriber ucCommandMsg;
int ucIndex; //ucontroller index number //Initialize serial port, return file descriptor
FILE *serialInit(char * port, int baud)
{
int BAUD = 0;
int fd = -1;
struct termios newtio;
FILE *fp = NULL; //Open the serial port as a file descriptor for low level configuration
// read/write, not controlling terminal for process,
fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY );
if ( fd<0 )
{
ROS_ERROR("serialInit: Could not open serial device %s",port);
return fp;
} // set up new settings
memset(&newtio, 0,sizeof(newtio));
newtio.c_cflag = CS8 | CLOCAL | CREAD; //no parity, 1 stop bit newtio.c_iflag = IGNCR; //ignore CR, other options off
newtio.c_iflag |= IGNBRK; //ignore break condition newtio.c_oflag = 0; //all options off newtio.c_lflag = ICANON; //process input as lines // activate new settings
tcflush(fd, TCIFLUSH);
//Look up appropriate baud rate constant
switch (baud)
{
case 38400:
default:
BAUD = B38400;
break;
case 19200:
BAUD = B19200;
break;
case 9600:
BAUD = B9600;
break;
case 4800:
BAUD = B4800;
break;
case 2400:
BAUD = B2400;
break;
case 1800:
BAUD = B1800;
break;
case 1200:
BAUD = B1200;
break;
} //end of switch baud_rate
if (cfsetispeed(&newtio, BAUD) < 0 || cfsetospeed(&newtio, BAUD) < 0)
{
ROS_ERROR("serialInit: Failed to set serial baud rate: %d", baud);
close(fd);
return NULL;
}
tcsetattr(fd, TCSANOW, &newtio);
tcflush(fd, TCIOFLUSH); //Open file as a standard I/O stream
fp = fdopen(fd, "r+");
if (!fp) {
ROS_ERROR("serialInit: Failed to open serial stream %s", port);
fp = NULL;
}
return fp;
} //serialInit //Process ROS command message, send to uController
void ucCommandCallback(const std_msgs::String::ConstPtr& msg)
{
ROS_DEBUG("uc%dCommand: %s", ucIndex, msg->data.c_str());
fprintf(fpSerial, "%s", msg->data.c_str()); //appends newline
} //ucCommandCallback //Receive command responses from robot uController
//and publish as a ROS message
void *rcvThread(void *arg)
{
int rcvBufSize = 200;
char ucResponse[rcvBufSize]; //response string from uController
char *bufPos;
std_msgs::String msg;
std::stringstream ss; ROS_INFO("rcvThread: receive thread running"); while (ros::ok()) {
bufPos = fgets(ucResponse, rcvBufSize, fpSerial);
if (bufPos != NULL) {
ROS_DEBUG("uc%dResponse: %s", ucIndex, ucResponse);
msg.data = ucResponse;
ucResponseMsg.publish(msg);
}
}
return NULL;
} //rcvThread int main(int argc, char **argv)
{
char port[20]; //port name
int baud; //baud rate char topicSubscribe[20];
char topicPublish[20]; pthread_t rcvThrID; //receive thread ID
int err; //Initialize ROS
ros::init(argc, argv, "r2serial_driver");
ros::NodeHandle rosNode;
ROS_INFO("r2serial_driver starting"); //Open and initialize the serial port to the uController
if (argc > 1) {
if(sscanf(argv[1],"%d", &ucIndex)==1) {
sprintf(topicSubscribe, "uc%dCommand",ucIndex);
sprintf(topicPublish, "uc%dResponse",ucIndex);
}
else {
ROS_ERROR("ucontroller index parameter invalid");
return 1;
}
}
else {
strcpy(topicSubscribe, "uc0Command");
strcpy(topicPublish, "uc0Response");
} strcpy(port, DEFAULT_SERIALPORT);
if (argc > 2)
strcpy(port, argv[2]); baud = DEFAULT_BAUDRATE;
if (argc > 3) {
if(sscanf(argv[3],"%d", &baud)!=1) {
ROS_ERROR("ucontroller baud rate parameter invalid");
return 1;
}
} ROS_INFO("connection initializing (%s) at %d baud", port, baud);
fpSerial = serialInit(port, baud);
if (!fpSerial )
{
ROS_ERROR("unable to create a new serial port");
return 1;
}
ROS_INFO("serial connection successful"); //Subscribe to ROS messages
ucCommandMsg = rosNode.subscribe(topicSubscribe, 100, ucCommandCallback); //Setup to publish ROS messages
ucResponseMsg = rosNode.advertise<std_msgs::String>(topicPublish, 100); //Create receive thread
err = pthread_create(&rcvThrID, NULL, rcvThread, NULL);
if (err != 0) {
ROS_ERROR("unable to create receive thread");
return 1;
} //Process ROS messages and send serial commands to uController
ros::spin(); fclose(fpSerial);
ROS_INFO("r2Serial stopping");
return 0;
}
Modify the CMakeList.txt file:
$ cd ~/catkin_ws/src/r2serial_driver
$ gedit CMakeList.txt
add/modify these lines as below:
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
) include_directories(
${catkin_INCLUDE_DIRS}
) add_executable(r2serial_driver src/r2serial.cpp) add_dependencies(r2serial_driver ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) target_link_libraries(r2serial_driver
${catkin_LIBRARIES}
)
Save and Build the package again:
$ cd ~/catkin_ws
$ catkin_make -DCMAKE_BUILD_TYPE=Release
He also offered a simple launch file that interfaces to two microcontrollers using two serial connections, put the code into
"~/catkin_ws/src/r2serial_driver/launch/r2serial_driver.launch" file:
<launch>
<node pkg="r2serial_driver" type="r2serial_driver" name="r2serial0" args="0 /dev/ttyUSB0 9600" output="screen" >
<remap from="ucCommand" to="uc0Command" />
<remap from="ucResponse" to="uc0Response" />
</node> <node pkg="r2serial_driver" type="r2serial_driver" name="r2serial1" args="1 /dev/ttyUSB1 9600" output="screen" >
<remap from="ucCommand" to="uc1Command" />
<remap from="ucResponse" to="uc1Response" />
</node> </launch>
Usage:
$ rosrun r2serial_driver r2serial_driver 0 /dev/ttyUSB0 9600
or
$ roslaunch r2serial_driver r2serial_driver.launch
try:
$ rostopic pub -r 1 /uc0Command std_msgs/String hello_my_serial
$ rostopic echo /uc0Response
You may also need to remap the /dev/ttyUSB* to some name you like cuz you may have several usb-serial devices.
If so, just Ref:重新指派usb转串口模块在linux系统中的设备调用名称(English Version: remap your usb-serial devices' names in Linux
)
But Kevin mentioned a question: "Interesting, but a lot of my serial stuff is send a message and receive a response back. Instead of separate publish/subscribes have you tried a service? That seems like it would work nicely for this."
I also noticed a problem: The Linux's System RAM and CPU will be much costed by r2serial_driver when it is running.
Next time, we'll see how to use Kevin's service to play ROS serial communication.
2. Use Service to play ROS-Serial communication
see this blog brother below...
http://blog.csdn.net/sonictl/article/details/51372534
ROS 进阶学习笔记(12) - Communication with ROS through USART Serial Port的更多相关文章
- ROS进阶学习笔记(11)- Turtlebot Navigation and SLAM - ROSMapModify - ROS地图修改
ROS进阶学习笔记(11)- Turtlebot Navigation and SLAM - 2 - MapModify地图修改 We can use gmapping model to genera ...
- ROS 进阶学习笔记(13) - Combine Subscriber and Publisher in Python, ROS
Combine Subscriber and Publisher in Python, ROS This article will describe an example of Combining S ...
- ROS进阶学习笔记(11)- Turtlebot Navigation and SLAM
(写在前面: 这里参考rbx书中第八章和ROS社区教程进行学习,先看社区教程) === Doing the Turtlebot Navigation === ref ros wiki: http ...
- ROS进阶学习笔记(10)- 搭建自己的Turtlebot(5) - Interactive Makers
用interactive_makers控制Turtlebot移动 interactive_makers 是Willow Garage公司开发的一个虚拟控制工具,可通过鼠标在虚拟环境中的操作,完成实际机 ...
- Ext.Net学习笔记12:Ext.Net GridPanel Filter用法
Ext.Net学习笔记12:Ext.Net GridPanel Filter用法 Ext.Net GridPanel的用法在上一篇中已经介绍过,这篇笔记讲介绍Filter的用法. Filter是用来过 ...
- SQL反模式学习笔记12 存储图片或其他多媒体大文件
目标:存储图片或其他多媒体大文件 反模式:图片存储在数据库外的文件系统中,数据库表中存储文件的对应的路径和名称. 缺点: 1.文件不支持Delete操作.使用SQL语句删除一条记录时,对应的文 ...
- golang学习笔记12 beego table name `xxx` repeat register, must be unique 错误问题
golang学习笔记12 beego table name `xxx` repeat register, must be unique 错误问题 今天测试了重新建一个项目生成新的表,然后复制到旧的项目 ...
- Spring MVC 学习笔记12 —— SpringMVC+Hibernate开发(1)依赖包搭建
Spring MVC 学习笔记12 -- SpringMVC+Hibernate开发(1)依赖包搭建 用Hibernate帮助建立SpringMVC与数据库之间的联系,通过配置DAO层,Service ...
- Python3+Selenium3+webdriver学习笔记12(js操作应用:滚动条 日历 内嵌div)
#!/usr/bin/env python# -*- coding:utf-8 -*-'''Selenium3+webdriver学习笔记12(js操作应用:滚动条 日历 内嵌div)'''from ...
随机推荐
- 坑人的 Javascript 模块化编程 require.js
坑人的 Javascript 模块化编程 require.js
- 前端之js-本地存储-localStorage && IndexedDB
1.LocalStorage示例 var Config = function ( name ) { //storage为空时,初始化的信息 var storage = { 'name': 'test' ...
- C# name scheme
1.For varibale.camel scheme.the first word lowercase the first letter,then other words capitalize th ...
- 2.Linux技能要求
Linux嵌入式工程师技能要求: 1.C语言 具备C语言基础.理解C语言基础编程及高级编程,包括:数据类型.数组.指针.结构体.链表.文件操作.队列.栈. ...
- Excel导入MS SQL SERVER 操作
关于Excel导入到sql操作的相关问题总结: 一.大批量数据导入 方法1.从Excel大批量数据导入时我们可以使用sql里面有一个batch copy的功能 方法2.在sql中建一个table ty ...
- dropwizard使用cors支持跨域浏览器取不到自定义header问题
dropwizard支持cors的配置如下: public void run(Configuration conf, Environment environment) { // Enable CORS ...
- ngIf和ngFor共用
Angular v2不支持同一元素上使用多个结构指令. 一种解决方法,使用<ng-container>,允许为每个结构指令使用单独元素的元素,但不会将其标记为DOM. <ng-con ...
- 找出N个无序数中第K大的数
使用类似快速排序,执行一次快速排序后,每次只选择一部分继续执行快速排序,直到找到第K个大元素为止,此时这个元素在数组位置后面的元素即所求 时间复杂度: 1.若随机选取枢纽,线性期望时间O(N) 2.若 ...
- android 根据滑动隐藏或显示导航 类似手机QQ好友个人信息
//重写ScrollView public class NotifyingScrollView extends ScrollView { /** * @author Cyril Mottier */ ...
- Jmeter(十六)Logic Controllers 之 Runtime Controller
Runtime Controller-----运行时间控制器:控制其下的Sampler运行时间. 该控制器较为简单,官方文档也没作太多说明.照着Blazemeter写个例子: 运行,查看结果. 可以看 ...