ROS与STM32通信-rosserial

news2024/10/6 18:36:07

文章目录

    • 硬件
      • 接线
    • 软件
      • STM32CubeMX配置
    • rosserial
    • 移植
    • 上位机订阅-下位机发布
      • 上位机订阅
      • 下位机发布
      • 通信
    • 上位机发布-下位机订阅
      • 上位机发布
      • 下位机订阅
      • 通信

硬件

  • STM32F103c8t6
  • OLED(I2C)
  • USB2TTL
  • Stlink

接线

OLED(GPIO模拟I2C)

硬件引脚
OLEDSCLPA4
OLEDSDAPA5

USART1

硬件引脚作用
RXPA9USART1_TX
TXPA10USART1_RX

LED

硬件引脚
LED0PC13
LED1PC15

软件

  • STM32CubeMX
  • Clion

STM32CubeMX配置

  • SYS->Debug->Serial Wire
  • RCC->HSE->Crystal/Ceramic Resonator
  • PC15->OutPut ,Label为LED0
  • PC13->OutPut ,Label为LED1
  • TIM1->Clock Source->Internal Clock
  • 时钟树,时钟设置为72M
  • USART1->Asynchronous Baud Rate: 115200

设置DMA

image-20230727095227292

开启串口中断

image-20230727095301013

rosserial

rosserial是ROS中的一个重要模块,它实现了ROS通信协议与各类嵌入式硬件平台之间的桥接,大大简化了ROS在底层硬件上的移植和应用。rosserial通过消息序列化和常用串行通信接口,实现了ROS主机和嵌入式客户端之间的消息交互,为各种嵌入式平台提供了C++和Python的ROS客户端库,使得在这些硬件上也能方便地使用ROS的通信架构来进行节点管理、话题通信和服务调用。rosserial还支持动态主题和服务,以较小的代码占用实现ROS功能,具有很强的可移植性。因此,rosserial是ROS物联网和机器人应用不可或缺的重要组件,极大地便利了ROS在各类嵌入式系统和小型机器人产品上的移植应用和开发。

rosserial_WIKI

image-20230727103754363

rosserial_stm32 Github地址

本文资源包stm32f103c8t6_rosserial, CSDN资源下载

移植

下载上述资源stm32f103c8t6_rosserial

git clone https://github.com/GHigher12/STM32f103c8t6_rosserial.git

or 直接在CSDN下载

将RosLibs文件夹添加到stm32工作文件里

image-20230727160334430

还有Core文件夹中的mainpp.h , round.h, mainpp.cpp

此时如果用Clion作为开发环境还需要修改CMakeList.txt

包含文件的路径

main.c使用

//...
#include "mainpp.h"
//...
int main(void)
{
//...
  setup();
  while (1)
  {
      loop();
  }
  /* USER CODE END 3 */
}

上位机订阅-下位机发布

上位机订阅

python订阅 demo01_sub_py.py

#! /usr/bin/env python
import rospy
from std_msgs.msg import String

if __name__ == "__main__":
    rospy.init_node("ros_pc_pub")
    pub = rospy.Publisher("pc_to_stm32",String,queue_size=10)
    msg = String()
    msg_front = "ros_2_stm32->"
    count = 0
    rate = rospy.Rate(1)
    while not rospy.is_shutdown():
        msg.data = msg_front + str(count)
        pub.publish(msg)
        rate.sleep()
        rospy.loginfo("发布的数据为:%s",msg.data)
        count += 1

c++订阅 demo01_sub_c.cpp

#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>


void doMsg(const std_msgs::String::ConstPtr &msg)
{
    ROS_INFO("订阅的数据为: %s", msg->data.c_str());
}

int main(int argc, char *argv[])
{

    setlocale(LC_ALL,"");
    ros::init(argc, argv, "ros_pc_sub");
    ros::NodeHandle nh;
    ros::Subscriber sub = nh.subscribe("stm32_to_pc", 10, doMsg);
    ros::spin();
    return 0;
}

安装rosserial_python

sudo apt-get install ros-noetic-rosserial-python

下位机发布

mainpp.cpp

#include <mainpp.h>
#include <ros.h>
#include <std_msgs/String.h>
#include "main.h"

ros::NodeHandle nh;

std_msgs::String stm32_to_pc_word;

ros::Publisher stm32_to_pc("stm32_to_pc", &stm32_to_pc_word);

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart){
  nh.getHardware()->flush();
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
  nh.getHardware()->reset_rbuf();
}
char hello[13] = "hello ros!";
u8 cnt = 0;
void setup(void)
{
    nh.initNode();
	nh.advertise(stm32_to_pc);
}

void loop(void)
{
    cnt+=1;
    sprintf(oledBuf,"stm32_2_ros->%d",cnt);
    OLED_ShowString(0,24,(u8*)oledBuf,16);
    OLED_Refresh();
    stm32_to_pc_word.data = oledBuf;
    HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);
    HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
	HAL_Delay(1000);
	stm32_to_pc.publish(&stm32_to_pc_word);
	nh.spinOnce();
}

编译将程序烧录到stm32中

通信

将usb2ttl连接好usart1,连接电脑

执行下列命令

lsusb
ls /dev/ttyUSB*
sudo chmod 777 /dev/ttyUSB0

image-20230727162511985

启动rosserial_python节点

roscore
rosrun rosserial_python serial_node.py _port:=/dev/ttyUSB0 _baud:=115200

出现以下内容则表示运行正常

[INFO] [1690446448.903399]: ROS Serial Python Node
[INFO] [1690446448.908570]: Connecting to /dev/ttyUSB0 at 115200 baud
[INFO] [1690446451.013146]: Requesting topics...
[INFO] [1690446451.772474]: Note: publish buffer size is 512 bytes
[INFO] [1690446451.774498]: Setup publisher on stm32_to_pc [std_msgs/String]

可使用rostopic echo /stm32_to_pc查看话题

image-20230727163158146

不过这里会出现[ERROR] [1690446652.290474]: Lost sync with device, restarting...报错,导致收发频率不一致,博主现在还没解决,如有读者有解决办法,可在评论留言。

python订阅

cd ~/catkin_ws
source ./devel/setup.bash
rosrun hello_vscode demo01_sub_py.py

image-20230727163637705

c++订阅

cd ~/catkin_ws
source ./devel/setup.bash
rosrun hello_vscode demo01_sub_c

image-20230727163815409

下位机显示

image-20230727165726493

查看rqt_graph

image-20230727163848358

上位机发布-下位机订阅

上位机发布

python发布 demo01_pub_py.py

#! /usr/bin/env python
import rospy
from std_msgs.msg import String

if __name__ == "__main__":
    rospy.init_node("ros_pc_pub")
    pub = rospy.Publisher("pc_to_stm32",String,queue_size=10)
    msg = String()
    msg_front = "ros_2_stm32->"
    count = 0
    rate = rospy.Rate(1)
    while not rospy.is_shutdown():
        msg.data = msg_front + str(count)
        pub.publish(msg)
        rate.sleep()
        rospy.loginfo("发布的数据为:%s",msg.data)
        count += 1

c++发布 demo01_pub_c.cpp

#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
int main(int argc, char *argv[])
{
    setlocale(LC_ALL,"");
    ros::init(argc, argv, "ros_pc_pub");
    ros::NodeHandle nh;
    ros::Publisher pub = nh.advertise<std_msgs::String>("pc_to_stm32", 10);
    std_msgs::String msg;
    ros::Rate rate(1);
    int count = 0;
    ros::Duration(3).sleep();
    while (ros::ok)
    {
        count++;
        std::stringstream ss;
        ss << "ros_2_stm32->" << count;
        msg.data = ss.str();
        pub.publish(msg);
        ROS_INFO("发布的数据为: %s", ss.str().c_str());
        rate.sleep();
        ros::spinOnce();  //处理回调函数
    }
    return 0;
}

下位机订阅

mainpp.cpp

#include <mainpp.h>
#include <ros.h>
#include <std_msgs/String.h>
#include "main.h"
void command_callback( const std_msgs::String& rxbuff);

ros::NodeHandle nh;

std_msgs::String stm32_to_pc_word;

ros::Subscriber<std_msgs::String> cmd_sub("pc_to_stm32", command_callback);

void command_callback(const std_msgs::String &rxbuff)
{
    char oled_rxbuff[128];
    stm32_to_pc_word = rxbuff;
    snprintf(oled_rxbuff, sizeof(oled_rxbuff), "%s", rxbuff.data);
    OLED_ShowString(0,24, (u8*)oled_rxbuff,16);
    OLED_Refresh();
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart){
  nh.getHardware()->flush();
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
  nh.getHardware()->reset_rbuf();
}
void setup(void)
{
    nh.initNode();
	nh.subscribe(cmd_sub);
}

void loop(void)
{
    HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);
    HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
	HAL_Delay(1000);
	nh.spinOnce();
}


通信

python发布

rosrun hello_vscode demo01_pub_py.py

image-20230727165011538

c++发布

rosrun hello_vscode demo01_pub_c

image-20230727165221524

下位机显示

image-20230727165700807

查看rqt_graph

image-20230727165258149

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/800619.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SwipeDelMenuLayout失效:Could not find SwipeDelMenuLayout-V1.3.0.jar

一、问题描述 最近在工作上的项目中接触到SwipeDelMenuLayout这个第三方Android开发库&#xff0c;然后我就根据网上的教程进行配置。这里先说一下我的开发环境&#xff1a;Android Studio版本是android-studio-2020.3.1.24-windows&#xff0c;gradle版本是7.0.2。 首先是在se…

LeetCode53.Maximum-Subarray<最大子数组和>

题目&#xff1a; 思路&#xff1a; 这题不会啊...然后发现题解如此简单, 逐层判断.得到最大值. 每次取得当前的最大值.并且更新结果最大值,结果循环扫描后得到结果 代码是&#xff1a; //codeclass Solution { public:int maxSubArray(vector<int>& nums) {int p…

【HarmonyOS】ArkTS自定义组件如何调用通用属性?

【关键词】 ArkTS、通用属性、 BuilderParam 【问题背景】 有个开发者使用ArkTS自定义了一个子组件AnimationButton&#xff0c;里面用到了装饰器 BuilderParam&#xff0c;在父页面中引用的时候使用自定义组件时&#xff0c;使用以下方式调用&#xff1a; 就报了这个错 【问…

基于双 STM32+FPGA 的桌面数控车床控制系统设计

桌 面数控 设 备 对 小 尺寸零件加工在成 本 、 功 耗 和 占 地 面 积等方 面有 着 巨 大 优 势 。 桌 面数控 设 备 大致 有 3 种 实 现 方 案 : 第 一种 为 微 型 机 床搭 配 传统 数控系 统 &#xff0c; 但 是 桌 面数控 设 备 对 成 本 敏感 ; 第二 种 为 基 于 PC…

《TCP IP网络编程》第十一章

第 11 章 进程间通信 11.1 进程间通信的基本概念 通过管道实现进程间通信&#xff1a; 进程间通信&#xff0c;意味着两个不同的进程中可以交换数据。下图是基于管道&#xff08;PIPE&#xff09;的进程间通信的模型&#xff1a; 可以看出&#xff0c;为了完成进程间通信&…

React入门学习笔记1

前言 React是一个用来动态构0建用户界面的JavaScript库&#xff08;只关注于视图&#xff09;。它可以帮助开发人员轻松地创建复杂的交互式界面&#xff0c;以及管理与用户交互的状态。相比于其他的JavaScript框架&#xff0c;React采用了一种不同的编程模型&#xff0c;称为“…

单片机中的通用LED驱动

前言 项目中需要用到很多的LED灯&#xff0c;存在不同的闪烁方式&#xff0c;比如单闪&#xff0c;双闪&#xff0c;快闪&#xff0c;慢闪等等&#xff0c;我需要一个有如下特性的LED驱动 方便的增加不同闪烁模式可以切换闪烁模式增加LED数目不会有太多的改动方便移植&#x…

《焊接点云处理》-V型焊缝处理

焊接点云处理-V型焊缝处理 前言一、代码二、处理步骤前言 处理效果 一、代码 主函数 #include "CGALRECONSTRUCT.h" #include"PCLFUNCTION.h"int main(int argc

vue+leaflet笔记之地图聚合

vueleaflet笔记之地图聚合 文章目录 vueleaflet笔记之地图聚合开发环境代码简介插件简介与安装使用简介 详细源码(Vue3) 本文介绍了Web端使用Leaflet开发库进行地图聚合查询的一种方法 (底图来源:中科星图)&#xff0c;结合Leaflet.markercluster插件能够快速的实现地图聚合查询…

【C++】做一个飞机空战小游戏(二)——利用getch()函数实现键盘控制单个字符移动

[导读]本系列博文内容链接如下&#xff1a; 【C】做一个飞机空战小游戏(一)——使用getch()函数获得键盘码值 【C】做一个飞机空战小游戏(二)——利用getch()函数实现键盘控制单个字符移动 在【C】做一个飞机空战小游戏(一)——使用getch()函数获得键盘码值一文中介绍了如何利用…

4.4 if选择结构

4.4 if选择结构 if单选择结构 我们很多时候需要去判断一个东西是否可行&#xff0c;然后我们才去执行&#xff0c;这样的一个过程在程序中用if语句来表示 语法 if(布尔表达式){//如果布尔表达式为true将执行的语句 }if单选择结构流程图 package com.baidu.www.struct;import …

JVM源码剖析之JIT工作流程

版本信息&#xff1a; jdk版本&#xff1a;jdk8u40思想至上 Hotspot中执行引擎分为解释器、JIT及时编译器&#xff0c;上篇文章描述到解释器过度到JIT的条件。JVM源码剖析之达到什么条件进行JIT优化 这篇文章大致讲述JIT的编译过程。在JDK中javac和JIT两部分跟编译原理挂钩&a…

MySQL 服务器的调优策略

点击上方↑“追梦 Java”关注&#xff0c;一起追梦&#xff01; 在工作中&#xff0c;我们发现慢查询一般有2个途径&#xff0c;一个是被动的&#xff0c;一个是主动的。被动的是当业务人员反馈某个查询界面响应的时间特别长&#xff0c;你才去处理。主动的是通过通过分析慢查询…

原生html—摆脱ps、excel 在线绘制财务表格加水印(html绘制表格js加水印)

文章目录 ⭐前言⭐html标签&#x1f496;table表格的属性&#x1f496;实现财务报表 ⭐结束 ⭐前言 大家好&#xff0c;我是yma16&#xff0c;本文分享原生html——绘制表格报表加水印。 背景&#xff1a;解决没有ps的情况下使用前端html制作表格报表。 html介绍 HTML&#xf…

【雕爷学编程】Arduino动手做(93)--- 0.96寸OLED液晶屏模块8

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…

C++ inline 内联函数

1.什么是内联函数 在函数声明或定义中&#xff0c;在函数的返回类型前加上C关键字inline&#xff0c;即将函数指定为内联函数。这样可以**解决一些频繁调用的简单函数大量消耗栈空间&#xff08;栈内存&#xff09;**的问题。关键字inline必须与函数定义放在一起才能使函数成为…

C++模拟实现queue

1.前言 queue 遵循的原则是先进先出&#xff0c;那到底是用list 还是 vector呢&#xff1f;其实都可以&#xff0c;但是严格来讲vector是不可以的&#xff0c;因为他头删的效率太低了。所以vs官方是不允许用vector的&#xff1a; 因为底层的pop用的是pop_front(), vector是没有…

【C刷题】矩阵相等判断与序列中删除指定的数字

目录 BC105-矩阵相等判断 方法1:两矩阵输入完毕后&#xff0c;进行比较 方法2:在接收过程中直接比较 BC98 - 序列中删除指定的数字 方法1:把要删除的元素改为0 方法2:打印不用删除的元素 方法3:定义两个下标 i 和 j(动图演示) 此篇文章是关于牛客网刷题的做题思路和代码…

Java版知识付费平台免费搭建 前后端分离实现知识付费平台

提供职业教育、企业培训、知识付费系统搭建服务。系统功能包含&#xff1a;录播课、直播课、题库、营销、公司组织架构、员工入职培训等。 提供私有化部署&#xff0c;免费售后&#xff0c;专业技术指导&#xff0c;支持PC、APP、H5、小程序多终端同步&#xff0c;支持二次开发…

大模型开发(十一):Chat Completions模型的Function calling功能详解

全文共5000余字&#xff0c;预计阅读时间约15~25分钟 | 满满干货(附代码案例)&#xff0c;建议收藏&#xff01; 本文目标&#xff1a;介绍Chat Completions模型的Function calling参数和使用方法&#xff0c;并完整的实现一个Chat模型的Function calling功能案例。 代码下载地…