yabhoom智能机器人学习记录——(三)激光雷达

文章讲述了作者使用游戏手柄控制车体行走,通过ROS和USB串口实现实时数据传输,同时遇到定时器合并数据的问题。还介绍了配置思岚A1激光雷达传感器的过程,包括udev规则、串口设置和功能包参数调整。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        昨天折腾了一天,主要是用游戏手柄对车体的行走进行控制,其实也就是控制灯的那一部分进行了一个改写。程序如下:

        

#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站上的大牛机器人工匠阿杰,他的书我买了,并且基本上学到哪里都会把上面的程序敲一遍,人老,笨,所以就不能懒惰。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值