昨天折腾了一天,主要是用游戏手柄对车体的行走进行控制,其实也就是控制灯的那一部分进行了一个改写。程序如下:
#include <ros/ros.h>
#include <serial/serial.h>
#include "joy_control/joy_send.h"
using namespace std;
string port = "/dev/PIserial";
//string port = "/dev/ttyUSB0";
unsigned int baudrate = 115200;
serial::Serial ser;
unsigned char send_lamp_data[9]= {0xff,0xfc,0x07,0x05,0xff,0x00,0x00,0x00,0xff};
unsigned char send_carspd_data[]={0xff,0xfc,0x0a,0x12,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0xff};
double Move_x_Spd_Read = 0,Move_y_Spd_Read = 0,Move_w_Spd_Read = 0;
void joy_control_lamp(const joy_control::joy_send joymsgs){
/*开灯*/
if(joymsgs.button[0] == 1){
send_lamp_data[5] = 0;
send_lamp_data[6] = 0;
send_lamp_data[7] = 0xff;
}else if(joymsgs.button[1] == 1){
send_lamp_data[5] = 0xff;
send_lamp_data[6] = 0;
send_lamp_data[7] = 0;
}else if(joymsgs.button[2] == 1){
send_lamp_data[5] = 0;
send_lamp_data[6] = 0xff;
send_lamp_data[7] = 0;
}else if(joymsgs.button[3] == 1){
send_lamp_data[5] = 0;
send_lamp_data[6] = 0;
send_lamp_data[7] = 0;
}
/*发速度*/
float f_Vx_temp = 256.0,f_Vy_temp = 256.0,f_Vw_temp = 256.0*4;
float f_Vx_send = 0,f_Vy_send = 0,f_Vw_send = 0;
unsigned int l_Vx_send = 0,l_Vy_send = 0,l_Vw_send = 0;
f_Vy_temp = f_Vy_temp * joymsgs.axis[0];
f_Vx_temp = f_Vx_temp * joymsgs.axis[1];
f_Vw_temp = f_Vw_temp * joymsgs.axis[2];
l_Vx_send = (int16_t)f_Vx_temp;
l_Vy_send = (int16_t)f_Vy_temp;
l_Vw_send = (int16_t)f_Vw_temp;
send_carspd_data[5] = l_Vx_send & 0xff;
send_carspd_data[6] = ((l_Vx_send & 0xff00)>>8);
send_carspd_data[7] = l_Vy_send & 0xff;
send_carspd_data[8] = ((l_Vy_send & 0xff00)>>8);
send_carspd_data[9] = l_Vw_send & 0xff;
send_carspd_data[10] = ((l_Vw_send & 0xff00)>>8);
}
void time2_callback(const ros::TimerEvent& time_e)
{
// ROS_INFO("time2_callback");
// 控制灯
unsigned int temp = 0;
for(int i= 2;i<sizeof(send_lamp_data)-1;i++)
{
temp += send_lamp_data[i];
}
send_lamp_data[sizeof(send_lamp_data)-1]=temp;
#if 1
ser.write(send_lamp_data, sizeof(send_lamp_data));
#endif
}
void time1_callback(const ros::TimerEvent& time_e)
{
// ROS_INFO("time1_callback");
//控制车速
unsigned int temp1 = 0;
for(int i= 2;i<sizeof(send_carspd_data)-1;i++)
{
temp1 += send_carspd_data[i];
}
send_carspd_data[sizeof(send_carspd_data)-1]=temp1;
#if 1
ser.write(send_carspd_data, sizeof(send_carspd_data));
#endif
}
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
ros::init(argc,argv,"usbserial_node");
ros::NodeHandle nh;
#if 0
if(nh.getParam("/Move_x_Spd",Move_x_Spd_Read) == 0){
ROS_WARN("getParam Move_x_Spd error");
}
else{
ROS_INFO("Move_x_Spd_Read = %f.",Move_x_Spd_Read);
}
if(nh.getParam("/Move_y_Spd",Move_y_Spd_Read) == 0){
ROS_WARN("getParam Move_y_Spd error");
}
else{
ROS_INFO("Move_y_Spd_Read = %f.",Move_y_Spd_Read);
}
if(nh.getParam("/Move_w_Spd",Move_w_Spd_Read) == 0){
ROS_WARN("getParam Move_w_Spd error");
}
else{
ROS_INFO("Move_w_Spd_Read = %f.",Move_w_Spd_Read);
}
#endif
ros::Timer timer1 = nh.createTimer(ros::Duration(0.05), time1_callback);//0.5s运行一次callback1
//ros::Timer timer2 = nh.createTimer(ros::Duration(0.1), time2_callback);//0.5s运行一次callback1
ros::Subscriber joy_control_sub = nh.subscribe<joy_control::joy_send>("/joy_data_for_use",100,joy_control_lamp);
try
{
ser.setPort(port);
ser.setBaudrate(baudrate);
serial::Timeout to = serial::Timeout::simpleTimeout(1000);
ser.setTimeout(to);
ser.open();
}
catch(const std::exception& e)
{
ROS_ERROR_STREAM("Unable to open port ");
return -1;
}
if(ser.isOpen()){
ROS_INFO("串口初始化完成");
}
else{
return -1;
}
#if 0
ros::Rate loop_rate(10);
while(ros::ok())
{
if(ser.available()){
ROS_INFO("reading from serial port");
ser.read(recv_data,ser.available());
for(int i=0;i<sizeof(recv_data);i++)
cout<<std::hex <<(recv_data[i] & 0xff)<<" ";
cout<<endl;
cout<<endl;
}
unsigned int temp = 0;
for(int i= 2;i<sizeof(send_lamp_data)-1;i++)
{
temp += send_lamp_data[i];
}
ROS_INFO("发送%ld个字节.",sizeof(send_lamp_data));
ROS_INFO("Send data sum = %x.",temp);
send_lamp_data[sizeof(send_lamp_data)-1]=temp;
ser.write(send_lamp_data, sizeof(send_lamp_data));
ros::spinOnce();
loop_rate.sleep();
}
#endif
ros::spin();
return 0;
}
这里面有一个知识点,一个问题。先说知识点,就是定时器,定时器这个东西,我感觉挺重要的,之前做的嵌入式操作系统程序中,有一些程序是靠着定时器的时长,触发信号量,另外一个线程接收该信号量,再进行数据处理,这里也沿用了这种思路,也就是以一定的间隔将车体速度,从串口中进行发送。
ROS中的定时器还是比较方便的,就一句定义,一个回调函数,记录一下:
1)定义
ros::Timer timer1 = nh.createTimer(ros::Duration(0.05), time1_callback);//0.05s运行一次callback1
2)回调函数
void time1_callback(const ros::TimerEvent& time_e)
{
// ROS_INFO("time1_callback");
//控制车速
unsigned int temp1 = 0;
for(int i= 2;i<sizeof(send_carspd_data)-1;i++)
{
temp1 += send_carspd_data[i];
}
send_carspd_data[sizeof(send_carspd_data)-1]=temp1;
#if 1
ser.write(send_carspd_data, sizeof(send_carspd_data));
#endif
}
问题来了,我定了两个定时器,分别是0.05s的时长和0.1s的时长,虽然两者有20倍的差距,但是监控发送出来的数据竟然是组合在一起的,也就是把两帧合并成了一帧,这个问题我没有解决。。。等后面有了思路再来补充解决方案。
有了上面的东西,车底盘可以走了。
下面开始今天的记录:思岚A1传感器。
参考的文章是这一篇
【项目】ROS下使用激光雷达_ros思岚a1激光雷达串口权限-CSDN博客
Step1:配置USB口
恩,没错,还是这个策略,还是那个步骤。
cd /etc/udev/rules.d/
sudo touch rplidar.rules
sudo nano rplidar.rules
我的第一篇文章中提到的嘿嘿的东西又来了,赶紧复制进去
KERNEL=="ttyUSB*",ATTRS{idVendor}=="10c4",ATTRS{idProduct}=="ea6",ATTRS{serial}=="0002",MODE:="0777",GROUP:="dialout",SYMLINK+="rplidar"
这一段话我复制粘贴了很多很多次,还是很容易出错的。
Step2:查看配置的串口
ls -l /dev | grep ttyUSB
当可以看到
lrwxrwxrwx 1 root root 7 Oct 17 01:38 rplidar -> ttyUSB2
这一句的时候,证明配置成功了。
STEP3:下载思岚提供的ros功能包
下载
sudo apt-get install ros-noetic-rplidar-ros
运行
roslaunch rplidar_ros rplidar.launch
STEP4:修改功能包中必要的参数
这里参考赵虚左老师的教程即可,其实主要就是改一下串口的名称,否则会在运行节点的时候报一个错误。
Can not start scan: 80008002!
修改的内容就是这一句:记得要全,/dev/rplidar,不是/rplidar
<param name="serial_port" type="string" value="/dev/rplidar"/>
STEP5:运行相应的launch文件
roslaunch rplidar_ros rplidar.launch
STEP6:查看数据
rostopic echo /scan
应该就能看到一脱脱的数据飘散在屏幕上了。
特别希望大家能耐心的去把赵虚左老师的那些课程看一遍,我是大概用了半个月看完的,当然我估计有三分之一的时间都看睡着了,不是老师讲的不好,而是知识不成体系前就这样,会的人说出来的话对于接受者来说,中间的gap,必须得等接收者自己明白了才能体会,不然为啥说是专有名词呢,特定语境下的产物。所以呢,做技术就要耐的住寂寞,还要有一个好的支持自己的领导,我现在在单位的乒乓球室写这些,其实还是要感谢我的领导能够这么信任我。。。哈哈,马屁时间。。。但是真的,人要感恩。。。
说道感恩,还要推荐一下B站上的大牛机器人工匠阿杰,他的书我买了,并且基本上学到哪里都会把上面的程序敲一遍,人老,笨,所以就不能懒惰。