ROS2手写接收IMU数据(Imu)代码并发布

2023-05-16

目录

  • 前言
  • 接收IMU数据
    • IMU的串口连接
      • 问题
    • python接收串口数据
  • python解析数据
  • ROS2发布IMU数据
  • 可视化IMU数据
  • 效果

前言

在前面测试完了单独用激光雷达建图之后,一直想把IMU的数据融合进去,由于经费的限制,忍痛在淘宝上买了一款便宜的IMU—GY95T,如下图所示
在这里插入图片描述

东西买回来了,但是还需要写一个读取数据的代码,商家并没有提供在ROS2上用python接收数据,并且将其转换为ROS2的数据格式的代码,于是自己只能手搓一遍。
读取IMU数据的代码倒是不难,但是要怎么将其转换为ROS2的数据格式是我之前完全没接触到的,把整个流程记录一下,便于回忆。

环境

ROS2 humble
Ubuntu22.04
IMU:GY-95T

我将整个流程分成了以下步骤

串口接收IMU数据
解析IMU数据
ROS2发布IMU数据
利用rviz2可视化检查

接收IMU数据

流程如下 ,利用python打开串口,然后接收数据即可。具体的过程后面一步步写出

IMU的串口连接

首先通过USB将IMU连接到电脑上。用lsusb查看连接到Ubuntu上面的USB设备有哪些,我用的虚拟机测试,所以有一些虚拟机的设备

lsusb
# 返回以下信息

Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 038: ID 1a86:7523 QinHeng Electronics CH340 serial converter
Bus 002 Device 029: ID 0e0f:0008 VMware, Inc. Virtual Bluetooth Adapter
Bus 002 Device 003: ID 0e0f:0002 VMware, Inc. Virtual USB Hub
Bus 002 Device 002: ID 0e0f:0003 VMware, Inc. Virtual Mouse
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

可以看到有一个叫QinHeng Electronics CH340 serial converter的CH340设备,这就是IMU的串口连接设备了,再通过ls指令查看其被映射为了什么端口

ls /dev/ttyUSB*

# 返回
/dev/ttyUSB0

即这里的USB设备被映射为了/dev/ttyUSB0这个文件,后面还会用得上

问题

我在中途遇到了这么一个问题
能够找到USB设备,但是没有被映射为/dev/ttyUSB0的问题

我首先查看了是否存在ch340的驱动

lsmod | grep ch34

# 返回
ch341                  24576  0
usbserial              57344  1 ch341

说明我的虚拟机是存在串口驱动的,但是没有找到设备,那通过这篇博客,我发现了是端口被占用了

Ubuntu22.04没有ttyUSB(无法访问 ‘/dev/ttyUSB‘: 没有那个文件或目录)问题解决

文中所说的方法如下:
sudo dmesg | grep brltty

若出现[ 7033.078452] usb 1-13: usbfs: interface 0 claimed by ch341 while 'brltty' sets config #1 则说明驱动被占用

使用sudo apt remove brltty后,重新插拔设备即可

问题探究到底,这个brltty卸载后会不会对以后使用有影响呢?用chatgpt搜索这个软件后,给出的解释如下:

在Ubuntu中,Brltty 是一个用于盲人和视力受损人士的文本转换工具。它提供了一个用于显示在Braille终端上的用户界面,这些终端通常由触觉读取器件(如盲文显示器)或语音合成器(如屏幕阅读器)使用。
Brltty 可以将文本数据转换成 Braille 码,通过串口或并口将其发送到 Braille 终端。它支持多种不同类型的 Braille 终端,包括常见的 VarioUltra、BrailleNote 和 Focus 14/40。
除了将文本数据转换为 Braille 码之外,Brltty 还提供了一些其他的辅助功能,如语音反馈、支持多国语言、自动检测插入/拔出设备等。

因此对于非盲人和视力受损人士用处不大,因此卸载后无影响

注意:由于串口是具有权限的,为了确保在后续运行python代码的时候具有程序启动串口的权限,我们这里把端口的权限进行更改

sudo chmod 777 /dev/ttyUSB0 

python接收串口数据

在Ubuntu连接了串口之后,我们就可以使用python来读取IMU的数据了

这里用到了python的serial库

sudo apt install python3-serial

为确保读取IMU数据的准确性,我们用python读取串口的方法是,在一个周期下,收取该周期内所有信息,每隔time,将数据返回一次

因此,我们需要按照如下设置我们的串口

# 串口初始化
IMU_Usart = serial.Serial(
   				port = '/dev/ttyUSB0',      # 串口
   				baudrate=115200,            # 波特率
   				timeout = 0.001             # 由于后续使用read按照一个timeout周期时间读取数据
                               # imu在波特率115200返回数据时间大概是1ms,9600下大概是10ms
                               # 所以读取时间设置0.001s
        )
# ----读取IMU的内部数据-----------------------------------
try:
   count = IMU_Usart.inWaiting()
   if count > 0:
       # 接收数据至缓存区
        Read_buffer=self.IMU_Usart.read(40)         # 我们需要读取的是40个寄存器数据,即40个字节
except KeyboardInterrupt:
   if serial != None:
       print("close serial port")
       self.IMU_Usart.close()

#--------------------------------------------------------

其中.inWaiting()函数的作用如下:

用于检查串口缓冲区中等待读取的字节数。
在串口通信中,发送方发送的数据可能需要一定时间才能到达接收方。因此,接收方需要先将接收到的数据存储在缓冲区中,等待读取。.inWaiting() 方法可以用于检查当前串口缓冲区中等待读取的字节数,以便读取相应数量的字节。

我用流程图表述一下代码的读取原理

初始化串口
是否达到一个周期时间
根据真实数据长度读取数据
继续等待

python解析数据

在接收到了IMU传过来的数据之后,我们就需要对其数据进行解析了。

解析这个部分,没有特别多要说的,我是根据卖家给出的数据手册,按照状态机的方式接收并检查数据是否准确。这里把状态机的代码贴出来

def Read_data(self):
        '''
        Author: Liu Yuxiang 
        Time: 2022.12.13
        description: 读取IMU数据
        '''
        # 初始化数据
        counter = 0 
        Recv_flag = 0
        Read_buffer = []
        # 接收数据至缓存区
        Read_buffer=self.IMU_Usart.read(40)         # 我们需要读取的是40个寄存器数据,即40个字节
        # 状态机判断收包数据是否准确
        while(1):
            # 第1帧是否是帧头ID 0xA4
            if (counter == 0):
                if(Read_buffer[0] != 0xA4):
                    break    

            # 第2帧是否是读功能码 0x03  
            elif (counter == 1):
                if(Read_buffer[1] != 0x03):
                    counter=0
                    break

            # 第3帧判断起始帧        
            elif (counter == 2):
                if(Read_buffer[2] < 0x2c):
                    start_reg=Read_buffer[2]
                else:
                    counter=0 

            # 第4帧判断帧有多少数量 
            elif (counter == 3):
                if((start_reg+Read_buffer[3]) < 0x2C): # 最大寄存器为2C 大于0x2C说明数据肯定错了
                    len=Read_buffer[3]
                else:
                    counter=0
                    break                  
                 
            else:
                if(len+5==counter):
                    #print('Recv done!')
                    Recv_flag=1

            # 收包完毕
            if(Recv_flag):
                Recv_flag = 0
                sum = 0
                #print(Read_buffer)                                 # Read_buffer中的是byte数据字节流,用struct包解包
                data_inspect = str(binascii.b2a_hex(Read_buffer))   # data是将数据转化为原本的按照16进制的数据

                try:        # 如果接收数据无误,则执行数据解算操作
                    for i in range(2,80,2):                 # 根据手册,检验所有帧之和低八位是否等于末尾帧
                            sum += int(data_inspect[i:i+2],16)

                    if (str(hex(sum))[-2:] == data_inspect[80:82]): # 如果数据检验没有问题,则进入解包过程
                        #print('the Rev data is right')
                        
                        # 数据低八位在前,高八位在后
                        #print(Read_buffer[4:-1])                       
                        unpack_data = struct.unpack('<hhhhhhhhhBhhhhhhhh',Read_buffer[4:-1])
                        # 切片并将其解析为我们所需要的数据,切出我们所需要的数据部分
                        g = 9.8
                        
                        self.ACC_X  = unpack_data[0]/2048 * g       # unit m/s^2
                        self.ACC_Y  = unpack_data[1]/2048 * g    
                        self.ACC_Z  = unpack_data[2]/2048 * g
                        self.GYRO_X = unpack_data[3]/16.4           # unit 度/s
                        self.GYRO_Y = unpack_data[4]/16.4                
                        self.GYRO_Z = unpack_data[5]/16.4                     
                        self.roll   = unpack_data[6]/100                
                        self.pitch  = unpack_data[7]/100                 
                        self.yaw    = unpack_data[8]/100                          
                        self.level  = unpack_data[9]
                        self.temp   = unpack_data[10]/100 
                        self.MAG_X  = unpack_data[11]/1000          # unit Gaos             
                        self.MAG_Y  = unpack_data[12]/1000           
                        self.MAG_Z  = unpack_data[13]/1000
                        self.Q0     = unpack_data[14]/10000        
                        self.Q1     = unpack_data[15]/10000                 
                        self.Q2     = unpack_data[16]/10000                 
                        self.Q3     = unpack_data[17]/10000
                        #print(self.__dict__) 
                except:
                    print("Have Error in receiving data!!")
                counter=0               
                break
            else:
                counter += 1                        # 遍历整个接收数据的buffer

ROS2发布IMU数据

在跑通了整个读取数据的流程,并与卖家给的上位机返回的数据对比没问题之后,下一步就是需要将数据转换为ROS2的数据格式,并将其发布出来,ROS2中IMU的数据格式类型如下

std_msgs/Header header      # 时间戳和坐标系ID
geometry_msgs/Quaternion orientation # 四元数形式的方向
float64[9] orientation_covariance # 方向估计的协方差矩阵
geometry_msgs/Vector3 angular_velocity # 三维角速度
float64[9] angular_velocity_covariance # 角速度估计的协方差矩阵
geometry_msgs/Vector3 linear_acceleration # 三维线性加速度
float64[9] linear_acceleration_covariance # 线性加速度估计的协方差矩阵
  • header:标准的ROS消息头,包含测量的时间戳和坐标系。
    • 时间戳没有单位,坐标系ID是字符串类型;
  • orientation:以四元数形式表示的IMU传感器的方向,以 geometry_msgs/Quaternion 消息表示。四元数表示从IMU坐标系到由header指定的参考坐标系的旋转。四元数应该被归一化。
    • 四元数表示的方向没有单位;
  • orientation_covariance:一个包含9个元素的数组,表示方向估计的协方差矩阵。矩阵以行优先顺序存储。协方差值应以(x、y、z、x-y、x-z、y-z)的顺序表示。
    • 协方差矩阵是无单位的;
  • angular_velocity:以IMU坐标系表示的IMU传感器的角速度,以 geometry_msgs/Vector3 消息表示。
    • 角速度以弧度/秒(rad/s)为单位;
  • angular_velocity_covariance:一个包含9个元素的数组,表示角速度估计的协方差矩阵。矩阵以行优先顺序存储。协方差值应以(x、y、z、x-y、x-z、y-z)的顺序表示。
    • 角速度估计的协方差矩阵是以 (rad/s)^2 为单位的;
  • linear_acceleration:以IMU坐标系表示的IMU传感器的线性加速度,以 geometry_msgs/Vector3 消息表示。
    • 线性加速度以米/秒²(m/s²)为单位;
  • linear_acceleration_covariance:一个包含9个元素的数组,表示线性加速度估计的协方差矩阵。矩阵以行优先顺序存储。协方差值应以(x、y、z、x-y、x-z、y-z)的顺序表示。
    • 线性加速度估计的协方差矩阵是以 (m/s²)^2 为单位的。

这个IMU是可以直接传回四元数,因此我可以直接进行传参,而不需要再进行四元数转换

注意,这里需要用到ROS2的serial库,但是由于在ROS2 humble中并没有此库,因此,我们需要去下载这个库的源码,并手动安装,安装的教程参考我之前的这篇博客,地址如下:

ROS2安装serial库

这里把完整的代码贴出来

import rclpy                                     # ROS2 Python Client Library
from rclpy.node import Node                      # ROS2 Node
from sensor_msgs.msg import Imu

# Usart Library
import serial
import struct
import binascii

'''
    Author: Liu Yuxiang 
    Time: 2022.12.13
    description: IMU底层串口收发代码
'''


# imu接收数据类型
class IMU(Node):
    send_data = []
    def __init__(self):
        super().__init__('imu_publisher')
        self.publisher_ = self.create_publisher(Imu, 'imu_data', 1)

        # 串口初始化
        self.IMU_Usart = serial.Serial(
            port = '/dev/ttyUSB0',      # 串口
            baudrate=115200,            # 波特率
            timeout = 0.001             # 由于后续使用read_all按照一个timeout周期时间读取数据
                                        # imu在波特率115200返回数据时间大概是1ms,9600下大概是10ms
                                        # 所以读取时间设置0.001s
        )
        # 接收数据初始化
        self.ACC_X:float = 0.0                   # X轴加速度
        self.ACC_Y:float = 0.0                   # Y轴加速度
        self.ACC_Z:float  =  0.0                 # Z轴加速度
        self.GYRO_X :float = 0.0                 # X轴陀螺仪
        self.GYRO_Y :float = 0.0                 # Y轴陀螺仪
        self.GYRO_Z :float = 0.0                 # Z轴陀螺仪
        self.roll :float = 0.0                   # 横滚角    
        self.pitch :float = 0.0                  # 俯仰角
        self.yaw :float = 0.0                    # 航向角
        self.leve :float = 0.0                   # 磁场校准精度
        self.temp :float = 0.0                   # 器件温度
        self.MAG_X :float = 0.0                  # 磁场X轴
        self.MAG_Y :float = 0.0                  # 磁场Y轴
        self.MAG_Z :float = 0.0                  # 磁场Z轴
        self.Q0 :float = 0.0                     # 四元数Q0.0
        self.Q1 :float = 0.0                     # 四元数Q1
        self.Q2 :float = 0.0                     # 四元数Q2
        self.Q3 :float = 0.0                     # 四元数Q3
        # 判断串口是否打开成功
        if self.IMU_Usart.isOpen():
            print("open success")
        else:
            print("open failed")

        # 回调函数返回周期
        time_period = 0.001         
        self.timer = self.create_timer(time_period, self.timer_callback)

        # 发送读取指令
        self.Send_ReadCommand()

    def Send_ReadCommand(self):
        '''
        Author: Liu Yuxiang 
        Time: 2022.12.13
        description: 发送读取IMU内部数据指令
        · 第一个寄存器0x08 最后一个读取寄存器0x2A 共35个
        · 读寄存器例子,读取模块内部温度,主站发送帧为:A4 03 1B 02 C4
            |   A4    |    03    |    1B   |     02    |    C4
            |  帧头ID  | 读功能码 |起始寄存器| 寄存器数量 |校验和低 8 位
        '''
        # 使用优雅的方式发送串口数据
        send_data = [0xA4,0x03,0x08,0x23,0xD2]                      #需要发送的串口包
        #send_data = [0xA4,0x03,0x08,0x1B,0xCA]                      #需要发送的串口包
        send_data=struct.pack("%dB"%(len(send_data)),*send_data)    #解析成16进制
        print(send_data)
        self.IMU_Usart.write(send_data)                             #发送

    def Read_data(self):
        '''
        Author: Liu Yuxiang 
        Time: 2022.12.13
        description: 读取IMU数据
        '''
        # 初始化数据
        counter = 0 
        Recv_flag = 0
        Read_buffer = []
        # 接收数据至缓存区
        Read_buffer=self.IMU_Usart.read(40)         # 我们需要读取的是40个寄存器数据,即40个字节
        # 状态机判断收包数据是否准确
        while(1):
            # 第1帧是否是帧头ID 0xA4
            if (counter == 0):
                if(Read_buffer[0] != 0xA4):
                    break    

            # 第2帧是否是读功能码 0x03  
            elif (counter == 1):
                if(Read_buffer[1] != 0x03):
                    counter=0
                    break

            # 第3帧判断起始帧        
            elif (counter == 2):
                if(Read_buffer[2] < 0x2c):
                    start_reg=Read_buffer[2]
                else:
                    counter=0 

            # 第4帧判断帧有多少数量 
            elif (counter == 3):
                if((start_reg+Read_buffer[3]) < 0x2C): # 最大寄存器为2C 大于0x2C说明数据肯定错了
                    len=Read_buffer[3]
                else:
                    counter=0
                    break                  
                 
            else:
                if(len+5==counter):
                    #print('Recv done!')
                    Recv_flag=1

            # 收包完毕
            if(Recv_flag):
                Recv_flag = 0
                sum = 0
                #print(Read_buffer)                                 # Read_buffer中的是byte数据字节流,用struct包解包
                data_inspect = str(binascii.b2a_hex(Read_buffer))   # data是将数据转化为原本的按照16进制的数据

                try:        # 如果接收数据无误,则执行数据解算操作
                    for i in range(2,80,2):                 # 根据手册,检验所有帧之和低八位是否等于末尾帧
                            sum += int(data_inspect[i:i+2],16)

                    if (str(hex(sum))[-2:] == data_inspect[80:82]): # 如果数据检验没有问题,则进入解包过程
                        #print('the Rev data is right')
                        
                        # 数据低八位在前,高八位在后
                        #print(Read_buffer[4:-1])                       
                        unpack_data = struct.unpack('<hhhhhhhhhBhhhhhhhh',Read_buffer[4:-1])
                        # 切片并将其解析为我们所需要的数据,切出我们所需要的数据部分
                        g = 9.8
                        
                        self.ACC_X  = unpack_data[0]/2048 * g       # unit m/s^2
                        self.ACC_Y  = unpack_data[1]/2048 * g    
                        self.ACC_Z  = unpack_data[2]/2048 * g
                        self.GYRO_X = unpack_data[3]/16.4           # unit 度/s
                        self.GYRO_Y = unpack_data[4]/16.4                
                        self.GYRO_Z = unpack_data[5]/16.4                     
                        self.roll   = unpack_data[6]/100                
                        self.pitch  = unpack_data[7]/100                 
                        self.yaw    = unpack_data[8]/100                          
                        self.level  = unpack_data[9]
                        self.temp   = unpack_data[10]/100 
                        self.MAG_X  = unpack_data[11]/1000          # unit Gaos             
                        self.MAG_Y  = unpack_data[12]/1000           
                        self.MAG_Z  = unpack_data[13]/1000
                        self.Q0     = unpack_data[14]/10000        
                        self.Q1     = unpack_data[15]/10000                 
                        self.Q2     = unpack_data[16]/10000                 
                        self.Q3     = unpack_data[17]/10000
                        #print(self.__dict__) 
                except:
                    print("Have Error in receiving data!!")
                counter=0               
                break
            else:
                counter += 1                        # 遍历整个接收数据的buffer
        
    def timer_callback(self):

        # ----读取IMU的内部数据-----------------------------------
        try:
            count = self.IMU_Usart.inWaiting()
            if count > 0:
                self.Read_data()
                

                # 发布sensor_msgs/Imu 数据类型
                imu_data = Imu()
                imu_data.header.frame_id = "map"
                imu_data.header.stamp = self.get_clock().now().to_msg()
                imu_data.linear_acceleration.x = self.ACC_X
                imu_data.linear_acceleration.y = self.ACC_Y
                imu_data.linear_acceleration.z = self.ACC_Z
                imu_data.angular_velocity.x = self.GYRO_X * 3.1415926 / 180.0  # unit transfer to rad/s
                imu_data.angular_velocity.y = self.GYRO_Y * 3.1415926 / 180.0
                imu_data.angular_velocity.z = self.GYRO_Z * 3.1415926 / 180.0
                imu_data.orientation.x = self.Q0
                imu_data.orientation.y = self.Q1
                imu_data.orientation.z = self.Q2
                imu_data.orientation.w = self.Q3
                self.publisher_.publish(imu_data)             # 发布imu的数据

                # --------------------------------------------------------
                #print('读取中')

        except KeyboardInterrupt:
            if serial != None:
                print("close serial port")
                self.IMU_Usart.close()
        
        #--------------------------------------------------------



def main(args=None):

    # 变量初始化---------------------------------------------    
    rclpy.init(args=args)
    IMU_node = IMU()
    rclpy.spin(IMU_node)
    rclpy.shutdown()


if __name__ == '__main__':
    main()


'''
░░░░░░░░░░░░░░░░░░░░░░░░▄░░
░░░░░░░░░▐█░░░░░░░░░░░▄▀▒▌░
░░░░░░░░▐▀▒█░░░░░░░░▄▀▒▒▒▐░
░░░░░▄▄▀▒░▒▒▒▒▒▒▒▒▒█▒▒▄█▒▐░
░░░▄▀▒▒▒░░░▒▒▒░░░▒▒▒▀██▀▒▌░
░░▐▒▒▒▄▄▒▒▒▒░░░▒▒▒▒▒▒▒▀▄▒▒░
░░▌░░▌█▀▒▒▒▒▒▄▀█▄▒▒▒▒▒▒▒█▒▐
░▐░░░▒▒▒▒▒▒▒▒▌██▀▒▒░░░▒▒▒▀▄
░▌░▒▄██▄▒▒▒▒▒▒▒▒▒░░░░░░▒▒▒▒
▀▒▀▐████▌▄░▀▒▒░░░░░░░░░░▒▒▒
狗狗保佑代码无bug!
'''

其实最关键的部分就是对其进行一个赋值并发布出去即可。

可视化IMU数据

当我们有了数据之后,我们希望对其进行可视化,这样能够非常直观的看到我们的数据,并且符不符合ROS2的数据格式,因此,我们接下来用rviz2来可视化

首先,需要安装IMU的可视化工具,imu-tools

sudo apt install ros-humble-imu-tools

注意:如果你的ROS2的不是humble版本,就将其改为你自己的版本即可

安装完毕后,运行节点,并开启rviz2,点击add,在By topic中添加Imu就可以可视化IMU数据啦

效果

请添加图片描述

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

ROS2手写接收IMU数据(Imu)代码并发布 的相关文章

  • Camera-IMU联合标定原理

    Camera IMU联合标定原理 一 相机投影模型二 IMU 模型三 Camera IMU标定模型 一 相机 IMU旋转 二 相机 IMU平移 三 视觉惯性代价函数 四 camera imu联合标定 一 粗略估计camera与imu之间时间
  • IMU+GPS

    GPS 43 IMU 介绍 xff08 熟悉的略过 xff09 IMU校准姿态估算数据融合 介绍 xff08 熟悉的略过 xff09 GPS GlobalPositioningSystem xff1a 指美国国防部研制的全球定位系统 用户设
  • 在ROS2中,通过MoveIt2控制Gazebo中的自定义机械手

    目前的空余时间主要都在研究ROS2 xff0c 最终目的是控制自己用舵机组装的机械手 由于种种原因 xff0c 先控制Gazebo的自定义机械手 先看看目前的成果 左侧是rviz2中的moveit组件的机械手 xff0c 右侧是gazebo
  • BetaFlight深入传感设计之三:IMU传感模块

    BetaFlight深入传感设计之三 xff1a IMU传感模块 1 HwPreInit HwInit阶段1 1 业务HwPreInit gyroPreInit1 2 业务HwInit gyroInit amp accInit1 2 1 g
  • 星网宇达(惯导+IMU)设备实现自动采点

    一 创建和打开gps Road txt文件 xff0c 准备往里写数据 FILE span class token operator span p span class token operator 61 span span class t
  • 优化IMU数据避免突变的建议

    影响IMU数据变化的主要因素是应力 温度和电气干扰 xff1b xff11 温度的的骤升 xff0c 比如芯片的位置附件有相关器件几秒钟工作一次 xff0c 此时温度骤升 xff0c 可能会引起数据也发生突变 xff0c 周围有变化的热源和
  • 利用 imu_utils 标定 imu

    目录 前言 一 安装 imu utils 二 编译出现的错误 三 操作步骤 四 结果 前言 记录利用 imu utils 标定 imu xff0c 最近在使用imu做导航 xff0c 要对imu进行标定 xff0c 使用标定得到的加速度的噪
  • IMU 测量模型和运动学模型

    一 概念 高斯白噪声 测量噪声是AD转换器件引起的外部噪声 xff0c 波动激烈的测量白噪声 随机游走 这里指零偏Bias 随机游走噪声 xff0c 是传感器内部机械 温度等各种物理因素产生的传感器内部误差的综合参数 xff0c 是变化缓慢
  • ROS2话题入门

    1 订阅发布模式 一个节点发布数据到某个话题上 xff0c 另外一个节点就可以通过订阅话题拿到数据 除了上述这种一个节点发布 xff0c 一个节点接受的形式外 xff0c ROS2话题通信其实还可以是1对n xff0c n对1 xff0c
  • ROS2 + Qt5 cmake的CMakeLists.txt文件配置

    ROS2 QT实现学习笔记 1 1 功能包的创建和编译 ROS2 Foxy 43 Qt5 on Linux Platform 按上面两个文章配置后的目录结构 build CMakeLists txt include mainwindow h
  • 一文了解IMU原理、误差模型、标定、惯性传感器选型以及IMU产品调研(含IMU、AHRS、VRU和INS区别)

    在此记录一下测试IMU过程中的其它文章 xff0c 便于以后查看 xff1a IMU的误差标定以及姿态解算ROS下通过USB端口读取摄像头数据 包括笔记本自带摄像头 激光 摄像头 IMU等传感器数据同步方法 message filters
  • ros1 bag to ros2 bag play

    有个问题是 ros1格式的bag需要转到ros2格式的bag 怎么弄 需要注意的是 这里只能提供标准信息的rosbag转换 如果带有自定义msg的rosbag 应该是不可以的 请注意一下 解决办法 安装依赖 sudo apt install
  • Ubuntu 22.04 LTS安装ROS2 (ros-humble-desktop)

    本文记录Ubuntu 22 04虚拟机上安装ROS2的过程以及遇到的问题 1 确定Ubuntu和ROS版本 Ubuntu和ROS2存在一个版本的对应关系 具体可以看官网的这个页面 REP 2000 ROS 2 Releases and Ta
  • ROS2中创建 Python 和 C++包

    创建 Python 包 在本教程中 您将学习如何创建和设置 ROS2 Python 包 我将向您展示每一步 并解释文件之间的关系 在哪里编写节点 如何添加启动文件等 设置 ROS2 Python 包 Python包内文件说明 package
  • MoCaPose:在宽松服装中实现动作捕捉

    动作姿态是人类个体活动和互动的基本信息来源 采集人们的动作信息能实现了解 分析日常生活等功能 尽管在宽松服装上可以使用IMU实现动作捕捉 但由于需要将大量IMU并将其节点牢固 精确地固定在特定的身体位置 因此并不适合许多现实生活中的应用 这
  • 四元素与旋转矩阵

    如何描述三维空间中刚体的旋转 是个有趣的问题 具体地说 就是刚体上的任意一个点P x y z 围绕过原点的轴 i j k 旋转 求旋转后的点P x y z 旋转矩阵 旋转矩阵乘以点P的齐次坐标 得到旋转后的点P 因此旋转矩阵可以描述旋转 x
  • IMU姿态计算

    总述 IMU即惯性测量单元 主要用于对机体的加速度与角速度的测算 使用场景很多 例如 平衡车 惯性导航等等 姿态 姿态角 Euler angles 是用于描述物体在三维空间中的旋转姿态的一种表示方法 它由三个角度组成 通常表示物体绕三个轴
  • IMU用于上肢功能评估

    来自日本团队牵头研究揭示了利用九轴运动传感器评估上肢Fugl Meyer FMA 的潜力 该探索侧重于将惯性测量单元 IMU 集成到 FMA 的方法中 并探究是否可以出现标准化和更客观的测量 从而解决动态运动评估中的一个紧迫问题 九轴 IM
  • ros2 基础学习14-- Launch:多节点启动与配置脚本

    到目前为止 每当我们运行一个ROS节点 都需要打开一个新的终端运行一个命令 机器人系统中节点很多 每次都这样启动好麻烦呀 有没有一种方式可以一次性启动所有节点呢 答案当然是肯定的 那就是Launch启动文件 它是ROS系统中多节点启动与配置
  • gazebo(fortress) set the path of sdf file

    This method only satisfied with gazebo fortress not harmenic

随机推荐

  • Server Error in '/' Application. 解决办法

    Server Error in 39 39 Application Access to the path 39 E NetWeb2 Content upFile BClientExcel 大客户部通讯录导入 xlsx 39 is denie
  • easyui-datagrid 数据出不来(样式引起的bug)

    今天任务是需要从另一个项目中将某几个功能页面移植到现有的项目中 这是比较繁琐的功能 理解要移植功能的逻辑 xff08 业务逻辑 xff0c 涉及到的表和存储过程 xff09 页面样式 这么是我遇到的一个问题之一 xff1b 我需要展现一个e
  • c#切割字符串几种方法

    1 xff0c 按单一字符切割 string s 61 34 abcdeabcdeabcde 34 string sArray 61 s Split 34 c 34 oreach string i in sArray Console Wri
  • Linux

    一 常用操作以及概念 快捷键求助关机PATHsudo包管理工具发行版VIM 三个模式GNU开源协议 二 磁盘 磁盘接口磁盘的文件名 三 分区 分区表开机检测程序 四 文件系统 分区与文件系统组成文件读取磁盘碎片blockinode目录日志挂
  • 动态链接库与静态链接库的区别

    静态链接库与动态链接库都是共享代码的方式 xff0c 如果采用静态链接库 xff0c 则无论你愿不愿意 xff0c lib 中的指令都全部被直接包含在最终生成的 EXE 文件中了 但是若使用 DLL xff0c 该 DLL 不必被包含在最终
  • ssm——小学期实训总结

    实训总结 经过这两个星期短暂的学习 xff0c 我学习了ssm的框架搭建与web前端设计基础 在第一个星期 xff0c 老师着重为我们讲了框架的原理 搭建与运用 xff1b 而在第二个星期 xff0c 重点则转移到了小组对项目的开发与研究上
  • ROS TF原理和使用方法

    ROS TF介绍 一 TF是什么 xff1f 1 TF是ROS的一个包 xff08 package xff09 2 TF能让用户随时记录各种坐标系之间的变换关系 3 TF能让用户在一个坐标系中进行坐标运算 xff0c 并将转换关系后的位置关
  • 分布式系统核心—日志

    分布式系统的核心组件 日志 有时也叫write ahead logs commit logs 或者事物 logs 通常指在应用所有的修改之前先写入日志 xff0c 一般会将重放日志 撤销日志都写进去 NoSQL数据库 KV存储 Hadoop
  • Linux 下常见的进程调度算法

    进程调度 xff1a 在操作系统中调度是指一种资源分配 调度算法是指 根据系统的资源分配策略所规定的资源分配算法 操作系统管理了系统的有限资源 xff0c 当有多个进程 或多个进程发出的请求 要使用这些资源时 xff0c 因为资源的有限性
  • Ubuntu18.04更换内核方法(原内核版本 4.15.0-38-generic)

    以下过程全部在root权限下操作 xff08 sudo su xff09 1 安装必备软件编译工具 xff1a apt get install libncurses5 dev build essential kernel package 注
  • Mac下使用Java反编译工具JD-GUI

    下载 下载JD GUI 我们选择 Mac 版的 jd gui osx 1 6 6 tar 下载解压打开即可使用 xff0c 不出意外的话出意外了 竟然提示我没有找到Java 版本 xff0c 我直接zsh 命令行下执行查看 java ver
  • Android 中使用Lambda表达式

    Android Studio默认使用Lambda表达式是会报错的 xff0c 即使你使用的是java 8 xff0c 为了在android studio中使用lambda表达式 xff0c 我们必须借助一个插件retrolambda xff
  • 树莓派安装ros系统

    导语 最近给树莓派安装了ros系统 xff0c 这里记录一下 步骤 xff1a 1 下载ros系统的软件 这里推荐从ubiquityrobotics下载ubiquityrobotics 的系统 这个相当于是给你下载了ubuntu16 04和
  • 嵌入式软件工程师相关的应聘要求

    本文收集从网上找到的嵌入式软件工程师岗位相关的职位要求 xff0c 与自身能力进行对比 xff0c 找出不足 xff0c 查漏补缺 xff0c 为18年的跳槽做好准备 1 嵌入式软件工程师杭州 浙江大华技术股份有限公司 职位描述 xff1a
  • docker无法访问localhost的一种解决方法

    如果你使用的不是toolbox xff0c 可以关掉这个页面了 如果你使用的是toolbox xff0c 请使用192 168 99 100加你的的接口 因为toolbox使用了virtualbox虚拟机 xff0c 相当于包了一层 xff
  • VCC、VDD、VEE、VSS等有关电源标注的区别

    Almost all integrated circuits ICs have at least two pins which connect to the power rails of the circuit they are insta
  • Linux内核学习(三)应用层和内核

    目录 写在前面整体环境学习笔记操作系统和内核简介 96 printf 96 和 96 prinfk 96 应用层对内核的调用从例子看原理 应用层的 96 write 96 如何调用内核中的 96 write 96 调用过程实践实现原理学习笔
  • ROS2安装serial库

    场景及问题描述 xff1a 今天在使用ros2读取IMU数据的时候 xff0c 他需要用到一个serial的包 xff0c 由于我使用的是Ubuntu20 04 43 ROS2humble xff0c 并且没有安装这个包 xff0c 所以出
  • 滚动校验(Rolling Checksum)算法

    滚动校验 Rolling Checksum 算法 Rsync中使用了一种滚动检验 Rolling Checksum 算法 xff0c 用于快速计算数据块的检验值 它是一种弱校验算法 xff0c 采用的是Mark Adler的adler 32
  • ROS2手写接收IMU数据(Imu)代码并发布

    目录 前言接收IMU数据IMU的串口连接问题 python接收串口数据 python解析数据ROS2发布IMU数据可视化IMU数据效果 前言 在前面测试完了单独用激光雷达建图之后 xff0c 一直想把IMU的数据融合进去 xff0c 由于经