PS:本文需要的先行知识请自行补充
本文用linux的I2c_dev,去对I2C设备进行操作(open/read/write/close),实现部署于ROS中,并结合ROS特性完成于MPU9250的通讯
linux-I2C
代码需包含的头文件:
1 2 3 4 5 6 7 8
| #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <linux/i2c.h> #include <linux/i2c-dev.h>
|
开启I2C并进行初始化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| fd = open(I2C_DEV,O_RDWR); if(fd < 0) { // printf("open %s failed\n",I2C_DEV); std::stringstream ss; ss << "Failed to open " << I2C_DEV << " device"; throw std::runtime_error(ss.str()); } int ret = ioctl(fd,I2C_SLAVE,Device_Address); if(ret < 0) { // printf("setenv address faile ret: %x \n", ret); throw std::runtime_error("Failed to set I2C address"); }
|
读写操作:
1 2 3
| ssize_t bytesRead ; bytesRead = write(fd,addr,1); bytesRead = read(fd,buf,6);
|
ROS实现I2C通讯 MPU9250
工程环境:RK3588 + Ubuntu 20.04.2 LTS + ROS-noetic
默认工作空间已建立,环境变量已导入脚本;
创建功能包:catkin_create_pkg myi2C_MPU9250_pkg roscpp rospy std_msgs
MPU9250 BSP代码设计
部分宏定义:
1 2 3 4
| #define I2C_DEV "/dev/i2c-6" #define Device_Address 0x68 #define gravity 9.8
|
定义MPU9250类:
1 2 3 4 5 6 7 8 9 10 11 12 13
| class MPU9250 { public: MPU9250();
void Init(); int8_t MPU9250_SetLPF(int16_t LPF); void MPU9250_Accel_Gyro_Reda(int16_t *AccelGyroData); void MPU9250_Temp_Read(int16_t *TempData); void MPU9250_Set_ZeroBias(); private: int fd; };
|
部分函数封装:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| MPU9250::MPU9250() { fd = open(I2C_DEV,O_RDWR); if(fd < 0) { // printf("open %s failed\n",I2C_DEV); std::stringstream ss; ss << "Failed to open " << I2C_DEV << " device"; throw std::runtime_error(ss.str()); } int ret = ioctl(fd,I2C_SLAVE,Device_Address); if(ret < 0) { // printf("setenv address faile ret: %x \n", ret); throw std::runtime_error("Failed to set I2C address"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| void MPU9250::MPU9250_Accel_Gyro_Reda(int16_t *AccelGyroData) { char addr[1]; char buf[6]; ssize_t bytesRead ;
addr[0] = MPU_ACCEL_XOUTH_REG; bytesRead = write(fd,addr,1); bytesRead = read(fd,buf,6);
AccelGyroData[0] = (int16_t)((buf[0]<<8)|buf[1]); AccelGyroData[1] = (int16_t)((buf[2]<<8)|buf[3]); AccelGyroData[2] = (int16_t)((buf[4]<<8)|buf[5]);
addr[0] = MPU_GYRO_XOUTH_REG; bytesRead = write(fd,addr,1); bytesRead = read(fd,buf,6);
AccelGyroData[3] = (int16_t)((buf[0]<<8)|buf[1]); AccelGyroData[4] = (int16_t)((buf[2]<<8)|buf[3]); AccelGyroData[5] = (int16_t)((buf[4]<<8)|buf[5]); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| void MPU9250::MPU9250_Temp_Read(int16_t *TempData) { char addr[1]; char buf[6]; short data; ssize_t bytesRead ;
addr[0] = MPU_TEMP_OUTH_REG; bytesRead = write(fd,addr,1); bytesRead = read(fd,buf,6); data = (int16_t)((buf[0] << 8) | buf[1]); *TempData = 21.0 + ((float)data / 333.87f); }
|
ROS节点设计
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| #include <ros/ros.h> #include <sensor_msgs/Imu.h> #include <serial/serial.h> #include <std_msgs/String.h> #include <iostream> #include <string> #include <sstream> #include "MPU9250_I2C_pkg/mpu9250.h"
int main(int argc,char **argv) { int16_t accelgyrodata[6] = {0};
MPU9250 mpu9250; ros::init(argc,argv,"Imupublisher"); ros::NodeHandle seuNB; mpu9250.Init();
ros::Publisher tree = seuNB.advertise<sensor_msgs::Imu>("MPU9250_Topic",10);
sensor_msgs::Imu imu_msg;
ros::Rate loop_rate(1); while(ros::ok()) { mpu9250.MPU9250_Accel_Gyro_Reda(accelgyrodata);
imu_msg.header.stamp = ros::Time::now(); imu_msg.header.frame_id = "Imu_frame";
imu_msg.angular_velocity.x = accelgyrodata[3] / 16.4; imu_msg.angular_velocity.y = accelgyrodata[4] / 16.4; imu_msg.angular_velocity.z = accelgyrodata[5] / 16.4;
imu_msg.linear_acceleration.x = accelgyrodata[0] / 8192.0 * gravity; imu_msg.linear_acceleration.y = accelgyrodata[1] / 8192.0 * gravity; imu_msg.linear_acceleration.z = accelgyrodata[2] / 8192.0 * gravity;
tree.publish(imu_msg); loop_rate.sleep(); }
}
|
工程概述
在/dev/ 中可以查询设备的/dev/i2c-* ,选择需要的I2C即可
本例程中使用/dev/i2c-6
功能:
ROS从MPU9250传感器读取加速度计和陀螺仪数据,并以IMU消息的格式通过话题发布这些数据