ros学习之串口通信(数据读取),并进行发布

2023-05-16

串口参数:
波特率:9600
起始位:1
数据位:8
停止位:1
奇偶校验:无

例如超声波模组地址为0X01,则主机发送
0X55 0XAA 0X01 0X01 checksum
checksum=(帧头+用户地址+指令)&0x00ff=0x01

unsigned char all_data[5] = {0x55,0xAA,0x01,0x01,0x01}; //声明发出指令(帧头(0x55,0xAA),地址(0x01、0x02、0x03),指令(0x10),checksum)

超声波传感器发送指令周期需大于等于250ms。

在这里插入代码片
#include <ros/ros.h>                      //类似 C 语言的 stdio.h
#include <serial/serial.h>                //ROS已经内置了的串口包
#include <std_msgs/String.h>
#include <std_msgs/Empty.h>
#include <signal.h>
#include <sensor_msgs/Imu.h>
#include <ros_com_msg/com.h>
#include <ros/duration.h>
#include <string.h>
#include "ros_com_msg.h"
#include "ros_com_msg/com.h"          //要用到 msg 中定义的数据类型

ros::Publisher imu_pub;
serial::Serial ser; //声明串口对象

bool sendcheck = true ;

unsigned char all_data[5] = {0x55,0xAA,0x01,0x01,0x01}; //声明发出指令(帧头(0x55,0xAA),地址(0x01、0x02、0x03),指令(0x10),checksum)


const int MAX = 100;
int DecArr[MAX] = { 0 };

//十六进制转十进制
int Hex_Conversion_Dec(int aHex)
{
    long Dec = 0;
    int temp = 0;
    int count = 0;

    while (0 != aHex)//循环直至aHex的商为零
    {
//        ROS_INFO("%d------------------------------\n",aHex%16);
        temp = aHex;
        aHex = aHex / 16;//求商
        temp = temp % 16;//取余
        DecArr[count++] = temp;//余数存入数组
    }
    int j = 0;
    for (int i = 0; i<count; i++ )
    {
        if (i < 1)
        {
            Dec = Dec + DecArr[i];
        }
        else
        {
        //16左移4位即16²,左移8位即16³、以此类推。
            Dec = (Dec + (DecArr[i]*(16<<j)));
            j += 4;
        }
    }
    return Dec ;
}

/*************************************************************************/
//当关闭包时调用,关闭上传
void mySigIntHandler(int sig)
{
   ROS_INFO("close the com serial!\n");
   ser.close();
   ros::shutdown();
}
/*************************************************************************/

void timercallback(const ros::TimerEvent&)
{
    ser.write(all_data,5);
//    ROS_INFO("write----------\n");
}

void cmd_comCallback(const ros_com_msg::comPtr &msg)
{
    ROS_INFO("Subcribe Person Info++++++++++++++++: data1:%d  data2:%d  data3:%d  data4:%d\n",
                msg->Data_1, msg->Data_2, msg->Data_3,msg->Data_4);
}

int main(int argc,char **argv)
{
   u16 len = 0;
//   u16 TempCheck = 0 , check =0;
   u8  data[200];
   std::string usart_port;

   ros::init(argc,argv,"com_talker",ros::init_options::NoSigintHandler);            //解析参数,命名节点为 com_talker
   ros_com_msg::com com_msg;
   ros::NodeHandle nh;
   ros::Publisher pub = nh.advertise<ros_com_msg::com>("com_info",1);            //创建一个publisher对象,发布名为com_info,队列长度为1,消息类型为ros::com_msg::com。
   signal(SIGINT, mySigIntHandler);  											//把原来ctrl+c中断函数覆盖掉,把信号槽连接到mySigIntHandler保证关闭节点

   ros::Timer timer1 = nh.createTimer(ros::Duration (0.25), timercallback);    //设置定时器每隔250ms发送数据

   ros::Subscriber sub = nh.subscribe("cmd_com",1,cmd_comCallback);  //创建subscriber 对象,名为cmd_com,注册回调函数为cmd_velCallback,队列长度为1。

   try
    {
       //设置串口属性,并打开串口
      ser.setPort("/dev/ttyUSB0");
      ser.setBaudrate(9600);
      serial::Timeout to = serial::Timeout::simpleTimeout(1000);
      ser.setTimeout(to);
      ser.open();
    }
    catch (serial::IOException& e)
    {
        ROS_ERROR_STREAM("Unable to open port ");
        return -1;
    }

    //检测串口是否已经打开,并给出提示信息
    if(ser.isOpen())
    {
        ser.flushInput();      //清空输入缓存,把多余的无用数据删除
        ROS_INFO_STREAM("cgq Serial Port initialized");
    }
    else
    {
        return -1;
    }
     ros::Rate loop_rate(4);   //设置循环的频率为4Hz,250ms

   while(ros::ok())
   {

        ser.read(ReturnRobotData.data,sizeof(ReturnRobotData.data));

        u16 TempCheck = 0 , check =0;
        char num1 =0 ,num2 =0, num3 = 0,num4 =0;
        for(u8 i=0 ; i<sizeof(ReturnRobotData.data)-1; i++)
        {
         TempCheck += ReturnRobotData.data[i];
         check = TempCheck & 0x00ff;
//         printf("return data  %s\n",ReturnRobotData.data[i]);
        }
        //验证checksum
//        printf("Returnchecksum :%x %x \n",ReturnRobotData.prot.header1,ReturnRobotData.prot.header2);
//        printf("Returnchecksum :%x\n",ReturnRobotData.prot.Checksum);
//        printf("Returncheck :%X\n",check);

        if(ReturnRobotData.prot.header1 == 0x55 && ReturnRobotData.prot.header2 == 0xAA && ReturnRobotData.prot.Checksum == check)
        {
            ROS_INFO_STREAM("read seriel------------------");

           int num1 = ReturnRobotData.prot.Data_1H*256 + ReturnRobotData.prot.Data_1L;
           int num2 = ReturnRobotData.prot.Data_2H*256 + ReturnRobotData.prot.Data_2L;
           int num3 = ReturnRobotData.prot.Data_3H*256 + ReturnRobotData.prot.Data_3l;
           int num4 = ReturnRobotData.prot.Data_4H*256 + ReturnRobotData.prot.Data_4L;

//            printf("ultrasonic_num1(0x):%X ultrasonic_num1(0x):%X ultrasonic_num3(0x):%X ultrasonic_num4(0x):%X\n",
//                    ReturnRobotData.prot.Data_1H*256 + ReturnRobotData.prot.Data_1L,
//                    ReturnRobotData.prot.Data_2H*256 + ReturnRobotData.prot.Data_2L,
//                    ReturnRobotData.prot.Data_3H*256 + ReturnRobotData.prot.Data_3l,
//                    ReturnRobotData.prot.Data_4H*256 + ReturnRobotData.prot.Data_4L);

            printf("ultrasonic_num1(0x):%X ultrasonic_num1(0x):%X ultrasonic_num3(0x):%X ultrasonic_num4(0x):%X\n",
                   num1,num2,num3,num4);

            //十六进制转化为十进制
            int zhuanhuanum1 =  Hex_Conversion_Dec(num1);
            int zhuanhuanum2 =  Hex_Conversion_Dec(num2);
            int zhuanhuanum3 =  Hex_Conversion_Dec(num3);
            int zhuanhuanum4 =  Hex_Conversion_Dec(num4);
            printf("ultrasonic_num1(mm):%d ultrasonic_num2(mm):%d ultrasonic_num3(mm):%d ultrasonic_num4(mm):%d \n", zhuanhuanum1,zhuanhuanum2,zhuanhuanum3,zhuanhuanum4);

            com_msg.Data_1 = zhuanhuanum1;
            com_msg.Data_2 = zhuanhuanum2;
            com_msg.Data_3 = zhuanhuanum3;
            com_msg.Data_4 = zhuanhuanum4;
            pub.publish(com_msg); //发布

            ROS_INFO("------------------------------------------------\n");
            memset(ReturnRobotData.data,0,sizeof(ReturnRobotData.data));
        }
        else
        {
//          ROS_INFO("not return %x  %x  %x\n",ReturnRobotData.prot.header1,ReturnRobotData.prot.header2,ReturnRobotData.prot.Checksum);
            ROS_INFO("not read accuracy");
          len = ser.available();
          //清空数据残余
          if(len > 0)
          {
             ser.read(data,len);
          }
          //全部探头打开
        }
      ros::spinOnce();
      loop_rate.sleep();   //按前面设置的4Hz频率将程序挂起
    }
    return 0;
}

其中 ros::Rate loop_rate(4)和loop_rate.sleep()需要同时用才可以控制发布频率。
ros::Rate loop_rate写在循环外部,loop_rate.sleep写在循环内部。
ros::spinOnce()的作用是集中处理本节点的所有回调函数。当程序运行到spinOnce()时,程序到相应的topic订阅缓存区查看是否存在消息,如果有消息,则将消息传入回调函数执行回调函数;如果没有消息则继续向后执行。spinOnce()并不是等待到一个消息才向后执行,而是查看有没有消息。

运行成功截图在这里插入图片描述com.msg放进msg(功能包ros_com_msg下的msg文件)
com.msg的代码

int16 Data_1
int16 Data_2
int16 Data_3
int16 Data_4

ros_com_msg.h的代码

#ifndef ROS_COM_MSG_H
#define ROS_COM_MSG_H

#include <ros/ros.h>

#define HEADER    0x55AA		//数据头

typedef unsigned char      u8;
typedef unsigned short int u16;
typedef short int          s16;
typedef unsigned       int u32;


union ReturnRobotData
{
   u8 data[13];
   struct
   {
      u8 header1;
      u8 header2;
      u8 Add;
      u8 Cmd;
      u8 Data_1H;
      u8 Data_1L;
      u8 Data_2H;
      u8 Data_2L;
      u8 Data_3H;
      u8 Data_3l;
      u8 Data_4H;
      u8 Data_4L;
      u8 Checksum;
   }prot;
}ReturnRobotData;

#endif // ROS_COM_MSG_H

在CMakeList.txt 添加编译选项

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation
  serial
  geometry_msgs
)
-----------------------------------------------
## Generate messages in the 'msg' folder
 add_message_files(
   FILES
   com.msg
)
-----------------------------------------------
## Generate added messages and services with any dependencies listed here
 generate_messages(
   DEPENDENCIES
   std_msgs
 )
-----------------------------------------------
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES ros_com_msg
#  CATKIN_DEPENDS roscpp std_msgs
#  DEPENDS system_lib
#  message_runtime
CATKIN_DEPENDS message_runtime roscpp  std_msgs
)

在package.xml添加功能包依赖

  <build_depend>message_generation</build_depend>
  <exec_depend>message_runtime</exec_depend>
  
  <buildtool_depend>catkin</buildtool_depend>
  <build_depend>roscpp</build_depend>
  <build_depend>std_msgs</build_depend>
  <build_export_depend>roscpp</build_export_depend>
  <build_export_depend>std_msgs</build_export_depend>
  <exec_depend>roscpp</exec_depend>
  <exec_depend>std_msgs</exec_depend>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ros学习之串口通信(数据读取),并进行发布 的相关文章

随机推荐

  • Ubuntu更新源、添加和删除软件PPA源的命令

    一 更新源 sudo cp etc apt sources list etc apt sources list bak 备份原来的源文件 sudo vi etc apt sources list 编辑源文件 sudo apt update
  • 遗传算法求解无人机路径多目标规划问题(python实现)

    问题描述 前置背景 该问题是笔者所在学校2021年数学建模的第二次训练赛的第二问 问题一即有3种通信方式D1 D2 D3 xff0c 他们在三个海拔高度3km xff0c 6km xff0c 9km的通信包络网存在一个661 621的网格地
  • 如何给飞行器电调校准油门的方法

    一起校准 就是四个电调一块校准 xff0c 将飞控电源与电调电源分离开 xff0c 只给飞控上电 飞控解锁后 xff0c 油门打到最大 xff0c 再给电调上电 xff0c 此时若 听到电调发出 滴 滴 的两声后 xff0c 证明遥控油门的
  • STM32MP157系列教程连载-Linux系统移植篇4:STM32MP1微处理器之Bootloader移植

    STM32MP157系列教程连载 Linux系统移植篇4 xff1a STM32MP1微处理器之Bootloader移植 第 1 章 BootLoader xff08 Uboot xff09 移植 1 1 实验原理 1 1 1 概念 简单地
  • Makefile中的$@, $^, $< , $?, $%, $+, $*

    64 表示目标文件 表示所有的依赖文件 lt 表示第一个依赖文件 表示比目标还要新的依赖文件列表 仅当目标是函数库文件中 xff0c 表示规则中的目标成员名 例如 xff0c 如果一个目标是 foo a bar o xff0c 那么 xff
  • 嵌入式方向JD

    偏应用 xff1a 职位描述 xff1a 工作职责 负责业务部门嵌入式软件功能相关开发工作 xff0c 与其他同事合作完成项目交付 任职资格 1 本科及以上学历 xff1b 2 具备3 5年嵌入式行业软件开发经验 xff1b 3 熟练掌握C
  • VirtualBox虚拟机的迁移和快照问题

    查看原文 xff1a http www sijitao net 1616 html 前几天博主迁移了一台测试服务器上的virtualbox虚拟机 本来直接拷贝文件就可以解决的问题 xff0c 结果折腾了我一天 一开始 xff0c 我没注意这
  • 多轴飞行器无人机硬件技术细谈

    http www 52rd com S TXT 2015 3 TXT65233 HTM 多轴飞行器无人机硬件技术细谈 52RD com 2015年3月6日 电子工程专辑 参与 xff1a 2人 我来说两句 在今年CES上无人机成为了展会最大
  • android中onFinishInflate和onSizeChange()的调用时机

    1 onFinishInflate onFinishInflate是view加载完xml之后执行的方法 xff0c 相当于只是完成了布局的映射 xff0c 在这个方法里面是得不到控件的高宽的 xff0c 控件的高宽是必须在调用了onMeas
  • C++构造函数中冒号作用及explicit关键字

    构造函数中冒号作用 xff0c 类给成员变量赋值 xff0c 更适用于成员变量的常量const型 span class token keyword class span span class token class name myClass
  • IDEA(2022.2)搭建Servlet基本框架详细步骤

    文章目录 1 创建基本Web项目1 1 创建新项目1 2 生成Module1 3 设置Web框架1 4 新建导航页 2 配置Tomcat服务器2 1 设置Tomcat2 2 部署Tomcat启动服务2 3 测试Tomcat 3 实现Serv
  • 多径信道

    多径信道 多径信道的低通等效特征多径信道的统计特性时变行为的统计特性 在到达接收天线之前 xff0c 发送的信号遵循许多不同的路径 xff0c 并且这些路径的集合构成多径无线电传播信道 xff08 如图9 3 xff09 产生的信号强度将经
  • [VSCode] VSCode使用C++运行HelloWorld

    一 对于VS Code的介绍 首先需要明确的一点是VSCode并不是一个标准意义上的IDE Integrated Development Environment xff0c 集成开发环境 xff0c VSCode更像是一个功能强大的编辑器
  • 计算机组成.零件之间的通信.总线BUS

    总线干嘛的 xff1f 说白了就是用来传输数据的 xff0c 在计算机的各个部件之间 比如我主存里存的数据CPU要用 xff0c 需要一条线路传过去吧 xff0c CPU内部各个寄存器之间 寄存器与ALU CU与各个部件之间等等等等很多地方
  • 用linux也太爽了啊

    最近更换了公司 xff0c 换成了ubuntu系统进行开发 xff0c 我只能说比windows开发好用多了 xff0c 在windows需要各种工具 xff0c 然而linux的名林嗯行就解决了很多的问题 xff0c 从前windows下
  • 希望计算机专业学生都知道这些宝藏老师

    希望计算机专业学生都知道这些宝藏老师 IT服务圈儿 2022 12 04 17 30 发表于江苏 以下文章来源于程序员库森 xff0c 作者库森 程序员库森 阿里程序员 xff0c 专注分享编程学习 校招求职和大厂面试 IT服务圈儿 关注互
  • docker镜像push到仓库

    镜像可以很方便直接 push 到 docker 的公共仓库或阿里云仓库 1 上传至docker仓库 1 登录docker hub创建自己的仓库地址 xff1a https hub docker com repository create 创
  • 深度学习样本归一化到[0,1]还是[-1,1]

    一般 xff0c 我们需要对神经网络的输入样本进行归一化 xff0c 通常有多种选择 xff0c 比如归一化到 0 1 xff0c 或归一化到 1 1 这两种方法 xff0c 哪种归一化方法更好呢 xff1f 还是没有区别 现在的实验经验
  • ubuntu装机并设置远程连接

    step1 ubuntu16装系统的过程略过 step2 联网 step3 apt get更新 sudo apt get update step4 安装ssh 安装 openssh 服务 sudo apt get install opens
  • ros学习之串口通信(数据读取),并进行发布

    串口参数 波特率 9600 起始位 1 数据位 8 停止位 1 奇偶校验 无 例如超声波模组地址为0X01 则主机发送 0X55 0XAA 0X01 0X01 checksum checksum 61 帧头 43 用户地址 43 指令 am