ROS学习过程记录(二)
机器人运动控制
右手大拇指指定坐轴正方向,手指弯曲的方向就是沿各个轴转动的正方向。速度是弧度每秒。
运动解析与对应的消息包
使用wpr_simulation启动机器人仿真程序,按一下过程创建一个运动控制包:
catkin_create_pkg vel_pkg roscpp geometry_msgs
#include <ros/ros.h>
#include <geometry msgs/Twist.h>
int main(int argc,char *argv[]) {
ros::init(argc ,argv ,"vel_node");
ros::NodeHandle n;
ros::Publisher vel_pub = n.advertise<geometry_msgs::Twist>("/cmd_vel",10);
geometry_msgs::Twist vel msg;
vel msg.linear.x=0.1;
vel msg.linear.y =0;
vel msg.linear.z =0;
vel msg.angular.x =0;
vel msg.angular.y =0;
vel msg.angular.z =0;
ros::Rate r(30);
while (ros::ok()) {
vel pub.publish(vel msg);
r.sleep();
}
return 0;
}
/cmd_vel 是wpr_simulation中的速度控制的topic.
ROS 的速度指令(Twist 消息)不是持续生效的,而是瞬时的。机器人接收到 Twist 消息后,通常只执行这条指令一次,并不会自动保持这个速度。如果不持续发布,机器人可能在执行完这条指令后立刻停下(尤其是底层驱动没有内置“保持速度”的功能时)。有些机器人有超时机制:如果一段时间内没有收到新的速度指令,就会触发自动停止,防止机器人因通信中断失控。
例如:某些机器人要求每 100 毫秒收到一次速度指令,否则它会自动刹车。
激光雷达工作原理
激光雷达(LiDAR, Light Detection and Ranging)的工作原理可以简单概括为:用激光测距离,靠时间算位置。让我们一步步拆解一下:
🌟 1. 发射激光
激光雷达通过激光发射器向外发射一道或多道激光脉冲。
这些激光通常是不可见的红外线,波长一般在 900nm 到 1550nm 之间。
⏲️ 2. 激光反射
激光碰到障碍物后,会被反射回来。
反射信号被激光雷达的接收器捕捉到。
⏱️ 3. 计算距离
激光雷达根据**飞行时间(Time of Flight, ToF)**来计算障碍物的距离:
。
🔄 4. 扫描环境
大多数激光雷达通过机械旋转或电子扫描,让激光束覆盖一个360°平面或者3D空间。
每次扫描后,雷达生成一组点云(Point Cloud),包含障碍物的距离和角度信息。
🧠 5. 构建地图(可选)
机器人可以利用这些点云数据生成周围环境的2D地图或3D模型,实现避障、导航、定位等功能。
总结:
发射激光。
激光打到物体后反射回来。
根据激光往返的时间,计算距离。
重复扫描,获取环境的完整信息
使用RViz观察传感器数据
传感器数据包:sensor_msgs/LaserScan.msg
雷达发出激光,测距,然后旋转一个角度,再次测距,旋转的角度就是angle_increment, 两次测距消耗的时间就是time_increment. 雷达再rang_min 和range_max中测得的数据才是有效的。
ranges数组中就是激光雷达测得到障碍物的距离。
获取激光雷达数据
原理:
catkin_create_pkg lidar_pkg roscpp sensor_msgs
#include <ros/ros.h>
#include <sensor_msgs/Laserscan.h>
void LidarCallback(const sensor msgs::Laserscan msg) {
float fMidDist = msg.ranges[180];
ROS INFO("前方测距 ranges[180]=%f 米",,fMidDist);
}
int main(int argc, char *argv[]) {
setlocale(LC ALL,"");ros::init(argc, argv,"lidar_node");
ros::NodeHandle n;
ros::Subscriber lidar sub = n.subscribe("/scan", 10, &LidarCallback);
ros::spin();
return 0;
}
roslaunch wpr_simulation wpb_simple.launch
rosrun lidar_pkg lidar_node
激光雷达避开障碍物
#include <ros/ros.h>
#include <sensor_msgs/LaserScan.h>
#include <geometry_msgs/Twist.h>
ros::Publisher vel_pub;
void LidarCallback(const sensor_msgs::LaserScan msg) {
float fMidDist= msg.ranges[180];ROS INFO("前方测距 ranges[180]=&f 米",fMidDist);
geometry msgs::Twist vel_cmd;
if(fMidDist < 1.5) {
vel_cmd.angular.z=0.3;
}
else {
vel_cmd.linear.x=0.05;
vel_pub.publish(vel cmd);
}
}
int main(int argc, char** argv) {
setlocale(LC_ALL,"");
ros::init(argc,argv,"lidar node");
ros::NodeHandle n;
ros::Subscriber lidar_sub = n.subscribe("/scan", 10, &Lidarcallback);
vel_pub = n.advertise<geometry msgs::Twist>("/cmd vel", 10);
ros::spin();
return0:
}
IMU 惯性测量单元
IMU(Inertial Measurement Unit,惯性测量单元)是一种用来测量物体姿态、速度和加速度的传感器
IMU 主要由两个核心部件组成:
🌀 加速度计(Accelerometer):
用来测量线性加速度(比如前进、后退、上下运动时的加速度)。
还能通过重力分量,推算物体的倾斜角度。
🔄 陀螺仪(Gyroscope):
用来测量角速度(物体绕 X、Y、Z 轴的旋转速度)。
通过累积角速度,可以推算旋转角度。
部分高级 IMU 还包含:
🧭 磁力计(Magnetometer):
用来感知地球磁场,类似电子罗盘,提供航向角(Yaw)。
典型的 IMU 会输出:
加速度(linear acceleration): 描述直线运动时的加速度。
角速度(angular velocity): 描述绕各轴旋转的速度。
姿态(orientation): 通过合并加速度计、陀螺仪和磁力计数据,得到俯仰角(Pitch)、横滚角(Roll)、航向角(Yaw)。
获取IMU数据步骤:
IMU航向锁定
在IMUCallBack中补充
自定义消息类型
catkin_create_pkg qq_msgs roscpp std_msgs
创建carry.msg文件,其内容为:
string grade
int star
string data
查看自定义消息
使用自定义消息类型
#include <ros/ros.h>
#include <std msgs/string.h>
#include <qq msgs/carry.h>
int main(int argc, char *argv[]) {
ros::init(argc,argv,"chao node");printf("我的枪去而复返,你的生命有去无回!\n");
ros::NodeHandle nh;
ros::Publisher pub = nh.advertise<qq_msgs::carry>("kuai
ros::Rate loop_rate(10);
while(ros::ok()) {
printf("我要开始刷屏了!\n");
qq msgs::Carry msg;
msg.grade ="王者";
msg.star =50;msg.data =“国服马超,带飞";
pub.publish(msg);
loop_rate.sleep();
}
return 0;
}
在CMakeLists.txt中添加find_packge和add_dependencies