精华内容
下载资源
问答
  • 本文主要介绍怎么编写代码实现在上层修改底层参数的相关知识...ros下使用rosserial和STM32F1/STM32F4系列进行通信(MDK5工程):https://blog.csdn.net/qq_36349536/article/details/82773064 STM32(MDK)中如何使用ROS
  • ROSSTM32ROSSTM32通信

    千次阅读 2021-04-11 08:06:52
    本章节主要解决的是如何在ROSSTM32之间建立串口通信,达到相互发送接收对方数据的目的,从而为我们自己以ros操作系统开发硬件提供相应的便利。 一、前期准备 完成ROSSTM32之间的串口通信,需要准备的硬件有STM...


    本章节主要解决的是如何在ROS与STM32之间建立串口通信,达到相互发送和接收对方数据的目的,从而为我们自己以ros操作系统开发硬件提供相应的便利。

    一、相关原理及准备工作

    完成ROS与STM32之间的串口通信,需要准备的硬件有STM32串口TTL转USB模块Linux硬件设备,博主使用的STM32是正点原子的STM32精英板,Linux硬件设备下搭载的rROS环境是ros-kinetic,其工作原理如下图所示
    在这里插入图片描述
    在开始ROS与STM32的通信之前,需要注意以下几点
    (1)确保stm32端和ros端波特率一定一致
    (2)确保是stm32串口,TTL转USB模块和Linux设备之间是按照上图所示连接,TX与RX相连,RX与TX相连,同时,也要测试连接线的好坏
    (3)确保linux设备系统中有CH340/CH341驱动,一般情况下都会有,如果没有CH340/CH341驱动,需要到网上查找相关资料下载驱动
    (4)确保自己的串口在Linux系统中具有超级用户权限(一般都默认不具有该权限),一般插上TTL转USB模块,Linux系统中就可以检测到ttyUSB0的串口设备
    (5)如果插上TTL转USB模块后,Linux系统中查询的串口设备不是ttyUSB0的话,在编写相应的程序时,要注意串口设备名称的一致性

    二、STM32与ROS工程文件下载

    所需要的的STM32与ROS工程文件百度云链接如下
    链接: https://pan.baidu.com/s/1oOcfHVRdzKeyQKiBKLHsrg.
    提取码:abcd

    STM32与ROS工程文件所包含的工程文件
    (1)STM32端:STM32与ROS串口通信测试工程文件
    (2)ROS端:ROS与STM32串口通信测试功能包文件

    1、STM32测试工程文件结构

    主要包括:
    (1)主函数main.c
    (2)文件mbotLinuxUsart.c
    在这里插入图片描述

    STM32与ROS串口通信测试工程文件程序详解

    main.c文件

    #include "delay.h"
    #include "sys.h"
    #include "usart.h"
    #include "led.h"
    #include "mbotLinuxUsart.h"
    //测试发送变量
    short testSend1   =5000;
    short testSend2   =2000;
    short testSend3   =1000;
    unsigned char testSend4 = 0x05;
    //测试接收变量
    int testRece1     =0;
    int testRece2     =0;
    unsigned char testRece3 = 0x00;
    
    int main(void)
    {	
    	delay_init();	    	                      
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    	uart_init(115200);	                        
    	while(1)
    	{
    	    usartSendData(testSend1,testSend2,testSend3,testSend4);
    		delay_ms(13);
    	} 
    }
    //串口中断服务函数,接收数据
    void USART1_IRQHandler()
    {
    	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
     	 {
    		 USART_ClearITPendingBit(USART1,USART_IT_RXNE);
    		 //从ROS接收数据,并把他们存放到以下三个变量当中
    		 usartReceiveOneData(&testRece1,&testRece2,&testRece3);
    	 }
    }
    

    mbotLinuxUsart.c文件

    #include "mbotLinuxUsart.h"
    #include "usart.h"       
    //数据接收暂存区
    unsigned char  receiveBuff[16] = {0};   
    //通信协议常量
    const unsigned char header[2]  = {0x55, 0xaa};
    const unsigned char ender[2]   = {0x0d, 0x0a};
    //发送数据共用体
    union sendData
    {
    	short d;
    	unsigned char data[2];
    }leftVelNow,rightVelNow,angleNow;
    //接收数据共用体
    union receiveData
    {
    	short d;
    	unsigned char data[2];
    }leftVelSet,rightVelSet;
    
    int usartReceiveOneData(int *p_leftSpeedSet,int *p_rightSpeedSet,unsigned char *p_crtlFlag)
    {
    	unsigned char USART_Receiver              = 0;        
    	static unsigned char checkSum             = 0;
    	static unsigned char USARTBufferIndex     = 0;
    	static short j=0,k=0;
    	static unsigned char USARTReceiverFront   = 0;
    	static unsigned char Start_Flag           = START;    
    	static short dataLength                   = 0;
    
    	USART_Receiver = USART_ReceiveData(USART1);   
    
    	if(Start_Flag == START)
    	{
    		if(USART_Receiver == 0xaa)                           
    		{  
    			if(USARTReceiverFront == 0x55)       
    			{
    				Start_Flag = !START;             
    				printf("header ok\n");
    				receiveBuff[0]=header[0];       
    				receiveBuff[1]=header[1];  
    				USARTBufferIndex = 0;           
    				checkSum = 0x00;				
    			}
    		}
    		else 
    		{
    			USARTReceiverFront = USART_Receiver;  
    		}
    	}
    	else
        { 
    		switch(USARTBufferIndex)
    		{
    			case 0:
    				receiveBuff[2] = USART_Receiver;
    				dataLength     = receiveBuff[2];            //buf[2]
    				USARTBufferIndex++;
    				break;
    			case 1:
    				receiveBuff[j + 3] = USART_Receiver;        //buf[3] - buf[7]					
    				j++;
    				if(j >= dataLength)                         
    				{
    					j = 0;
    					USARTBufferIndex++;
    				}
    				break;
    			case 2:
    				receiveBuff[3 + dataLength] = USART_Receiver;
    				checkSum = getCrc8(receiveBuff, 3 + dataLength);
    				if (checkSum != receiveBuff[3 + dataLength]) //buf[8]
    				{
    					printf("Received data check sum error!");
    					return 0;
    				}
    				USARTBufferIndex++;
    				break;
    			case 3:
    				if(k==0)
    				{
    					k++;
    				}
    				else if (k==1)
    				{			
    					 for(k = 0; k < 2; k++)
    					{
    						leftVelSet.data[k]  = receiveBuff[k + 3]; //buf[3]  buf[4]
    						rightVelSet.data[k] = receiveBuff[k + 5]; //buf[5]  buf[6]
    					}				
    					*p_leftSpeedSet  = (int)leftVelSet.d;
    					*p_rightSpeedSet = (int)rightVelSet.d;
    					//ctrlFlag
    					*p_crtlFlag = receiveBuff[7];                //buf[7]
    					USARTBufferIndex   = 0;
    					USARTReceiverFront = 0;
    					Start_Flag         = START;
    					checkSum           = 0;
    					dataLength         = 0;
    					j = 0;
    					k = 0;
    				}
    				break;
    			 default:break;
    		}		
    	}
    	return 0;
    }
    
    void usartSendData(short leftVel, short rightVel,short angle,unsigned char ctrlFlag)
    {
    	unsigned char buf[13] = {0};
    	int i, length = 0;
    	leftVelNow.d  = leftVel;
    	rightVelNow.d = rightVel;
    	angleNow.d    = angle;
    	for(i = 0; i < 2; i++)
    		buf[i] = header[i];                      // buf[0] buf[1] 
    	length = 7;
    	buf[2] = length;                             // buf[2]
    	for(i = 0; i < 2; i++)
    	{
    		buf[i + 3] = leftVelNow.data[i];         // buf[3] buf[4]
    		buf[i + 5] = rightVelNow.data[i];        // buf[5] buf[6]
    		buf[i + 7] = angleNow.data[i];           // buf[7] buf[8]
    	}
    	buf[3 + length - 1] = ctrlFlag;              // buf[9]
    	buf[3 + length] = getCrc8(buf, 3 + length);  // buf[10]
    	buf[3 + length + 1] = ender[0];              // buf[11]
    	buf[3 + length + 2] = ender[1];              // buf[12]
    	USART_Send_String(buf,sizeof(buf));
    }
    void USART_Send_String(u8 *p,u16 sendSize)
    { 
    	static int length =0;
    	while(length<sendSize)
    	{   
    		while( !(USART1->SR&(0x01<<7)) );
    		USART1->DR=*p;                   
    		p++;
    		length++;
    	}
    	length =0;
    }
    unsigned char getCrc8(unsigned char *ptr, unsigned short len)
    {
    	unsigned char crc;
    	unsigned char i;
    	crc = 0;
    	while(len--)
    	{
    		crc ^= *ptr++;
    		for(i = 0; i < 8; i++)
    		{
    			if(crc&0x01)
                    crc=(crc>>1)^0x8C;
    			else 
                    crc >>= 1;
    		}
    	}
    	return crc;
    }
    

    2、ROS测试功能包文件结构

    主要包括:
    (1)通信协议以及串口配置程序文件mbot_linux_serial.cpp
    (2)系统结构测试主程序文件publish_node.cpp
    (3)一个基础ROS功能包具备的其他程序文件
    在这里插入图片描述

    ROS与STM32串口通信测试功能包程序详解

    publish_node.cpp文件

    //包含ros库下的ros.h头文件
    #include "ros/ros.h"
    //包含std_msgs库下的String.h头文件
    #include "std_msgs/String.h" 
    //包含mbot_linux_serial.h头文件
    #include "mbot_linux_serial.h"
    
    //测试发送数据两
    double testSend1=5555.0;
    double testSend2=2222.0;
    unsigned char testSend3=0x07;
    //测试接受数据变量
    double testRece1=0.0;
    double testRece2=0.0;
    double testRece3=0.0;
    unsigned char testRece4=0x00;
    
    int main(int agrc,char **argv)
    {
        //创建一个ros节点,节点名称为public_node
        ros::init(agrc,argv,"public_node");
        //创建句柄,用于管理节点信息
        ros::NodeHandle nh;
        //设置频率,10HZ
        ros::Rate loop_rate(10);
        //串口初始化,相关定义在mbot_linux_serial.cpp有描述
        serialInit();
        /*
        ros::ok()在不进行任何操作时,就相当于返回True,只有在以下几种情况下会变成返回False
        (1)运行终端时,按下Ctrl-C时
        (2)我们被一个同名同姓的节点从网络中踢出。
        (3)ros::shutdown()被应用程序的另一部分调用。
        (4)所有的ros::NodeHandles都被销毁了。
        */
        while(ros::ok())
        {
            /*
            ros::spinOnce()和ros::spin()是ros消息回调处理函数
            ros消息回调处理函数原理:如果你的程序写了相关的消息订阅函数,那么程序在执行过程中,除了主程序以外,ROS还会自动在后台按照你规定的格式,接受订阅的消息,但是所接到的消息并不是立刻就被处理,而是必须要等到ros::spin()或ros::spinOnce()执行的时候才被调用
            他们的区别在于ros::spinOnce调用后会继续执行其后面的语句,而ros::spin()则在调用后不会继续执行其后面的语句
            */
            ros::spinOnce();
            //向STM32端发送数据,前两个为double类型,最后一个为unsigned char类型,其函数相关定义在mbot_linux_serial.cpp有描述
    	    writeSpeed(testSend1,testSend2,testSend3);
            //从STM32接收数据,输入参数依次转化为小车的线速度、角速度、航向角(角度)、预留控制位,其函数相关定义在mbot_linux_serial.cpp有描述
    	    readSpeed(testRece1,testRece2,testRece3,testRece4);
            //打印数据
    	    ROS_INFO("%f,%f,%f,%d\n",testRece1,testRece2,testRece3,testRece4);
    	    //等待100ms的时间
            loop_rate.sleep();
        }
        return 0;
    }
    

    mbot_linux_serial.cpp文件

    //包含对应头文件
    #include "mbot_linux_serial.h"
    using namespace std;//设定工作空间的名称
    using namespace boost::asio;//设定工作空间的名称
    //串口相关对象
    //创建一个 io_service实例
    boost::asio::io_service iosev;
    //构造一个串口,将"/dev/ttySUB0"转移给实例iosev
    boost::asio::serial_port sp(iosev, "/dev/ttyUSB0");
    boost::system::error_code err;
    /********************************************************
                串口发送接收相关常量、变量、共用体对象
    ********************************************************/
    const unsigned char ender[2] = {0x0d, 0x0a};//数据尾
    const unsigned char header[2] = {0x55, 0xaa};//数据头
    //发送左右轮速控制速度共用体
    union sendData
    {
    	short d;
    	unsigned char data[2];
    }leftVelSet,rightVelSet;
    //接收数据(左轮速、右轮速、角度)共用体(-32767 - +32768)
    union receiveData
    {
    	short d;
    	unsigned char data[2];
    }leftVelNow,rightVelNow,angleNow;
    /********************************************************
    函数功能:串口参数初始化
    入口参数:无
    出口参数:
    ********************************************************/
    void serialInit()
    {
        sp.set_option(serial_port::baud_rate(115200));//设置波特率
        sp.set_option(serial_port::flow_control(serial_port::flow_control::none));//流量控制
        sp.set_option(serial_port::parity(serial_port::parity::none));//奇偶校验
        sp.set_option(serial_port::stop_bits(serial_port::stop_bits::one));//停止位
        sp.set_option(serial_port::character_size(8)); //字符大小
    }
    /********************************************************
    函数功能:将对机器人的左右轮子控制速度,打包发送给下位机
    入口参数:机器人线速度、角速度
    出口参数:
    ********************************************************/
    void writeSpeed(double Left_v, double Right_v,unsigned char ctrlFlag)
    {
        unsigned char buf[11] = {0};//
        int i, length = 0;
    
        leftVelSet.d  = Left_v;//mm/s
        rightVelSet.d = Right_v;
    
        // 设置消息头
        for(i = 0; i < 2; i++)
            buf[i] = header[i];             //buf[0]  buf[1]
        
        // 设置机器人左右轮速度
        length = 5;
        buf[2] = length;                    //buf[2]
        for(i = 0; i < 2; i++)
        {
            buf[i + 3] = leftVelSet.data[i];  //buf[3] buf[4]
            buf[i + 5] = rightVelSet.data[i]; //buf[5] buf[6]
        }
        // 预留控制指令
        buf[3 + length - 1] = ctrlFlag;       //buf[7]
    
        // 设置校验值、消息尾
        buf[3 + length] = getCrc8(buf, 3 + length);//buf[8]
        buf[3 + length + 1] = ender[0];     //buf[9]
        buf[3 + length + 2] = ender[1];     //buf[10]
    
        // 通过串口下发数据
        boost::asio::write(sp, boost::asio::buffer(buf));
    }
    /********************************************************
    函数功能:从下位机读取数据
    入口参数:机器人左轮轮速、右轮轮速、角度,预留控制位
    出口参数:bool
    ********************************************************/
    bool readSpeed(double &Left_v,double &Right_v,double &Angle,unsigned char &ctrlFlag)
    {
        char i, length = 0;
        unsigned char checkSum;
        unsigned char buf[150]={0};
        //=========================================================
        //此段代码可以读数据的结尾,进而来进行读取数据的头部
        try
        {
            boost::asio::streambuf response; 
            boost::asio::read_until(sp, response, "\r\n",err);   
            copy(istream_iterator<unsigned char>(istream(&response)>>noskipws),
            istream_iterator<unsigned char>(),
            buf); 
        }  
        catch(boost::system::system_error &err)
        {
            ROS_INFO("read_until error");
        } 
        //=========================================================        
    
        // 检查信息头
        if (buf[0]!= header[0] || buf[1] != header[1])   //buf[0] buf[1]
        {
            ROS_ERROR("Received message header error!");
            return false;
        }
        // 数据长度
        length = buf[2];                                 //buf[2]
    
        // 检查信息校验值
        checkSum = getCrc8(buf, 3 + length);             //buf[10] 计算得出
        if (checkSum != buf[3 + length])                 //buf[10] 串口接收
        {
            ROS_ERROR("Received data check sum error!");
            return false;
        }    
    
        // 读取速度值
        for(i = 0; i < 2; i++)
        {
            leftVelNow.data[i]  = buf[i + 3]; //buf[3] buf[4]
            rightVelNow.data[i] = buf[i + 5]; //buf[5] buf[6]
            angleNow.data[i]    = buf[i + 7]; //buf[7] buf[8]
        }
    
        // 读取控制标志位
        ctrlFlag = buf[9];
        
        Left_v  =leftVelNow.d;
        Right_v =rightVelNow.d;
        Angle   =angleNow.d;
        return true;
    }
    /********************************************************
    函数功能:获得8位循环冗余校验值
    入口参数:数组地址、长度
    出口参数:校验值
    ********************************************************/
    unsigned char getCrc8(unsigned char *ptr, unsigned short len)
    {
        unsigned char crc;
        unsigned char i;
        crc = 0;
        while(len--)
        {
            crc ^= *ptr++;
            for(i = 0; i < 8; i++)
            {
                if(crc&0x01)
                    crc=(crc>>1)^0x8C;
                else 
                    crc >>= 1;
            }
        }
        return crc;
    }
    

    mbot_linux_serial.h文件

    //类似stm32程序头文件的编写规则
    #ifndef MBOT_LINUX_SERIAL_H
    #define MBOT_LINUX_SERIAL_H
    
    #include <ros/ros.h>
    #include <ros/time.h>
    #include <geometry_msgs/TransformStamped.h>
    #include <tf/transform_broadcaster.h>
    #include <nav_msgs/Odometry.h>
    #include <boost/asio.hpp>
    #include <geometry_msgs/Twist.h>
    
    extern void serialInit();
    extern void writeSpeed(double Left_v, double Right_v,unsigned char ctrlFlag);
    extern bool readSpeed(double &Left_v,double &Right_v,double &Angle,unsigned char &ctrlFlag);
    unsigned char getCrc8(unsigned char *ptr, unsigned short len);
    
    #endif
    

    三、ROS与STM32串口通信实验及运行效果

    在STM32端,下载测试工程文件后,打开keil5软件,对程序进行编译烧录;在ROS端,打开vscode软件,在/home/ubuntu/fjy_xm路径下创建catkin_serial/src文件,对工作空间进行编译,并在/catkin_serial/src文件加下添加topic_example功能包,再进行工作空间的编译,并设置环境变量source devel/setup.bash
    在这里插入图片描述
    将TTY转USB模块按照对应的连接关系分别与STM32和ROS端相连,确保设备连接好之后,上电,首先需要查看以下串口设备,显示如下,说明设备之间连接正常

    #查看串口设备
    ls -l /dev/ttyUSB*

    在这里插入图片描述
    其次,为串口添加超级用户权限

    #添加设备权限
    sudo chmod 777 /dev/ttyUSB0

    然后,新建一个终端 ,启动rosmaster,即在终端中输入roscore
    在原终端下运行publish_node节点

    rosrun topic_example publish_node

    在这里插入图片描述
    在这里插入图片描述
    ROS端正常接收到STM32端发送过来的信息,stm32查看ROS端发送过来的信息,可以在串口调试助手上进行查看,这样,我们就完成了一个简单的ROS与STM32之间的串口通信,为我们的ROS操作系统的开发提供了些许帮助

    展开全文
  • ROSstm32通信

    千次阅读 多人点赞 2020-04-21 22:57:43
    stm32和arduino等主要用来处理一些边缘事件,比如亮个LED,驱动个电机啥的。相比于ros,实时性强是嵌入式单片机最大的优点(以我做的两轮平衡小车为例,stm32f103的一个周期大概为3ms左右),所以ros和单片机的...

    0.概述

    ros和stm32等嵌入式单片机的最大区别在于ros主要用于处理slam、机器视觉、人工智能这种对于算力要求高,算法复杂的问题;而stm32和arduino等主要用来处理一些边缘事件,比如亮个LED,驱动个电机啥的。相比于ros,实时性强是嵌入式单片机最大的优点(以我做的两轮平衡小车为例,stm32f103的一个周期大概为3ms左右),所以ros和单片机的通讯是必然的。
    这篇文章是基于ros的串口函数库来和stm32进行串口通讯。stm32采用usart+dma接收数据。同时也可移植arduino等平台。

    1.ROS端配置

    共有两个功能包stm32_talker和stm32_listener。由stm32_talker向stm32_listener发布给stm32的命令消息,listener通过串口和stm32双向通讯,再向talker发布反馈消息。笔者这么做的目的是将串口部分分离位一个单独的功能包,方便以后移植。

    1.安装串口库

    $ sudo apt-get install ros-<版本号>-serial
    

    2.创建talker功能包,基于rospy、roscpp、serial这三个包

    catkin_create_pkg stm32_talker rospy roscpp serial
    

    3.在此功能包下创建两个消息stm32_message_bag和stm32_message_back,分别是发送给stm32的命令和stm32回传的消息,并且将其包含在CMakeList中
    消息内容为:

    //stm32_message_back
    uint8 data0
    uint8 data1
    uint8 data2
    uint8 data3
    uint8 data4
    uint8 data5
    uint8 data6
    uint8 data7
    
    //stm32_message_back
    uint8 data0
    uint8 data1
    uint8 data2
    uint8 data3
    uint8 data4
    uint8 data5
    uint8 data6
    uint8 data7
    
    消息内容是一样的,创建两个只是为了区分,不差这点内存。
    

    创建消息的具体过程在笔者之前的文章中,不再赘述。

    4.在src下新建stm32_talker.cpp,并且输入以下代码:

    #include <ros/ros.h>
    #include <stm32_talker/stm32_message_bag.h>
    #include <stm32_talker/stm32_message_back.h>
    
    stm32_talker::stm32_message_bag msg;//声明命令变量
    /****初始化命令****/
    void init_message_command()
    	{
    		msg.data0=0x01;
    		msg.data1=0x01;
    		msg.data2=0x01;
    		msg.data3=0x01;
    		msg.data4=0x01;
    		msg.data5=0x01;
    		msg.data6=0x01;
    		msg.data7=0x01;
    	}
    
    
    /****接收到stm32反馈后的回调函数****/
    void stm32backcallback(const stm32_talker::stm32_message_bag::ConstPtr& back)
    	{
    		ROS_INFO("I heard back");
    
    		uint8_t stm32_back[10];
    		size_t n=8;
    
    		stm32_back[0]=back->data0;
    		stm32_back[1]=back->data1;
    		stm32_back[2]=back->data2;
    		stm32_back[3]=back->data3;
    		stm32_back[4]=back->data4;
    		stm32_back[5]=back->data5;
    		stm32_back[6]=back->data6;
    		stm32_back[7]=back->data7;
    		for(int i=0;i<=7;i++)
    			{
    				ROS_INFO("%02x",stm32_back[i]);
    			}
    	}
    
    
    
    int main(int argc, char **argv)
    	{
    		ros::init(argc,argv,"stm32_talker");
    		ros::NodeHandle n;
    		ros::Rate loop_rate(10);
    		ros::Publisher stm32_command_pub = n.advertise<stm32_talker::stm32_message_bag>("stm32_command",1000);//发布命令
    		ros::Subscriber stm32_back_sub = n.subscribe("stm32_back",1000,stm32backcallback);//订阅反馈
    
    		while(ros::ok())
    		{
    			init_message_command();
    			stm32_command_pub.publish(msg);//发布命令
    			loop_rate.sleep();
    			ros::spinOnce();
       		}
    	}
    

    5.创建listener功能包,基于rospy、roscpp、serial、stm32_talker这四个包

    catkin_create_pkg stm32_listener rospy roscpp serial stm32_talker
    

    6.在listener功能包下,src文件夹中新建stm32_listener.cpp,并且输入以下代码:

    #include <ros/ros.h>
    #include <serial/serial.h>
    #include <stm32_talker/stm32_message_bag.h>
    #include <stm32_talker/stm32_message_back.h>
    
    
    serial::Serial ser;//串口变量
    
    //打开串口
    void openserial()
    	{
    		try
    			{
    				ser.setPort("/dev/ttyUSB0");//设备端口号
    				ser.setBaudrate(38400);//波特率
    				serial::Timeout t = serial::Timeout::simpleTimeout(1000);//这个应该是超时,但是是必须的!! 
          			ser.setTimeout(t); 
    				ser.open();//打开串口
    			}
    		catch (serial::IOException& e) 
        			{ 
            			ROS_ERROR_STREAM("Unable to open port "); 
        			} 
    		if(ser.isOpen())
    			{
    				ROS_INFO("OPEN");
    			}
    	}
    
    //订阅到talker后的回调函数
    void stm32commandcallback(const stm32_talker::stm32_message_bag::ConstPtr& command)
    	{
    		ROS_INFO("I heard talker");
    		uint8_t data[10];
    		size_t n=8;
    		data[0]=command->data0;
    		data[1]=command->data1;
    		data[2]=command->data2;
    		data[3]=command->data3;
    		data[4]=command->data4;
    		data[5]=command->data5;
    		data[6]=command->data6;
    		data[7]=command->data7;
    		ser.write(data,n);
    	}
    
    
    int main(int argc,char **argv)
    	{
    		ros::init(argc,argv,"stm32_listener");
    		ros::NodeHandle m;
    
    		openserial();					//打开串口
    		ros::Subscriber stm32_command_sub = m.subscribe("stm32_command",1000,stm32commandcallback);
    		ros::Publisher stm32_back_pub = m.advertise<stm32_talker::stm32_message_back>("stm32_back",1000);
    
    		while(ros::ok())
    			{
    				size_t w=ser.available();//串口缓存区字节数
    				uint8_t buffer[10];
    				if(w!=0)
    					{
    						ser.read(buffer,w);
    						stm32_talker::stm32_message_back msg_back;
    
    						msg_back.data0=buffer[0];
    						msg_back.data1=buffer[1];
    						msg_back.data2=buffer[2];
    						msg_back.data3=buffer[3];
    						msg_back.data4=buffer[4];
    						msg_back.data5=buffer[5];
    						msg_back.data6=buffer[6];
    						msg_back.data7=buffer[7];
    						w=0;
    						stm32_back_pub.publish(msg_back);
    						ROS_INFO("BACK");
    					}
    				ros::spinOnce();
    			}
    	}
    

    关于Cmakelist 与 package的配置可以参考笔者以前文章,这里不再赘述。主要一点就是talker创建了消息,listener引用了消息。

    3.stm32配置

    工程文件的创建不再赘述,主函数代码如下:

    #include"stm32f10x.h"
    #include"systick.h"
    //PA9_TX PA10_RX
    
    uint8_t USART1_RX_BUF[8];
    uint8_t USART1_TX_BUF[8];
    int sig=0;
    
    void SBUS_Configuration(void);
    void DMA_Config(void);
    void Data_Back_Init(void);
    void Send_Data();
    
    int main()
    {
     SBUS_Configuration();
     DMA_Config();
     while(1)
    {
     Data_Back_Init();
     Send_Data();
     delay_ms(500);
    }
    
    }
    
    void Data_Back_Init(void)
    {
    USART1_TX_BUF[0]=0x00;
    USART1_TX_BUF[1]=0x00;
    USART1_TX_BUF[2]=0x00;
    USART1_TX_BUF[3]=0x00;
    USART1_TX_BUF[4]=0x00;
    USART1_TX_BUF[5]=0x00;
    USART1_TX_BUF[6]=0x00;
    USART1_TX_BUF[7]=0x00;
    }
    
    void Send_Data()
    {
    for(int i=0;i<=7;i++)
    {
    USART_SendData(USART1,USART1_TX_BUF[i]);
    }
    }
    
    void SBUS_Configuration(void)
    {
    	GPIO_InitTypeDef  GPIO_InitStructure;
    	USART_InitTypeDef USART_InitStructure;
    	NVIC_InitTypeDef  NVIC_InitStructure;
    
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA| RCC_APB2Periph_AFIO, ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
    	
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    	GPIO_Init(GPIOA, &GPIO_InitStructure);
    	
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; 
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
        GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA.9
    
    	//  波特率100000 8个数据位 无校验位 1个停止位
    	USART_InitStructure.USART_BaudRate = 38400;
    	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    	USART_InitStructure.USART_StopBits = USART_StopBits_1;
    	USART_InitStructure.USART_Parity = USART_Parity_NO;
    	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    	USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
    	USART_Init(USART1, &USART_InitStructure);
    	USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
    	USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//采取串口空闲中断来处理数据
    	USART_Cmd(USART1, ENABLE);
    
    
    	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    	NVIC_Init(&NVIC_InitStructure);
    }
    void DMA_Config()
    {
        DMA_InitTypeDef DMA_InitStructure;
        DMA_DeInit(DMA1_Channel5);
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);                  // 开启DMA时钟
        DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40013804;        // 设置DMA源地址:串口数据寄存器地址*/
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART1_RX_BUF;            // 内存地址(要传输的变量的指针)
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                  // 方向:外设到内存
        DMA_InitStructure.DMA_BufferSize = 8;                         // 传输大小 
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;    // 外设地址不增
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;             // 内存地址自增   
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 外设数据单位   
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;     // 内存数据单位 
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                   // DMA一次模式  
        DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;               // 优先级:中 
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                        // 禁止内存到内存的传输
        DMA_Init(DMA1_Channel5, &DMA_InitStructure);                 // 配置DMA通道DMA1_Channel5
        DMA_Cmd(DMA1_Channel5,ENABLE);                              // 使能DMA
    
    }
    void USART1_IRQHandler(void)
    {
    	sig++;
    	u8 clear=0;
    	if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)
    	{
    		clear = USART1->SR;
    		clear = USART1->DR;
    		DMA_Config();
    		
    	}
    }
    
    }
    

    2020.4.21于家中,QAQ我要回学校。

    展开全文
  • ROSSTM32通信

    千次阅读 2020-08-03 22:51:23
    ROSSTM32通信 2020.8.1 主要内容 制作ROS包,将控制命令传给STM32,并将接收到的数据作为话题进行发布 STM32接收数据并将姿态数据传回给ROS 接收:期望角速度、期望线速度 返回:实际角速度、实际线速度 STM32端...

    ROS与STM32是用串口进行通信的,主要有两种方式,一是将STM32作为一个节点,二是制作一个上位机节点,负责与STM32进行串口通信.第一种方式需要专门的硬件,所以我选择第二种方式

    本文将实现在ROS上制作上位机节点接收来自STM32发送的IMU数据,并将接收到的数据作为话题进行发布.由于发送的数据均为float型数据,而串口只支持发送字节型的数据,所以实现两者通信的关键就是float与字节数据的相互转换.目前我知道两种将float拆分成字节数组的方式

    1. 将float数据强制转换成int整型,再将int整型拆分成字节数组
    2. 使用联合体将float型数据拆分成字节数组

    第一种方式会导致部分精度的损失,所以本文将使用第二种方式,具体做法如下:
    首先定义一个联合体

    typedef union{
    	float data;
    	uint8_t data8[4];
    }data_u;
    

    这个联合体中有两个成员,一个是32位的float数据data,另一个同样是占据了32位字长的字节数组data8,根据联合体的性质,这两个成员所在的内存位置是一样的,也就是说,改变其中任何一个成员的值,另一个也会被改变.利用这个性质,我们就可以实现float与字节数据的互换.

    运行环境

    • 软件环境:Ubuntu18.04 / ROS melodic / VScode / Keil 5
    • 硬件环境:普通PC / STM32F401 Nucleo

    STM32端

    使用联合体的方式将float型数据拆分成字节数组,数据的传输协议如下,此外还可以在后面加上纠错码

    帧头1帧头2RollPitchYaw
    0xAA0xBB4Bytes(低字节在前)4Bytes(低字节在前)4Bytes(低字节在前)

    部分串口通信程序如下

    // 联合体
    typedef union
    {
    	float data;
    	uint8_t data8[4];
    } data_u;
    
    void DataTrans(void)
    {
    	uint8_t _cnt = 0;
    	data_u _temp; // 声明一个联合体实例,使用它将待发送数据转换为字节数组
    	uint8_t data_to_send[100]; // 待发送的字节数组
    	
    	data_to_send[_cnt++]=0xAA;
    	data_to_send[_cnt++]=0xBB;
    		
    	// 将要发送的数据赋值给联合体的float成员
    	// 相应的就能更改字节数组成员的值
    	_temp.data = imu_data.yaw;
    	data_to_send[_cnt++]=_temp.data8[0];
    	data_to_send[_cnt++]=_temp.data8[1];
    	data_to_send[_cnt++]=_temp.data8[2];
    	data_to_send[_cnt++]=_temp.data8[3]; // 最高位
    	
    	_temp.data = imu_data.pit;
    	data_to_send[_cnt++]=_temp.data8[0];
    	data_to_send[_cnt++]=_temp.data8[1];
    	data_to_send[_cnt++]=_temp.data8[2];
    	data_to_send[_cnt++]=_temp.data8[3]; // 最高位
    	
    	_temp.data = imu_data.rol;
    	data_to_send[_cnt++]=_temp.data8[0];
    	data_to_send[_cnt++]=_temp.data8[1];
    	data_to_send[_cnt++]=_temp.data8[2];
    	data_to_send[_cnt++]=_temp.data8[3]; // 最高位
    	
        // 串口发送
    	HAL_UART_Transmit(&hlpuart1, data_to_send, _cnt, 0xFFFF); 
    }
    

    ROS端

    ROS端主要实现串口数据的接收,并作为消息进行发布

    首先ROS中需要安装串口开发的package,使用以下命令安装,API说明见于http://wjwwood.io/serial/doc/1.1.0/classserial_1_1_serial.html

    sudo apt-get install ros-melodic-serial
    

    然后安装Linux的串口调试助手cutecom,然后打开这个调试助手,查看STM32所连接的端口

    sudo apt-get install cutecom
    sudo cutecom
    

    新建一个package,命名为serial_node,相关的ROS环境配置见 使用VScode搭建ROS开发环境

    由于要发布接收到的imu数据,所以我们需要新建一个msg文件,命名为my_msg.msg,操作方式见ROS 自定义消息类型方法,文件内容如下

    float32 roll
    float32 pitch
    float32 yaw
    

    接下来在serial_node/src下新建一个serial_node.cpp文件,内容如下

    #include <iostream>
    #include <string>
    #include <sstream>
    using namespace std;
    
    #include "ros/ros.h"
    #include "std_msgs/String.h"
    #include "serial/serial.h"
    
    #include "serial_node/my_msg.h"
    
    #define sBUFFER_SIZE 1024
    #define rBUFFER_SIZE 1024
    unsigned char s_buffer[sBUFFER_SIZE];
    unsigned char r_buffer[rBUFFER_SIZE];
    
    serial::Serial ser;
    typedef union
    {
    	float data;
    	unsigned char data8[4];
    } data_u;
    data_u pitch;
    data_u roll;
    data_u yaw;
    
    int main(int argc, char** argv)
    {
    	ros::init(argc, argv, "serial_node");
    	ros::NodeHandle nh;
    
    	// 打开串口
    	try
    	{
    		ser.setPort("/dev/ttyACM0"); // 这个端口号就是之前用cutecom看到的端口名称
    		ser.setBaudrate(115200);
    		serial::Timeout to = serial::Timeout::simpleTimeout(1000);
    		ser.setTimeout(to);
    		ser.open();
    	}
    	catch(serial::IOException &e)
    	{
    		ROS_INFO_STREAM("Failed to open port ");
    		return -1;
    	}
    	ROS_INFO_STREAM("Succeed to open port" );
    
    	int cnt = 0;
    	ros::Rate loop_rate(500);
    	ros::Publisher imu_pub = nh.advertise<serial_node::my_msg>("imu", 1000);
    	while(ros::ok())
    	{
    		serial_node::my_msg msg;
    		if(ser.available())
    		{
    			// 读取串口数据
    			size_t bytes_read = ser.read(r_buffer, ser.available());
    			// 使用状态机处理读取到的数据,通信协议与STM32端一致
    			int state = 0;
    			unsigned char buffer[12] = {0};
    			for(int i = 0; i < bytes_read && i < rBUFFER_SIZE; i++)
    			{
    				if(state == 0 && r_buffer[i] == 0xAA)
    				{
    					state++;
    				}
    				else if(state == 1 && r_buffer[i] == 0xBB)
    				{
    					state++;
    				}
    				else if(state >= 2 && state < 14)
    				{
    					buffer[state-2]=r_buffer[i];
    					state ++;
    					if(state == 14)
    					{
    						for(int k = 0; k < 4; k++)
    						{
    							roll.data8[k] = buffer[k];
    							pitch.data8[k] = buffer[4 + k];
    							yaw.data8[k] = buffer[8 + k];
    						}						
    						ROS_INFO("%f, %f, %f, %d", roll.data, pitch.data, yaw.data, cnt);
    						state = 0;
    					}
    				}
    				else state = 0;
    			}
    		}
    		// 发布接收到的imu数据
    		msg.roll = roll.data;
    		msg.pitch = pitch.data;
    		msg.yaw = yaw.data;
    		imu_pub.publish(msg);
    		// ros::spinOnce();
    		loop_rate.sleep();
    		cnt++;
    	}
    	// 关闭串口
    	ser.close();
    	return 0;
    }
    

    测试

    运行编译生成的节点

    source ./devel/setup.bash
    rosrun serial_node serial_node
    

    运行时如果提示串口打开失败,有两种原因,一是串口号不对,使用dmesg | grep ttyS*列出检测到的串口号,逐个测试;二是没有操作权限,使用sudo chmod 666 /dev/ttyACM0即可解决,也可以使用sudo usermod -aG dialout 用户名来获得永久权限,用户名可使用whoami查看

    结果如下:
    在这里插入图片描述
    然后在该目录下新开一个终端,执行

    rostopic list
    

    可以看到/imu话题
    在这里插入图片描述
    再依次执行下面的命令,就可以看到该节点发布的imu信息

    source ./devel/setup.bash
    rostopic echo /imu
    

    在这里插入图片描述

    第一句命令必须执行,不然会报错:

    ERROR: Cannot load message class for [serial_node/my_msg]. Are your messages built?
    

    参考

    ROS进阶——串口通讯

    展开全文
  • ROS平台构建:(二)ROSstm32通信

    千次阅读 2018-07-13 18:52:59
    https://blog.csdn.net/weixin_40641902/article/details/78873340ROS平台与底盘通信协议 ROS平台与stm32通过串口进行通讯 (1)stm32部分 串口接收 (1)内容:小车左右轮速度,单位:mm/s(所有数据都为 float型,...

    这篇介绍下在上位机上如何接收和发送数据。https://blog.csdn.net/weixin_40641902/article/details/78873340

    ROS平台与底盘通信协议
    ROS平台与stm32通过串口进行通讯
    (1)stm32部分
    串口接收
    (1)内容:小车左右轮速度,单位:mm/s(所有数据都为 float型,float型占4字节)
    (2)格式:10字节
    [右轮速度4字节][左轮速度4字节][结束符”\r\n”2字节]
    串口发送
    (1)内容:里程计(x,y坐标、线速度、角速度和方向角,单位依次为:mm,mm,mm/s,rad/s,rad,所有数据都为float型,float型占4字节)
    (2)格式:21字节
    [x坐标4字节][y坐标4字节][方向角4字节][线速度4字节][角速度4字节][结束符”\n”1字节]

    (2)ROS平台串口节点部分

    写入串口
    (1)内容:左右轮速度,单位为mm/s
    (2)格式:10字节,[右轮速度4字节][左轮速度4字节][结束符"\r\n"2字节]
    
    读取串口
    (1)内容:小车x,y坐标,方向角,线速度,角速度,单位依次为:mm,mm,rad,mm/s,rad/s
    (2)格式:21字节,[X坐标4字节][Y坐标4字节][方向角4字节][线速度4字节][角速度4字节][结束符"\n"1字节]
    

    串口通信处理程序

    (1)小车底盘串口处理程序。

    底盘串口处理的程序主要写在了 main.c 文件中。
    
    底盘向串口发送里程计代码:
    
    if(main_sta&0x01)//执行发送里程计数据步骤
    {
        //里程计数据获取
        x_data.odoemtry_float=position_x;//单位mm
        y_data.odoemtry_float=position_y;//单位mm
        theta_data.odoemtry_float=oriention;//单位rad
        vel_linear.odoemtry_float=velocity_linear;//单位mm/s
        vel_angular.odoemtry_float=velocity_angular;//单位rad/s
    
        //将所有里程计数据存到要发送的数组
        for(j=0;j<4;j++)
        {
            odometry_data[j]=x_data.odometry_char[j];
            odometry_data[j+4]=y_data.odometry_char[j];
            odometry_data[j+8]=theta_data.odometry_char[j];
            odometry_data[j+12]=vel_linear.odometry_char[j];
            odometry_data[j+16]=vel_angular.odometry_char[j];
        }
    
        odometry_data[20]='\n';//添加结束符
    
        //发送数据要串口
        for(i=0;i<21;i++)
        {
            USART_ClearFlag(USART1,USART_FLAG_TC);  //在发送第一个数据前加此句,解决第一个数据不能正常发送的问题             
            USART_SendData(USART1,odometry_data[i]);//发送一个字节到串口 
            while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); //等待发送结束            
        }
    
        main_sta&=0xFE;//执行计算里程计数据步骤
    }

    底盘接收串口发来的速度代码:

    if(USART_RX_STA&0x8000)  // 串口1接收函数
    {           
        //接收左右轮速度
        for(t=0;t<4;t++)
        {
            rightdata.data[t]=USART_RX_BUF[t];
            leftdata.data[t]=USART_RX_BUF[t+4];
        }
    
        //储存左右轮速度
        odometry_right=rightdata.d;//单位mm/s
        odometry_left=leftdata.d;//单位mm/s
    
        USART_RX_STA=0;//清楚接收标志位
    }

    (2)ROS平台串口处理程序

    ROS平台串口处理程序主要写在 base_controller.cpp 文件中。
    
    ROS平台向串口发送速度代码:
    
    void callback(const geometry_msgs::Twist & cmd_input)//订阅/cmd_vel主题回调函数
    {
        string port("/dev/ttyUSB0");    //小车串口号
        unsigned long baud = 115200;    //小车串口波特率
        serial::Serial my_serial(port, baud, serial::Timeout::simpleTimeout(1000)); //配置串口
    
        angular_temp = cmd_input.angular.z ;//获取/cmd_vel的角速度,rad/s
        linear_temp = cmd_input.linear.x ;//获取/cmd_vel的线速度.m/s
    
        //将转换好的小车速度分量为左右轮速度
        left_speed_data.d = linear_temp - 0.5f*angular_temp*D ;
        right_speed_data.d = linear_temp + 0.5f*angular_temp*D ;
    
        //存入数据到要发布的左右轮速度消息
        left_speed_data.d*=ratio;   //放大1000倍,mm/s
        right_speed_data.d*=ratio;//放大1000倍,mm/s
    
        for(int i=0;i<4;i++)    //将左右轮速度存入数组中发送给串口
        {
            speed_data[i]=right_speed_data.data[i];
            speed_data[i+4]=left_speed_data.data[i];
        }
    
        //在写入串口的左右轮速度数据后加入”/r/n“
        speed_data[8]=data_terminal0;
        speed_data[9]=data_terminal1;
        //写入数据到串口
        my_serial.write(speed_data,10);
    }

    ROS平台接收串口发来的里程计代码:

    rec_buffer =my_serial.readline(25,"\n");    //获取串口发送来的数据
    const char *receive_data=rec_buffer.data(); //保存串口发送来的数据
    展开全文
  • 前两篇里开发环境就位了,今天我们进入树莓派上ROS代码的编写。我们基于ROS构建移动机器人,首先是设计ROS节点计算里程,负责与树莓派ROS的通讯。1. 新建ROS包新建ROS包:打开roboware软件,在左侧的工作空间目录,...
  • ROSSTM32的串口通信

    千次阅读 2018-11-23 10:20:37
    参考上一篇 Ubuntu16之STM32开发–点灯串口通信, 主要代码节选如下: uint8_t count = 0; while (1) { ++count; HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin); printf(&quot;Hello, %3d\r\n&quot...
  • ROS下使用rosserial和STM32(ST库)进行通信,4轮驱动MDK5工程
  • ROSSTM32的串口通信篇 二

    千次阅读 2020-01-06 19:39:00
    ROSSTM32的串口通信 之前写过一篇用boost的串口通信, 本篇写下ros的serial的通信方式. serial安装 sudo apt-get install ros-<distro>-serial, 由于是Ubuntu 18, 那么就是: sudo apt install ros-melodic-...
  • stm32和ros的串口通信

    万次阅读 多人点赞 2020-04-13 17:51:34
    全网最实用的STM32和ROS机器人的串口通信方案
  • 本节内容包括如何实现ros主控和stm32之间的通信,以及ros主控对stm32发送的数据做了哪些处理 一. 两种控制器的功能 1.1 ROS主控实现的功能 ①雷达信息采集 ②摄像头信息采集 ③路径规划 1.2 STM32控制器实现的功能 ...
  • ros系统与stm32f407的串口通信ros系统发布信息,stm32通过串口接收消息,有食用方法。
  • 解决STM32和ROS串口通信问题,代码简单好用,分享给大家
  • ROSSTM32串口通信

    2021-04-18 15:48:24
    ROSSTM32串口通信 对于不是noetic版本的ros来说,是集成了serial功能包的,但是笔者在实践中发现,最新的noetic版本并没有serial功能包,也就是说通过命令 sudo apt install ros-noetic-serial 下载是行不通的=,...
  • ROS和stm32串口通信的代码, 使用asio, 参考我的博客ROSSTM32的串口通信
  • STM32F10x USB 完整通信 亲测可行,从GIT上下载下来的,修改相关source
  • 树莓派4b和stm32f103通信过程 参考资料: 1.ROS的树莓派与stm32的地面移动机器人构建问题 链接1 2.STM32和树莓派串口透传 链接2 3.树莓派串口通信配置教程 链接3
  • stm32ros进行串口通信

    千次阅读 2019-06-08 12:15:12
    最近老师定做了一个气动手抓,手抓的原理简单,主要是通过气泵充气后,通过24v电压控制,进而以通电放电的方式来使手抓闭合张开,此时可以用一个继电器来自动控制手抓电源。 首先分析一下继电器大致原理:如图...
  • ROSSTM32的串口通信篇 二 原创 weifengdq weifengdq 2020-01-06 文章目录 前言 serial安装 STM32工程 ROS程序 微信公众号 前言 ROSSTM32的串口通信 之前写过一篇用 boost的串口通信, 本篇写下 ros的 serial...
  • 本人电子信息工程专业,致力于...本文主要介绍ROS下使用rosserial和STM32(ST库)进行通信,移植网上各位大神的代码,实现自己想要的功能 主要参考:https://www.baidu.com/link?url=HHBcr34K6SbLnst52P-4mSGPKxv...
  • ROSSTM32之间的联系简介ROS主要实现的功能STM32主要实现的功能两者之间的关系两者之间的通信 简介 1、 如何实现ROSstm32之间的通信ROSstm32发送过来的数据做了哪些处理 2、在ROS小车里面有两个核心控制器,...
  • rosstm32串口通信实现

    千次阅读 2018-08-02 11:36:25
    ros/ros.h&gt; #include &lt;serial/serial.h&gt; //ROS已经内置了的串口包 #include &lt;std_msgs/String.h&gt; #include &lt;std_msgs/Empty.h&gt; #include "uart/uartmsg....
  • 序 本文主要发布一些作者从零...一、环境搭建 本人开发环境 ——上位机:MAC主机+PD虚拟机+Ubuntu12.04(64位)+Hydro,底层:STM32F407 先说下为什么是PD虚拟机,现在主流的电脑安装Ubuntu容易出现没有无线网...
  • ROS小车STM32底层控制代码

    千次阅读 多人点赞 2020-08-21 00:50:02
    2.6 ROS小车STM32底层控制代码 经过之前几篇文章,我相信大家一定对下面这些模块都已经...注意:该工程文件中的STM32ROS通信的程序前面写的文章提供的程序,有一点出入,之前是为了方便理解。大家调用的时候注意即
  • 1.msg创建报错 ...检查报错发现是stm32_message_bag.msg报错,开始没有重视,在发现是它报错只是匆匆检查了一下语法关键字有没有错,没发现错误,就去别的地方。再后来回顾报错信息仔细对比,试着将注

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 623
精华内容 249
关键字:

ros和stm32通信