【cartographer_ros】五: 发布和订阅陀螺仪Imu信息
上一节介绍了里程计Odometry传感数据的订阅和发布。
本节会介绍陀螺仪Imu数据的发布和订阅。陀螺仪在cartographer中主要用于前端位置预估和后端优化。
目录
1:sensor_msgs/Imu消息类型
在终端查看消息数据结构:
rosmsg show sensor_msgs/Imu
Odometry消息类型数据结构如下:
Header header
geometry_msgs/Quaternion orientation
float64[9] orientation_covariance // Row major about x, y, z axes
geometry_msgs/Vector3 angular_velocity
float64[9] angular_velocity_covariance // Row major about x, y, z axes
geometry_msgs/Vector3 linear_acceleration
float64[9] linear_acceleration_covariance // Row major x, y z
其中linear_acceleration表示线加速度,angular_velocity表示角速度,orientation表示姿态,使用四元数表示。covariance表示对应协方差,体现各个数据的误差
2:发布Imu消息
陀螺仪用的是LPMS-IG1 RS232,这个陀螺仪同时能提供角速度 ,线加速度,和欧拉角。
#include <ros/ros.h>
#include <tf/tf.h>
#include <sensor_msgs/Imu.h>
using namespace std;
unsigned int step = 0;
unsigned int data_i = 0;
unsigned int data_len = 0;
unsigned char handle_buf[2048];
float acc[3];
float gyo[3];
float eular[3];
void DataReceivedCallback(std::vector<unsigned char> &data)
{
unsigned char datasingle1;
for (size_t k = 0; k < data.size(); k++)
{
datasingle1 = data[k];
switch (step)
{
case 0:
{
if (datasingle1 == 0x3A)
{
step = 1;
data_i = 0;
memset(handle_buf, 0, 2048);
}
break;
}
case 1: // sensor id low
{
handle_buf[0] = datasingle1;
step = 2;
break;
}
case 2: // sensor id high
{
handle_buf[1] = datasingle1;
step = 3;
break;
}
case 3: //指令号 low
{
handle_buf[2] = datasingle1;
step = 4;
break;
}
case 4: //指令号 high
{
handle_buf[3] = datasingle1;
step = 5;
break;
}
case 5: //数据长度 low
{
handle_buf[4] = datasingle1;
data_len = datasingle1;
step = 6;
break;
}
case 6: //数据长度 high
{
handle_buf[5] = datasingle1;
data_len += (uint16_t)handle_buf[5] * 256;
if (data_len > 512)
{
step = 0;
cout << " data_len error : " << hex << datasingle1 << ", " << data_len << std::endl;
}
else
{
if (data_len > 0)
{
data_i = 0;
step = 7;
}
else
{
step = 0;
cout << " data_len error : " << hex << datasingle1 << ", " << data_len << std::endl;
}
}
break;
}
case 7:
{
handle_buf[data_i + 6] = datasingle1;
data_i++;
if (data_i >= data_len + 4) //完整一帧
{
//判断包尾
if ((handle_buf[data_len + 8] != 0x0D) && (handle_buf[data_len + 9] != 0x0A))
{
step = 0;
cout << " tail error : " << hex << handle_buf[data_len + 8] << ", " << hex << handle_buf[data_len + 9] << std::endl;
break;
}
uint16_t lrc = ((uint16_t)handle_buf[data_len + 7] * 256) + (uint16_t)handle_buf[data_len + 6];
//判断lrc
uint16_t sum_lrc = 0;
for (unsigned int i = 0; i < (6 + data_len); i++)
{
sum_lrc += handle_buf[i];
}
if (lrc != sum_lrc)
{
step = 0;
cout << " crc error : " << lrc << ", " << sum_lrc << std::endl;
break;
}
//线加速度(含重力)
acc[0] = *((float *)&handle_buf[22]);
acc[1] = *((float *)&handle_buf[26]);
acc[2] = *((float *)&handle_buf[30]);
//角速度(陀螺仪I的输出)
gyo[0] = *((float *)&handle_buf[82]);
gyo[1] = *((float *)&handle_buf[86]);
gyo[2] = *((float *)&handle_buf[90]);
//欧拉角
eular[0] = *((float *)&handle_buf[146]);
eular[1] = *((float *)&handle_buf[150]);
eular[2] = *((float *)&handle_buf[154]);
step = 0;
}
break;
}
default:
break;
}
}
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "Imu_publisher");
ros::NodeHandle n;
ros::Publisher imu_pub = n.advertise<sensor_msgs::Imu>("imu", 50);
string device = "/dev/ttyUSB0";
int baud_rate = 921600;
int data_bits = 8;
int stop_bits = 0;
string parity = "n";
boost::shared_ptr<SerialPort> serialPort;
serialPort.reset(new SerialPort(device, baud_rate, data_bits, stop_bits, parity));
auto binding = bind(&DataReceivedCallback, this, std::placeholders::_1);
serialPort->setcallback(binding);
if (serialPort->Open())
{
serialPort->LoadConfig();
cout << "Init serial open success";
}
else
cout << "Init serial open false";
ros::Rate r(1.0);
while (n.ok())
{
ros::spinOnce();
sensor_msgs::Imu imu;
imu.header.stamp = ros::Time::now();
imu.header.frame_id = "base_link";
imu.linear_acceleration.x = acc[0] * (-9.8);
imu.linear_acceleration.y = acc[1] * (-9.8);
imu.linear_acceleration.z = acc[2] * (-9.8);
imu.angular_velocity.x = gyo[0] * 3.1415926 / 180.0;
imu.angular_velocity.y = gyo[1] * 3.1415926 / 180.0;
imu.angular_velocity.z = gyo[2] * 3.1415926 / 180.0;
imu.orientation = tf::createQuaternionMsgFromRollPitchYaw(eular[0], eular[1], eular[2]);
//发布Imu消息
imu_pub.publish(imu);
last_time = current_time;
r.sleep();
}
}
SerialPort是自定义的串口通信类,附上代码:
3:订阅Imu消息
(1) 通过rosbag订阅
rostopic echo /imu
(2) 通过rviz查看
打开rviz
rosrun rviz rviz
Fixed Frame修改为base_link,添加Imu并将Topic设为/imu
(3) 编写程序打印
#include "ros/ros.h"
#include "sensor_msgs/Imu.h"
void imuCallback(const sensor_msgs::Imu::ConstPtr &msg)
{
ROS_INFO("imu: %f, %f, %f, %f, %f, %f, %f, %f, %f, %f", msg->linear_acceleration.x, msg->linear_acceleration.y, msg->linear_acceleration.z,
msg->angular_velocity.x, msg->angular_velocity.y, msg->angular_velocity.z,
msg->orientation.w, msg->orientation.x, msg->orientation.y, msg->orientation.z);
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "listener");
ros::NodeHandle node;
ros::Subscriber subimu = node.subscribe("imu", 1000, imuCallback);
ros::spin();
return 0;
}
【完】
下一节会介绍路标Landmark数据的发布和订阅。
【cartographer_ros】五: 发布和订阅陀螺仪Imu信息的更多相关文章
- 【cartographer_ros】六: 发布和订阅路标landmark信息
上一节介绍了陀螺仪Imu传感数据的订阅和发布. 本节会介绍路标Landmark数据的发布和订阅.Landmark在cartographer中作为定位的修正补充,避免定位丢失. 这里着重解释一下Land ...
- StackExchange.Redis学习笔记(五) 发布和订阅
Redis命令中的Pub/Sub Redis在 2.0之后的版本中 实现了 事件推送的 发布订阅命令 以下是Redis关于发布和订阅提供的相关命令 SUBSCRIBE channel [channe ...
- 【cartogarpher_ros】三: 发布和订阅雷达scan信息
上一节介绍和测试了cartographer的官方demo. 本节会编写ros系统中,最常用的激光雷达LaserScan传感数据的订阅和发布,方便在cartographer中加入自己的数据进行建图与定位 ...
- 【cartographer_ros】四: 发布和订阅里程计odom信息
上一节介绍了激光雷达Scan传感数据的订阅和发布. 本节会介绍里程计Odom数据的发布和订阅.里程计在cartographer中主要用于前端位置预估和后端优化. 官方文档: http://wiki.r ...
- 八十五:redis之redis的事物、发布和订阅操作 (2019-11-18 22:54)
redis事物可以一次执行多个命令,事物具有以下特征1.隔离操作:事物中的所有命令都会序列化.按顺序执行,不会被其他命令打扰2.原子操作:事物中的命令要么全部被执行,要么全部都不执行 开启一个事物,以 ...
- Redis的高级应用-事务处理、持久化、发布与订阅消息、虚拟内存使用
三.事务处理 Redis的事务处理比较简单.只能保证client发起的事务中的命令可以连续的执行,而且不会插入其他的client命令,当一个client在连接 中发出multi命令时,这个连接就进入一 ...
- Dubbo系列之 (五)服务订阅(2)
辅助链接 Dubbo系列之 (一)SPI扩展 Dubbo系列之 (二)Registry注册中心-注册(1) Dubbo系列之 (三)Registry注册中心-注册(2) Dubbo系列之 (四)服务订 ...
- (转)SqlServer 数据库同步的两种方式 (发布、订阅),主从数据库之间的同步
最近在琢磨主从数据库之间的同步,公司正好也需要,在园子里找了一下,看到这篇博文比较详细,比较简单,本人亲自按步骤来过,现在分享给大家. 在这里要提醒大家的是(为了更好的理解,以下是本人自己理解,如有错 ...
- (原)3.2 Zookeeper应用 - 数据的发布与订阅
本文为原创文章,转载请注明出处,谢谢 数据的发布与订阅 1.应用 服务端监听数据改变,客户端创建/更新节点数据,客户端提供数据,服务端处理 2.原理 客户端监控节点数据改变事件(例如配置信息,下图的c ...
随机推荐
- Java基础语法Day_05(数组的概念)
第14节 数组 day05_01_数组的概念 day05_02_数组的定义格式一_动态初始化 day05_03_数组的定义格式二_静态初始化 day05_04_数组的定义格式三_省略的 ...
- 了解mybatis
什么是mybatis? MyBatis 是一款优秀的持久层框架,它支持自定义 SQL.存储过程以及高级映射.MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作.MyBati ...
- iNeuOS工业互联网操作系统,数据点、设备和业务的计算与预警
目 录 1. 概述... 2 2. 概念解释... 2 3. 数据点的计算与预警... 2 4. 设备的计算与预警... 3 5. 业务的 ...
- 现代 CSS 解决方案:CSS 数学函数
在 CSS 中,其实存在各种各样的函数.具体分为: Transform functions Math functions Filter functions Color functions Image ...
- 探索ABP基础架构-下
配置应用程序 ASP.NET Core 的配置系统提供了一个基于键值对的配置方法.它是一个可扩展的系统,可以从各种资源中读取键值对,例如 JSON 设置文件.环境变量.命令行参数等等. 设置配置值 默 ...
- 【多线程】线程休眠 Thread.sleep()
线程休眠 Thread.sleep() sleep (时间) 指定当前线程阻塞的毫秒数: sleep存在异常InterruptedException: sleep时间达到后线程进入就绪状态: slee ...
- 167. Two Sum II - Input array is sorted - LeetCode
Question 167. Two Sum II - Input array is sorted Solution 题目大意:和Two Sum一样,这里给出的数组是有序的 思路:target - nu ...
- Proxmox 7.2 部署 DoraCloud桌面云,支持vGPU
介绍 本文介绍了使用Proxmox + DoraCloud,将一台图形工作站(配置有Tesla P4显卡)改造成一台桌面云主机.可以满足多个桌面用户同时使用3D应用的需求. 该方案适合于小型工作室.电 ...
- 直观比较 popcount 的效率差异
问题 求 \(\sum\limits_{i=1}^{3\times 10^8} popcount(i)\) . 仅考虑在暴力做法下的效率. 枚举位 __builtin_popcount #includ ...
- Go微服务框架go-kratos实战02:proto 代码生成和编码实现步骤
在上一篇 kratos quickstart 文章中,我们直接用 kratos new 命令生成了一个项目. 这一篇来看看 kratos API 的定义和使用. 一.kratos 中 API 简介 1 ...