【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 ...
随机推荐
- GeoServer style中文乱码解决方法
在说明这个问题之前,有三点需要明确: 一是创建New style时,网页中文本框内的内容才是最终会应用到GeoServer的sld内容,这与本地sld文件没有关系. 二是xml的encoding定义的 ...
- python学习-Day20
目录 今日内容详细 作业讲解 re模块补充说明 findall的优先级查询 通过索引的方式单独获取分组内匹配到的数据 分组之后还可以给组起别名 split的优先级查询 collections模块 具名 ...
- 攻防世界-MISC:pdf
这是攻防世界新手练习区的第二题,题目如下: 点击附件1下载,打开后发现是一个pdf文件,里面只有一张图片 用WPS打开,没发现有什么不对的地方,参考一下WP,说是要转为word格式.随便找一个在线转换 ...
- MySQL事务基本使用
目录 1 事务概述 1.1 事务的支持情况 1.2 事务的特性 1.3 事务的状态 2 使用事务 2.1 显示事务 2.2 隐藏事务 3 事务隔离等级 3.1 数据并发问题 3.2 事务隔离等级介绍 ...
- [笔记] 2-sat
定义 简单的说就是给出 \(n\) 个集合,每个集合有两个元素,已知形如选 \(a\) 则必须选 \(b\) 的若干个条件, 问是否存在从每个集合选择一个元素满足条件的方案,通常可以题目只要求任意一种 ...
- kafka基础原理
1.什么是kafka Kafka 是一个分布式的基于发布/订阅模式的消息队列 消息队列的两种模式: 点对点模式(一对一,消费者主动拉取数据,消息收到后消息清除).特点,一个消息只能被一个消费者消费 发 ...
- JavaScript 数据结构与算法3(链表)
学习数据结构的 git 代码地址: https://gitee.com/zhangning187/js-data-structure-study 1.链表 本章学习如何实现和使用链表这种动态的数据结构 ...
- 关于background-*的一些属性
1.盒模型 盒模型从外到内一次为:margin-box.border-box.padding-box.content-box. 2.一些属性设置的相对位置 ⑴background-position的属 ...
- AQS源码探究之竞争锁资源
AQS源码探究---竞争锁资源 我们进入ReentrantLock源码中查看其内部类 Sync 对AQS进行扩展公共方法并定义抽象方法的抽象类 FaireSync 实现公平锁的AQS的实现类 UnFa ...
- PCIe引脚PRSNT与热插拔
热插拔的基本目的是要让PCIe设备按照规定的顺序.原则,从系统中移除或插入到系统中来,并能正常的工作,且不影响系统的正常运行.事实上,PCIe"热插拔"的关键目的就是为前面面所提到 ...