在STM32中实现ROS节点——Rosserial的用法

2023-05-16

目录

  • 内容介绍
    • 前言
    • 生成要移植到stm32的自定义消息和服务
    • 生成针对stm32的移植库包roslibs
    • 在Mdk中实现C和C++代码混合编译
    • 修改mdk配置
    • 修改stm32 ROS通讯接口驱动
    • 测试
    • 补充说明

内容介绍

本文介绍如何将stm32控制板作为一个单独的ROS节点接入整个机器人ROS系统。

前言

在一个完整的机器人硬件系统中,由于众多传感器接口和实时性的需求,不可避免的需要加入嵌入式控制器,现在的机器人大多使用了分布式ROS系统,这套系统主要基于linux运行,而以stm32为例的大多数嵌入式控制器不支持linux。于是,当工控机想要与stm32进行数据交换时,只能脱离ROS体系采用自定义通讯协议。
那么,能不能在STM32中使用ROS架构呢,答案是肯定的,通过rosserial模块,我们可以把一部分ROS的接口定义移植到STM32中编译,虽然不能实现完整的ROS移植,但是可以把整个STM32控制器作为一个单独的ROS节点加入到ROS系统中,实现消息定义与收发、服务创建等功能。本文接下来将介绍该实现方法。

生成要移植到stm32的自定义消息和服务

在ros工作空间catkin_ws中,我们可以创建自己的包,并在msg和srv目录中加入自己定义的消息和服务,这些消息和服务是STM32与工控机通讯时需要用到的,这样接下来生成roslibs时,就会自动包含这些自定义消息和服务。

生成针对stm32的移植库包roslibs

  1. 下载rosserial_stm32包:进入自己的ROS工作空间src目录,如~/catkin_ws/src,输入
git clone https://github.com/yoneken/rosserial_stm32.git
  1. 编译rosserial_stm32:在~/catkin_ws/目录下输入catkin_make编译新加入的包,之后记得输入source ~/.bashrc使得编译内容生效
cd ~/catkin_ws
catkin_make
source ~/.bashrc
  1. 生成待移植的头文件:
    在工作目录下新建一个文件夹,例如stm32_roslib,然后进入stm32_roslib新建一个Inc文件夹,首字母I要大写。在stm32_roslib目录(不是Inc目录)下执行命令:
cd ~
mkdir -p stm32_roslib/Inc
cd stm32_roslib
rosrun rosserial_stm32 make_libraries.py ./

这将在stm32_roslib/Inc目录下生成一堆文件夹,包含ROS自带的消息和服务,以及catkin_ws下所有包内自定义的消息和服务,均以C++头文件的方式定义,此外,还生成了ros.h、STM32Hardware.h、duration.cpp、time.cpp四个文件。这就是我们需要移植到stm32的项目中混合编译的内容。

注意,这里有两点需要说明:

  • 根据ros版本的不同,在执行make_libraries.py时可能报错SyntaxError: Missing parentheses in call to 'print'. Did you mean print(__usage__)?,这是由于脚本在python3执行,但是python3的语法下print需要加(),我们需要修改rosserial_stm32包下面的make_libraries.py文件
cd ~/catkin_ws/src/rosserial_stm32/src/rosserial_stm32 
vim make_libraries.py

第74行和第81行有两个print,把后面的内容加上括号即可。

# need correct inputs
if (len(sys.argv) < 2):
    print (__usage__)
    exit()

# get output path
path = sys.argv[1]
if path[-1] == "/":
    path = path[0:-1]
print ("\nExporting to %s" % path)
  • Inc下包含的目录很多,但是不一定所有的消息和服务我们在stm32都要用到,可以视情况删除一部分,减少stm32项目体量。

在Mdk中实现C和C++代码混合编译

将上一步生成的Inc文件夹整个拷贝出来,进入windows系统,将Inc文件夹复制到stm32的Mdk项目下面,例如,我们放置在stm32_ros_lib/Inc下。接下来,打开mdk,进入stm32的项目,由于我们生成的Inc下所有的头文件都是C++编写的,所以我们要开启Mdk的c++编译。

一定要注意,这里网上很多文章说应该添加–cpp修改mdk的编译配置,据我测试这么做限制很大,因为这样会让mdk对项目所有文件均采用c++编译器编译,如果你的项目添加了第三方模组,如freertos、虚拟串口VCP等,这些c文件都会编译报错。

兼容性最好的方法应该是采用mdk的c/c++混合编译模式,因为默认情况下,mdk会通过文件扩展名来选择对应的编译器,.c文件会用c编译器,.cpp文件会采用c++编译器,所以我们应该利用cpp文件,将所有与ROS有关的内容都写到单独的cpp文件(如rosserial_lib.cpp)里,然后在头文件rosserial_lib.h中将cpp的函数声明用extern C包装一下,其它c文件中即可使用#include rosserial_lib.h来包含cpp文件的内容了,至于cpp中调用其它c文件内容,本来就是向下兼容的,所以无需烦恼。

具体来说,我们综合freertos的任务架构以及ROS节点的while循环写法,将ROS移植相关内容都放在同一个freertos任务中。
首先是rosserial_lib.h文件:

#ifndef ROSSERIAL__H_
#define ROSSERIAL__H_

#ifdef __cplusplus
 extern "C" {
#endif

void RosserialSetup(void);
void RosserialLoop(void);

#ifdef __cplusplus
}
#endif
#endif 

这里我们定义了两个函数,分别是节点初始化函数RosserialSetup(void)和节点循环函数RosserialLoop(void)

其次是freertos的任务,我们创建了一个ControlTask的任务,在进入无限循环前先执行节点初始化函数RosserialSetup(void),然后再无限循环中执行RosserialLoop(),注意到这里是通过#include "rosserial_lib.h",来调用C++函数RosserialSetup(void)RosserialLoop(void),由于在头文件中加入了extern "C",这种调用编译器是不会报错的。

#include "rosserial_lib.h"
void ControlTask(void *argument) {
  osDelay(500);
  RosserialSetup();
  osDelay(500);
  for(;;) {
    RosserialLoop();
  }
}

接下来,我们介绍和分析rosserial_lib.cpp里面两个函数的具体实现。如下代码所示,这是一段stm32中ROS节点的具体实现示例,ros.h是ros功能的核心头文件,std_msgs/String.h是ros自带的标准消息头文件,ts_vision_ctrl/final_data.h是用户自定义消息头文件,这些都包含在之前生成的Inc文件夹内。

基本写法和标准ROS节点类似,只是语法有些微区别,同样是定义nodehandle类、消息收发类型、接收消息回调函数,在 RosserialSetup(void)函数中进行节点初始化,注册需要收发的消息和服务,在RosserialLoop(void)函数中进行节点消息的更新发送,编写相关控制代码,最后执行nh.spinOnce()来响应各种回调函数(这里不能用spin(),否则任务循环会被阻塞)。注意由于RosserialLoop()函数本身在freertos的任务无限循环中执行,所以RosserialLoop()函数内部不再需要while循环。

#include "rosserial_lib.h"
#include "cmsis_os.h"
#include <ros.h>
#include <std_msgs/String.h>
#include <ts_vision_ctrl/final_data.h>

void command_callback(const std_msgs::String &rxbuff);
ros::NodeHandle nh;

std_msgs::String stm32_to_pc_word;
ts_vision_ctrl::final_data my_data;

ros::Subscriber<std_msgs::String> cmd_sub("pc_to_stm32", command_callback);
ros::Publisher publisher("stm32_to_pc", &stm32_to_pc_word);
ros::Publisher my_pub("stm32_my_data", &my_data);

void command_callback(const std_msgs::String &rxbuff) {
  stm32_to_pc_word = rxbuff;
  publisher.publish(&stm32_to_pc_word);
}

void RosserialSetup(void) {
  nh.initNode();
  nh.advertise(publisher);
  nh.advertise(my_pub);
  nh.subscribe(cmd_sub);
  my_data.heading = 3.5;
  my_data.x = 1.23;
  my_data.y = 2.56;
  my_data.header.frame_id = "position";
  my_data.header.seq = 0;
}

void RosserialLoop(void) {
  static int i = 0;
  my_data.header.seq = i;
  i++;
  my_pub.publish(&my_data);
  nh.spinOnce();
  osDelay(20);
}

修改mdk配置

在Mdk宏定义中加入,__USE_C99_MATH,这样可以避免roslib编译错误
在这里插入图片描述
在include paths中加入…/stm32_ros_lib/Inc目录
在这里插入图片描述
在左边project项目名称右键,选择Manage Project Items,在Groups新建一个组别,如RosLibs,添加早先用make_libraries.py生成Inc文件夹下的四个文件:ros.h、STM32Hardware.h、duration.cpp、time.cpp。其实两个头文件加不加都可以,我们只需要修改STM32Hardware.h的内容完成移植。
在这里插入图片描述

修改stm32 ROS通讯接口驱动

打开STM32Hardware.h文件,STM32Hardware.h中的类STM32Hardware会在node_handle.h中调用
需要在这个类中实现read()write()的公共方法。这里就和stm32的硬件接口相关了,由于我们用的是rosserial,所以这里将会调用stm32的串口驱动与工控机进行通讯。

class STM32Hardware {
protected:
public:
  STM32Hardware() {}

  void init() {}

  int read() {
    if (Uart_Available()) {
      return Uart_Read();
    } else {
      return -1;
    }
  }

  void flush(void) {}

  void write(uint8_t *data, int length) { Uart_Write(data, length); }

  unsigned long time() { return HAL_GetTick(); } 
protected:
};

我们需要实现三个函数,分别是int read()、 void write(uint8_t *data, int length)以及unsigned long time()。其中read函数返回值是一个整型,其实是每次读取并返回一个字节,write函数每次则是发送长度为length的字节数组。为此,最好为串口配置一个接收环形缓冲区,每次串口接收到数据,就写入环形缓冲区。read()函数首先调用Uart_Available()函数,判断环形缓冲区是否有数据,如果有,就通过Uart_Read()函数从环形缓冲区读取一个字节并返回这个字节。

下面的代码是最简单的环形缓冲区实现,仅供参考,实际应用时,应考虑多任务对全局变量操作时可能产生的竞争冒险现象,添加信号量等同步机制。至于串口数据接收写入环形缓冲区,是在串口中断里面实现的。

int Uart_Available(void) {
  return ((uint32_t)(UART_RX_DATA_SIZE + uart_rxBufPtrIn - uart_rxBufPtrOut)) %
         UART_RX_DATA_SIZE;
}

//从接收缓冲区中读取
int Uart_Read(void) {
  // if the head isn't ahead of the tail, we don't have any characters
  if (uart_rxBufPtrIn == uart_rxBufPtrOut) {
    return -1;
  } else {
    unsigned char ch = uart_rxBuffer[uart_rxBufPtrOut];
    uart_rxBufPtrOut = (uint16_t)(uart_rxBufPtrOut + 1) % UART_RX_DATA_SIZE;
    return ch;
  }
}
//通过usb_vcp向外发送
void Uart_Write(uint8_t *Buf, uint16_t Len) {
  while (UART2_Transmit(Buf, Len) != HAL_OK) {
    osDelay(1);
  }
}

最后是time()函数,需要提供一个毫秒计数的系统时间,一般我们的freertos系统节拍都是1ms,因此直接返回HAL_GetTick()即可 ,这个函数返回的是32位的毫秒计数,超时时间很长,不用担心溢出问题。

测试

至此,stm32全部的ROS移植就完成了,将stm32项目编译后下载,然后将其对应的串口接入工控机,在工控机中执行

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

注意上述ttyUSB0 要改成实际识别的串口名,波特率也要和stm32中设置的波特率匹配。如果一切正常,可以看到输出信息

[INFO] [1661936312.766461]: ROS Serial Python Node
[INFO] [1661936312.784234]: Connecting to /dev/ttyUSB0 at 115200 baud
[INFO] [1661936314.895818]: Requesting topics...
[INFO] [1661936314.915546]: Note: publish buffer size is 1024 bytes
[INFO] [1661936315.080871]: Setup publisher on odom [nav_msgs/Odometry]
[INFO] [1661936315.179145]: Setup publisher on imu [sensor_msgs/Imu]
[INFO] [1661936316.061922]: Setup publisher on /tf [tf/tfMessage]
[INFO] [1661936316.073155]: Note: subscribe buffer size is 1024 bytes
[INFO] [1661936316.077387]: Setup subscriber on cmd_vel [geometry_msgs/Twist]
...
...

此时,整个stm32嵌入式系统已经作为一个ROS节点运行在ROS系统内了,之后新打开一个终端,执行rostopic list,可以看到相关的收发消息

gm@controlboard:~$ rostopic list
/cmd_vel
/diagnostics
/imu
/odom
/rosout
/rosout_agg
/tf

补充说明

以上内容是基于stm32的标准串口实现,但是实际使用时,由于ROS数据传输量较大,标准串口的带宽不够用,因此大部分情况下,我们都使用STM32的usb虚拟串口VCP来取代标准串口,VCP带宽就完全能够满足ROS的常用需求了,下一篇文章,我们将详细介绍如何结合虚拟串口来实现Rosserial功能。

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

在STM32中实现ROS节点——Rosserial的用法 的相关文章

  • STM32用一个定时器执行多任务写法

    文章目录 main c include stm32f4xx h uint32 t Power check times 电量检测周期 uint32 t RFID Init Check times RFID检测周期 int main Timer
  • STM32 GPIO工作原理详解

    STM32 GPIO介绍 1 STM32引脚说明 GPIO是通用输入 输出端口的简称 是STM32可控制的引脚 GPIO的引脚与外部硬件设备连接 可实现与外部通讯 控制外部硬件或者采集外部硬件数据的功能 以STM32F103ZET6芯片为例
  • 解决KEIL编译慢问题

    两种方案 使用v6版本的ARM Compiler 如果v6版本编译不过 必须使用v5版本的 则可以勾选掉Browse Information选项 提升很明显 1分多钟能优化到几秒 看代码量 但是这个有个弊端 在KEIL中会影响函数跳转 建议
  • 串口通讯第一次发送数据多了一字节

    先初始化IO再初始化串口 导致第一次发送时 多出一个字节数据 优化方案 先初始化串口再初始化IO 即可正常通讯
  • 1.69寸SPI接口240*280TFT液晶显示模块使用中碰到的问题

    1 69寸SPI接口240 280TFT液晶显示模块使用中碰到的问题说明并记录一下 在网上买了1 69寸液晶显示模块 使用spi接口 分辨率240 280 给的参考程序是GPIO模拟的SPI接口 打算先移植到FreeRtos测试 再慢慢使用
  • 在 ROS - Python 中使用来自多个主题的数据

    我能够显示来自两个主题的数据 但无法在 ROS 中实时使用和计算这两个主题的数据 用 Python 代码编写 您有想法存储这些数据并实时计算吗 谢谢 usr bin env python import rospy import string
  • ROS 从 python 节点发布数组

    我是 ros python 的新手 我正在尝试从 python ros 节点发布一个一维数组 我使用 Int32MultiArray 但我无法理解多数组中布局的概念 谁能给我解释一下吗 或者还有其他方式发布数组吗 Thanks usr bi
  • 可以在catkin工作区之外创建ROS节点吗?

    我想在catkin工作区之外创建一个ROS发布者节点 可以创建吗 当然可以 像对待任何其他 cpp 库或 python 包一样对待 ROS 在Python中你必须保留PYTHONPATH环境变量指向ros包 opt ros kinetic
  • Freertos低功耗管理

    空闲任务中的低功耗Tickless处理 在整个系统运行得过程中 其中大部分时间都是在执行空闲任务的 空闲任务之所以执行 因为在系统中的其他任务处于阻塞或者被挂起时才会执行 因此可以将空闲任务的执行时间转换成低功耗模式 在其他任务解除阻塞而准
  • for循环延时时间计算

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 前言 一 pandas是什么 二 使用步骤 1 引入库 2 读入数据 总结 前言 之前做led点亮的实验 好像是被delay函数影响了 因为delay参数设置的不对
  • 嵌入式开发--STM32G4系列片上FLASH的读写

    这个玩意吧 说起来很简单 就是几行代码的事 但楞是折腾了我大半天时间才搞定 原因后面说 先看代码吧 读操作 读操作很简单 以32位方式读取的时候是这样的 data IO uint32 t 0x0800F000 需要注意的是 当以32位方式读
  • 从没有中断引脚并且在测量准备好之前需要一些时间的传感器读取数据的最佳方法

    我正在尝试将压力传感器 MS5803 14BA 与我的板 NUCLEO STM32L073RZ 连接 根据 第 3 页 压力传感器需要几毫秒才能准备好读取测量值 对于我的项目 我对需要大约 10 毫秒来转换原始数据的最高分辨率感兴趣 不幸的
  • 嵌入式 C++11 代码 — 我需要 volatile 吗?

    采用 Cortex M3 MCU STM32F1 的嵌入式设备 它具有嵌入式闪存 64K MCU固件可以在运行时重新编程闪存扇区 这是由闪存控制器 FMC 寄存器完成的 所以它不像a b那么简单 FMC 获取缓冲区指针并将数据刻录到某个闪存
  • STM32 上的 ADC 单次转换

    我正在研究 STM32 F103x 上的 ADC 编程 并从最简单的情况 单次转换开始 测量内部温度传感器 连接到 ADC1 的值 并使用 USART 将其发送到 COM 端口 目标似乎很明确 但是当我尝试将源代码下载到闪存时 它不会向 C
  • STM32内部时钟

    我对 STM32F7 设备 意法半导体的 Cortex M7 微控制器 上的时钟系统感到困惑 参考手册没有充分阐明这些时钟之间的差异 SYSCLK HCLK FCLK 参考手册中阅读章节 gt RCC 为 Cortex 系统定时器 SysT
  • PWM DMA 到整个 GPIO

    我有一个 STM32F4 我想对一个已与掩码进行 或 运算的 GPIO 端口进行 PWM 处理 所以 也许我们想要 PWM0b00100010一段时间为 200khz 但随后 10khz 后 我们现在想要 PWM0b00010001 然后
  • 使用 STM32 USB 设备库将闪存作为大容量存储设备

    我的板上有这个闪存IC 它连接到我的STM32F04 ARM处理器 处理器的USB端口可供用户使用 我希望我的闪存在通过 USB 连接到 PC 时被检测为存储设备 作为第一步 我在程序中将 USB 类定义为 MSC 效果很好 因为当我将主板
  • 使用 STM32F0 ADC 单独读取不同的输入

    STM32F072CBU 微控制器 我有多个 ADC 输入 并且希望单独读取它们 STMcubeMX 生成样板代码 假设我希望按顺序读取所有输入 但我无法弄清楚如何纠正这个问题 这篇博文 http blog koepi info 2015
  • ROS中spin和rate.sleep的区别

    我是 ROS 新手 正在尝试了解这个强大的工具 我很困惑spin and rate sleep功能 谁能帮助我了解这两个功能之间的区别以及何时使用每个功能 ros spin and ros spinOnce 负责处理通信事件 例如到达的消息
  • 如何使用一个凉亭同时创建两个地图?

    如下图所示 现在我的gazebo正在运行2个slam gmapping包 首先是 turtlebot slam gmapping 发布到 map 主题 第二个是 slam gmapping 发布到与第一个相同的 map 主题 我想创建一个新

随机推荐

  • 爆一下年终奖

    点击上方 小麦大叔 xff0c 选择 置顶 星标公众号 福利干货 xff0c 第一时间送达 各个公司的年终奖大多尘埃落定了 xff0c 大环境说实话不是很好 xff0c 有人欢喜有人愁 xff0c 汇总了一波 xff0c 大概50位小伙伴的
  • ChatGPT火爆,背后的核心到底是什么?

    点击上方 小麦大叔 xff0c 选择 置顶 星标公众号 福利干货 xff0c 第一时间送达 2022年12月份的时候 xff0c ChatGPT还只是个被人各种撩的聊天工具 但进入2023年后 xff0c 已经向着效率工具迈进了 微软宣布正
  • 不小心当上CTO了

    点击上方 小麦大叔 xff0c 选择 置顶 星标公众号 福利干货 xff0c 第一时间送达 大家好 xff0c 我是小麦 在知乎上看到一篇从创业公司的工程师一路成长为CTO的真实故事 看完我获益匪浅 在这里分享给大家 01 创业初期 在创业
  • 盘点一下电子嵌入式相关的公司

    点击上方 小麦大叔 xff0c 选择 置顶 星标公众号 福利干货 xff0c 第一时间送达 大家好 xff0c 我是小麦 最近入坑电子信息工程专业的表弟问我毕业能去干什么 xff1f 于是在这里盘点了一下电子嵌入式相关的公司 在这里和大家分
  • C# 解析ini类型文件详解

    1 什么是ini文件 INI文件是一种配置文件格式 xff0c 通常用于Windows操作系统中的应用程序中 它是一种文本文件 xff0c 由多个节和键值对组成 xff0c 用于存储应用程序的配置信息 INI文件的特点包括 xff1a IN
  • CAN总线显性电平和隐性电平详解

    相关文章 CAN总线简易入门教程 CAN总线显性电平和隐性电平详解 STM32的CAN总线调试经验分享 CAN 信号线 CAN 传输的两条信号线被称为 CAN H 和CAN L 通电状态 xff1a CAN H xff08 2 5V xff
  • STM32的CAN总线调试经验分享

    相关文章 CAN总线简易入门教程 CAN总线显性电平和隐性电平详解 STM32的CAN总线调试经验分享 文章目录 相关文章背景CAN总线CAN控制器CAN收发器 调试过程硬件排查CAN分析仪芯片CAN控制器调试 总结 背景 最近负责的一个项
  • 我的新副业

    大家好 xff0c 我是麦叔 聊聊我的新副业吧 尝试做了一段时间餐饮 xff0c 差不多有半年时间了 感触很深 在这里和大家分享一下 缘起 去年10月份朋友的店铺转让 xff0c 于是我就盘下来了 店面不大 xff0c 投入也不是很大 xf
  • 螺旋桨拉力

    介绍 螺旋桨拉力计算公式 直径 xff08 米 xff09 X 螺距 xff08 米 xff09 X 桨宽度 xff08 米 xff09 X 转速 xff08 转 秒 xff09 X 经验系数 xff08 0 25 xff09 61 拉力
  • 爆炸了!但YYDS

    正文共 xff1a 2962字 预计阅读时间 xff1a 8分钟 成功发射 xff0c 但在空中爆炸了 这一刻 xff0c 我们都仰望星空 北京时间 4 月 20 日晚 9 点半 xff0c 随着倒计时声音的结束 xff0c 在 Space
  • 赞爆了!Tabby 这款开源工具真的好用!

    点击上方 小麦大叔 xff0c 选择 置顶 星标公众号 福利干货 xff0c 第一时间送达
  • 惠普暗影精灵VMware安装CentOS7显示[此主机支持 Intel VT-x,但 Intel VT-x 处于禁用状态]

    进入BIOS页面开启CPU虚拟化处理技术 电脑开机时按 ESC 键进入系统启动菜单 然后按F10进入BIOS页面 xff0c 开启 处理器虚拟化技术
  • Python的main函数

    在 Python 中 xff0c 程序的入口点通常指的是一个特定的函数 xff0c 即 main 函数 这个函数是程序的起点 xff0c 也是程序的入口 xff0c 通过调用 main 函数 xff0c 程序开始执行 在 Python 中
  • CMakeList静态库多层嵌套问题 undefined reference to

    前言 被一个问题缠绕了很长时间 xff0c 这两天花精力好好研究了一下 xff0c 总算解决了 xff0c 翻过来看 xff0c 就是自己不注意造的很多小问题 我的想法是把一些代码封装起来 xff0c 但是有些部分要求能让现场工作同事有一定
  • gazebo仿真环境中 加入传感器

    1 传感器加入自己的模型中需要那些步骤 1 节点说明 xff0c 链接关系 lt robot name 61 test gt lt link name 61 34 link1 34 gt lt link name 61 34 link2 3
  • 以下为Windows NT 下的32 位C++程序,请计算sizeof 的值

    char str 61 Hello char p 61 str int n 61 10 请计算 sizeof str 61 sizeof p 61 sizeof n 61 答案 6 4 4 void Func char str 100 请计
  • vue实现显示10条数据点击查询看更多

    vue实现显示10条数据点击查询看更多 要求如下 当页面的数据超过10条时只显示10条 且显示 点我查看更多喔 每次点击 页面数据增加10条 思路解析 如题 假设有20条数据 只显示10条 点击查看更多按钮 span class token
  • 433和2.4G无线通信比较

    DSSS 2 4G无线数据传输系统优势 一 很正常的升级换代 xff1a 系统工作的长期稳定性和可靠性 xff0c 是一个无线通信系统最重要的指标 由于一般433兆及915兆产品使用的是低频窄带通信技术 xff0c 它们的工作频率范围很窄5
  • Android adb dumpsys 命令总结

    adb shell dumpsys 有哪些命令可以用 xff0c 可以使用adb shell service list来查看 查看package这个service的帮助信息 adb shell dumpsys package h 查看act
  • 在STM32中实现ROS节点——Rosserial的用法

    目录 内容介绍前言生成要移植到stm32的自定义消息和服务生成针对stm32的移植库包roslibs在Mdk中实现C和C 43 43 代码混合编译修改mdk配置修改stm32 ROS通讯接口驱动测试补充说明 内容介绍 本文介绍如何将stm3