摘自:https://blog.csdn.net/u014695839/article/details/81209082
ROS串口编程学习笔记
培培哥 2018-07-25 21:15:13 11172 收藏 67
分类专栏: ROS
版权
串口是一种设备间常用的通讯接口,本文将记录如何在ROS上使用其提供的serial包进行串口通信。
首先,这里要引入一个名称为serial的包,这个包的安装命令为:
$ sudo apt-get install ros-<版本号>-serial
serial包的介绍:http://wiki.ros.org/serial
接下来,创建一个自己的包,借助serial这个包来编写串口通信的代码。
1、创建一个包,依赖roscpp和serial两个包
$ catkin_create_pkg serial_port roscpp serial
2、在这个包的目录下面创建src目录,并在src目录中编写串口通信的代码
-
//serial_port.cpp
-
#include <ros/ros.h>
-
#include <serial/serial.h>
-
#include <iostream>
-
-
int main(int argc, char** argv)
-
{
-
ros::init(argc, argv, "serial_port");
-
//创建句柄(虽然后面没用到这个句柄,但如果不创建,运行时进程会出错)
-
ros::NodeHandle n;
-
-
//创建一个serial类
-
serial::Serial sp;
-
//创建timeout
-
serial::Timeout to = serial::Timeout::simpleTimeout(100);
-
//设置要打开的串口名称
-
sp.setPort("/dev/ttyUSB0");
-
//设置串口通信的波特率
-
sp.setBaudrate(115200);
-
//串口设置timeout
-
sp.setTimeout(to);
-
-
try
-
{
-
//打开串口
-
sp.open();
-
}
-
catch(serial::IOException& e)
-
{
-
ROS_ERROR_STREAM("Unable to open port.");
-
return -1;
-
}
-
-
//判断串口是否打开成功
-
if(sp.isOpen())
-
{
-
ROS_INFO_STREAM("/dev/ttyUSB0 is opened.");
-
}
-
else
-
{
-
return -1;
-
}
-
-
ros::Rate loop_rate(500);
-
while(ros::ok())
-
{
-
//获取缓冲区内的字节数
-
size_t n = sp.available();
-
if(n!=0)
-
{
-
uint8_t buffer[1024];
-
//读出数据
-
n = sp.read(buffer, n);
-
-
for(int i=0; i<n; i++)
-
{
-
//16进制的方式打印到屏幕
-
std::cout << std::hex << (buffer[i] & 0xff) << " ";
-
}
-
std::cout << std::endl;
-
//把数据发送回去
-
sp.write(buffer, n);
-
}
-
loop_rate.sleep();
-
}
-
-
//关闭串口
-
sp.close();
-
-
return 0;
-
}
serial包的文档有对每个类和函数的解释,可以参考:http://docs.ros.org/kinetic/api/serial/html/annotated.html
其中解释一下timeout的作用,在serial::Timeout结构体中有这么5个成员:
-
-
serial::Timeout::Timeout (
-
uint32_t inter_byte_timeout_ = 0,
-
uint32_t read_timeout_constant_ = 0,
-
uint32_t read_timeout_multiplier_ = 0,
-
uint32_t write_timeout_constant_ = 0,
-
uint32_t write_timeout_multiplier_ = 0
-
)
参考另一个大神的解释:(出处:https://www.cnblogs.com/visionfeng/p/5614066.html)
“间隔超时=ReadIntervalTimeout
总超时 = ReadTotalTimeoutMultiplier * 字节数 + ReadTotalTimeoutConstant
串口读取事件分为两个阶段(我以Win32 API函数ReadFile读取串口过程来说明一下)
第一个阶段是:串口执行到ReadFile()函数时,串口还没有开始传输数据,所以串口缓冲区的第一个字节是没有装数据的,这时候总超时起作用,如果在总超时时间内没有进行串口数据的传输,ReadFile()函数就返回,当然 没有读取到任何数据。而且,间隔超时并没有起作用。
第二阶段:假设总超时为20秒,程序运行到ReadFile(),总超时开始从0 计时,如果在计时到达10秒时,串口开始了数据的传输,那么从接收的第一个字节开始,间隔超时就开始计时,假如间隔超时为1ms,那么在读取完第一个字节后,串口开始等待1ms,如果1ms之内接收到了第二个字节,就读取第二个字节,间隔超时重置为0并计时,等待第三个字节的到来,如果第三个字节到来的时间超过了1ms,那么ReadFile()函数立即返回,这时候总超时计时是没到20秒的。如果在20秒总计时时间结束之前,所有的数据都遵守数据间隔为1ms的约定并陆陆续续的到达串口缓冲区,那么就成功进行了一次串口传输和读取;如果20秒总计时时间到,串口还陆陆续续的有数据到达,即使遵守字节间隔为1ms的约定,ReadFile()函数也会立即返回,这时候总超时就起作用了。
总结起来,总超时在两种情况下起作用
第一:串口没进行数据传输,等待总超时时间那么长ReadFile()才返回。非正常数据传输
第二:数据太长,总超时设置太短,数据还没读取完就返回了。读取的数据是不全的
间隔超时触发是有条件的
第一:在总超时时间内。
第二:串口进行了数据的传输。
成功的进行一次串口数据的传输和读取,只有总超时和间隔超时相互参与配合才能完成”
3、修改CMakeList文件,添加选项
-
add_executable(serial_port src/serial_port.cpp)
-
-
add_dependencies(serial_port ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
-
-
target_link_libraries(serial_port
-
${catkin_LIBRARIES}
-
)
4、编译,运行即可看到结果(记得运行roscore和在工程目录下source devel/setup.bash)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)