天天看點

【ROS】ubuntu16.04下HANDSFREE_ROS_IMU調試一、準備工作二、IMU子產品功能包的使用三、IMU功能包代碼解析

【ROS】ubuntu16.04下HANDSFREE_ROS_IMU調試

  • 一、準備工作
    • 1.下載下傳驅動軟體壓縮包
    • 2.安裝 ros_imu能依賴包
    • 3.建立工作空間
    • 4.編譯并設定環境變量
    • 5.檢查是否能檢測到裝置
  • 二、IMU子產品功能包的使用
  • 三、IMU功能包代碼解析
    • 1.hfi_imu_ros.py
    • 2.get_imu_rpy.py

最近在網上購買了ROS機器人IMU子產品ARHS姿态傳感器,購買的型号是HFI-B6,下面是官方給出的資料連結,這種信号的IMU是ROS作業系統專用的,能夠直接讀取目前子產品的角度資訊,并列印出來,而且傳輸速率非常快,相比較于傳統的imu子產品而言,使用起來更加的友善,因為官方已經完成了底層代碼的編寫,我們在使用上不需要考慮通信的問題

連結: https://gitee.com/HANDS-FREE/handsfree_ros_imu/blob/master/tutorials/doc.md.

如果你沒有gitee賬号的話,需要重新注冊一個,才能下載下傳gitee網站上的ROS驅動功能包

【ROS】ubuntu16.04下HANDSFREE_ROS_IMU調試一、準備工作二、IMU子產品功能包的使用三、IMU功能包代碼解析

一、準備工作

1.下載下傳驅動軟體壓縮包

部落客的linux系統是ubuntu16.04,安裝的是ros-kinetic版本,對應的python版本是python2,點選python2右邊的下載下傳驅動軟體壓縮包,即可完成驅動軟體壓縮包的下載下傳

2.安裝 ros_imu能依賴包

打開一個終端,在終端中輸入,這裡是針對kinetic版本的指令,如果你們是其他版本的話,還是安裝官方教程來進行下載下傳安裝

sudo apt-get install ros-kinetic-imu-tools ros-kinetic-rviz-imu-plugin

sudo apt-get install python-visual

3.建立工作空間

在終端中輸入以下指令

mkdir -p ~/handsfree/handsfree_ros_ws/src/

cd ~/handsfree/handsfree_ros_ws/src/

将之前下載下傳好的軟體驅動壓縮包解壓後,提取到 src 目錄下,正常情況下提取出來的壓縮封包件名是handsfree_ros_imu,如果不是請修改成 handsfree_ros_imu

4.編譯并設定環境變量

cd ~/handsfree/handsfree_ros_ws/

catkin_make

cd ~/handsfree/handsfree_ros_ws/src/handsfree_ros_imu/scripts/

sudo chmod 777 *.py

echo “source ~/handsfree/handsfree_ros_ws/devel/setup.bash” >> ~/.bashrc

source ~/.bashrc

5.檢查是否能檢測到裝置

連接配接 IMU 的 USB,檢查電腦能否識别到 ttyUSB0,檢測到 ttyUSB0 後,給 ttyUSB0 賦權限

ls /dev/ttyUSB0

sudo chmod 777 /dev/ttyUSB0

二、IMU子產品功能包的使用

在下載下傳的驅動軟體功能包中,我們可以看到,一共有6個.py檔案,其中,有四個是對應于不同IMU子產品的.py檔案,get_imu_rpy.py檔案是讀取目前子產品的角度資訊值,包括Roll(翻滾角),Pitch(俯仰角)和Yaw(偏航角)

【ROS】ubuntu16.04下HANDSFREE_ROS_IMU調試一、準備工作二、IMU子產品功能包的使用三、IMU功能包代碼解析

如果我們要在終端下實時讀取目前子產品的角度資訊,我們先要将IMU子產品與ubuntu系統連接配接上,打開終端,輸入以下指令

ls /dev/ttyUSB0

sudo chmod 777 /dev/ttyUSB0

然後在終端中輸入roscore,啟動ros_master,重新打開一個終端,在終端中輸入指令rosrun handsfree_ros_imu hfi_b6_ros.py,這裡要根據你購買的IMU子產品的型号進行選擇,然後在重新打開一個終端,在終端中輸入rosrun handsfree_ros_imu get_imu_rpy.py,你就會看到實時列印的角度資訊了

rosrun handsfree_ros_imu hfi_b6_ros.py

rosrun handsfree_ros_imu get_imu_rpy.py

【ROS】ubuntu16.04下HANDSFREE_ROS_IMU調試一、準備工作二、IMU子產品功能包的使用三、IMU功能包代碼解析

相比于其他的一些可視化界面,讀取目前子產品的角度資訊是最重要的,其他相關部分功能的,大家可以自行去官網上進行檢視,如果要使用rviz來進行檢視IMU子產品的變化資訊的話,也可以roslaunch功能包中的其他launch檔案,也很友善

三、IMU功能包代碼解析

1.hfi_imu_ros.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import math
import serial
import struct
import time
import rospy
import serial.tools.list_ports
from geometry_msgs.msg import Quaternion
from sensor_msgs.msg import Imu
from sensor_msgs.msg import MagneticField

cov_orientation = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
cov_angular_velocity = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
cov_linear_acceleration = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]


def eul_to_qua(Eular):
    eular_div = [0, 0, 0]
    eular_div[0], eular_div[1], eular_div[2] = Eular[0] / 2.0, Eular[1] / 2.0, Eular[2] / 2.0

    ca, cb, cc = math.cos(eular_div[0]), math.cos(eular_div[1]), math.cos(eular_div[2])
    sa, sb, sc = math.sin(eular_div[0]), math.sin(eular_div[1]), math.sin(eular_div[2])

    x = sa * cb * cc - ca * sb * sc
    y = ca * sb * cc + sa * cb * sc
    z = ca * cb * sc - sa * sb * cc
    w = ca * cb * cc + sa * sb * sc

    orientation = Quaternion()
    orientation.x, orientation.y, orientation.z, orientation.w = x, y, z, w
    return orientation


# 在緩沖資料中找到第一個包的起始位置
def find_first_package(buffer):
    i = 0
    while True:
        if buffer[i] == 0x55 and (buffer[i + 1] & 0x50) == 0x50:
            return i
        if i + 2 >= len(buffer):
            return -1
        i += 1


# 檢查校驗和
def sb_sum_chech(byte_temp):
    # if(len(byte_temp)==11) :
    if (((byte_temp[0] + byte_temp[1] + byte_temp[2] + byte_temp[3] + byte_temp[4] + byte_temp[5] + byte_temp[6] +
          byte_temp[7] + byte_temp[8] + byte_temp[9]) & 0xff) == byte_temp[10]):
        # print('sum check ok!')
        return True
    else:
        # print('sum check false!')
        return False


# 查找 ttyUSB* 裝置
def find_ttyUSB():
    count = 0
    port_list = []
    for ser in serial.tools.list_ports.comports():
        if str(ser.name).find("USB") == 3:
            print("\033[32m找到了:" + str(ser.name) + " 裝置\033[0m")
            port_list.append(str(ser.name))
        else:
            count += 1
            if count == len(list(serial.tools.list_ports.comports())):
                print("\033[31m沒有找到相關的 ttyUSB* 裝置\033[0m")
                exit(0)
    return port_list

if __name__ == "__main__":
    port_list = find_ttyUSB()
    rospy.init_node("imu")
    port = rospy.get_param("~port", "/dev/ttyUSB0")
    baudrate = rospy.get_param("~baudrate", 921600)
    try:
        hf_imu = serial.Serial(port=port, baudrate=baudrate, timeout=0.5)
        if hf_imu.isOpen():
            rospy.loginfo("\033[32m序列槽打開成功...\033[0m")
        else:
            hf_imu.open()
            rospy.loginfo("\033[32m打開序列槽成功...\033[0m")
    except Exception as e:
        print(e)
        rospy.loginfo("\033[31m序列槽錯誤,其他因素\033[0m")
        exit(0)
        
    else:
        imu_pub = rospy.Publisher("handsfree/imu", Imu, queue_size=10)
        receive_buffer = bytearray()
        linear_acceleration_x = 0
        linear_acceleration_y = 0
        linear_acceleration_z = 0
        angular_velocity_x = 0
        angular_velocity_y = 0
        angular_velocity_z = 0
        data_timeout = 0
        while not rospy.is_shutdown():
            if data_timeout < 1000:
                data_timeout += 1
            else:
                print("\033[31m讀取不到 imu 資料,目前 ttyUSB0 裝置不是 imu\033[0m")
                exit(0)
            eul = []
            try:
                count = hf_imu.inWaiting()
            except Exception as e:
                print(e)
                print ("\033[31mimu 失聯\033[0m")
                exit(0)
            else:
                if count > 0:
                    s = hf_imu.read(count)
                    receive_buffer += s
                stamp = rospy.get_rostime()
                dataLen = len(receive_buffer)
                if dataLen >= 11:
                    # 去掉第1個標頭前的資料
                    headerPos = find_first_package(receive_buffer)
                    if headerPos >= 0:
                        if headerPos > 0:
                            receive_buffer[0:headerPos] = b''
                        # 取 Config.minPackageLen 整數倍長度的資料
                        if dataLen - headerPos >= 11:
                            packageCount = int((dataLen - headerPos) / 11)
                            if packageCount > 0:
                                cutLen = packageCount * 11
                                temp = receive_buffer[0:cutLen]
                                # 按16進制字元串的形式顯示收到的内容
                                receive_buffer[0:cutLen] = b''

                                # 解析資料,逐個資料包進行解析
                                for i in range(packageCount):
                                    beginIdx = int(i * 11)
                                    endIdx = int(i * 11 + 11)
                                    byte_temp = temp[beginIdx:endIdx]
                                    # 校驗和通過了的資料包才進行解析
                                    imu_msg = Imu()
                                    imu_msg.header.stamp = stamp
                                    imu_msg.header.frame_id = "base_link"
                                    mag_msg = MagneticField()
                                    mag_msg.header.stamp = stamp
                                    mag_msg.header.frame_id = "base_link"

                                    if sb_sum_chech(byte_temp):
                                        data_timeout = 0
                                        Data = list(struct.unpack("hhhh", byte_temp[2:10]))
                                        # 加速度
                                        if byte_temp[1] == 0x51:
                                            linear_acceleration_x = Data[0] / 32768.0 * 16 * -9.8
                                            linear_acceleration_y = Data[1] / 32768.0 * 16 * -9.8
                                            linear_acceleration_z = Data[2] / 32768.0 * 16 * -9.8

                                        # 角速度
                                        if byte_temp[1] == 0x52:
                                            imu_msg.orientation_covariance = cov_orientation
                                            angular_velocity_x = Data[0] / 32768.0 * 2000 * math.pi / 180
                                            angular_velocity_y = Data[1] / 32768.0 * 2000 * math.pi / 180
                                            angular_velocity_z = Data[2] / 32768.0 * 2000 * math.pi / 180

                                        # 姿态角
                                        if byte_temp[1] == 0x53:
                                            for i in range(3):
                                                eul.append(Data[i] / 32768.0 * math.pi)

                                            imu_msg.orientation = eul_to_qua(eul)

                                            imu_msg.linear_acceleration.x = linear_acceleration_x
                                            imu_msg.linear_acceleration.y = linear_acceleration_y
                                            imu_msg.linear_acceleration.z = linear_acceleration_z

                                            imu_msg.angular_velocity.x = angular_velocity_x
                                            imu_msg.angular_velocity.y = angular_velocity_y
                                            imu_msg.angular_velocity.z = angular_velocity_z

                                            imu_msg.angular_velocity_covariance = cov_angular_velocity
                                            imu_msg.linear_acceleration_covariance = cov_linear_acceleration

                                            imu_pub.publish(imu_msg)
                time.sleep(0.001)
           

2.get_imu_rpy.py

#!/usr/bin/env python
#coding=UTF-8

import rospy
import tf
from tf.transformations import *
from sensor_msgs.msg import Imu

def callback(data):
    #這個函數是tf中的,可以将四元數轉成歐拉角
    (r,p,y) = tf.transformations.euler_from_quaternion((data.orientation.x,data.orientation.y,data.orientation.z,data.orientation.w))
    #由于是弧度制,下面将其改成角度制看起來更友善
    rospy.loginfo("Roll = %f, Pitch = %f, Yaw = %f",r*180/3.1415926,p*180/3.1415926,y*180/3.1415926)

def get_imu():
    rospy.init_node('get_imu', anonymous=True)
    rospy.Subscriber("/handsfree/imu", Imu, callback) #接受topic名稱
    rospy.spin()

if __name__ == '__main__':
    get_imu()
           

官方使用的是python,編寫了一個釋出者和訂閱者,通過訂閱IMU釋出的資訊,并将其轉換為角度資訊,就得到了目前子產品的排程資訊,這款子產品對于ROS而言,使用起來很友善