基于ROS和beaglebone的串口通信方式,使用键盘控制移动机器人

一、所需工具包

 1.ROS键盘包:teleop_twist_keyboard 
 2.ROS串口通讯包:serial

  1.     $ cd ~/catkin_ws/src
  2.     $ git clone https://github.com/Forrest-Z/teleop_twist_keyboard.git
  3.     $ git clone https://github.com/Forrest-Z/serial.git
  4.     $ catkin_make

 3.在ubuntu的ros中建立一个ros_car_pkg包:

  1.     $ cd ~/catkin_ws/src
  2.     $ catkin_create_pkg ros_car_pkg roscpp rospy std_msgs

 4.新建 base_controller 文件:

  1.     $ cd catkin_ws/src/base_controller
  2.     $ mkdir src 
  3.     $ vim src/base_controller.cpp

代码如下:
    /******************************************************************
    串口通信说明:
    1.写入串口
    (1)内容:左右轮速度,单位为mm/s
    (2)格式:10个字节,[右轮速度4字节][左轮速度4字节][结束符"\n"1个字节]
    2.读取串口
    (1)内容:小车线速度,角速度,单位依次为:mm/s,rad/s
    *******************************************************************/

  1.     #include "ros/ros.h"  
  2.     #include <geometry_msgs/Twist.h>
  3.     #include <string>        
  4.     #include <iostream>
  5.     #include <cstdio>
  6.     #include <unistd.h>
  7.     #include <math.h>
  8.     #include "serial/serial.h"
  9.     using std::ios;
  10.     using std::string;
  11.     using std::exception;
  12.     using std::cout;
  13.     using std::cerr;
  14.     using std::endl;
  15.     using std::vector;
  16.     float ratio = 1000.0f ;   //转速转换比例,执行速度调整比例
  17.     float D = 0.2680859f ;    //两轮间距,单位是m
  18.     float linear_temp=0,angular_temp=0;//暂存的线速度和角速度
  19.     unsigned char data_terminal=0x0a;  //“/n"字符
  20.     unsigned char speed_data[9]={0};   //要发给串口的数据
  21.     union floatData         //union的作用将较大的对象分解成组成这个对象的各个字节
  22.     {
  23.         float d;
  24.         unsigned char data[4];
  25.     }right_speed_data,left_speed_data;
  26.     /************************************************************/
  27.     void callback(const geometry_msgs::Twist& cmd_input)//订阅/cmd_vel主题回调函数
  28.     {
  29.         string port("/dev/ttyUSB0");    //小车串口号
  30.         unsigned long baud = 115200;    //小车串口波特率
  31.         serial::Serial my_serial(port, baud, serial::Timeout::simpleTimeout(1000)); //配置串口
  32.          
  33.         angular_temp = cmd_input.angular.z ;//获取/cmd_vel的角速度,rad/s
  34.         linear_temp = cmd_input.linear.x ;//获取/cmd_vel的线速度.m/s
  35.         //将转换好的小车速度分量为左右轮速度
  36.         left_speed_data.d = linear_temp- 0.5f*angular_temp*D ;
  37.         right_speed_data.d = linear_temp+ 0.5f*angular_temp*D ;
  38.         //存入数据到要发布的左右轮速度消息
  39.         left_speed_data.d*=ratio;   //放大1000倍,mm/s
  40.         right_speed_data.d*=ratio;//放大1000倍,mm/s
  41.     
  42.         cout<<"angular_temp = "<< angular_temp << endl;
  43.         cout<<"linear_temp = "<< linear_temp<<endl;
  44.         cout<<"left_speed_data.d = "<< left_speed_data.d<<endl;
  45.         cout<<"right_speed_data.d = "<< right_speed_data.d << endl;
  46.         for(int i=0;i<4;i++)    //将左右轮速度存入数组中发送给串口
  47.         {
  48.         speed_data[i]=right_speed_data.data[i];
  49.         speed_data[i+4]=left_speed_data.data[i];
  50.         }
  51.      
  52.         //在写入串口的左右轮速度数据后加入”/n“
  53.         speed_data[8]=data_terminal;
  54.         //speed_data[9]=data_terminal1;
  55.         //写入数据到串口
  56.         for(int i=0;i<9;i++){
  57.         cout.setf(ios::hex,ios::basefield);//设置十六进制显示数值
  58.         cout.setf(ios::showbase|ios::uppercase);//设置0x头和大写
  59.         cout<<"s_i = "<<(int)speed_data[i]<<endl;
  60.         }
  61.         my_serial.write(speed_data,10);
  62.         
  63.     }
  64.      
  65.     int main(int argc, char **argv)
  66.     {
  67.         ros::init(argc, argv, "base_controller");
  68.         ros::NodeHandle n;  
  69.         ros::Subscriber sub = n.subscribe("cmd_vel", 20, callback); //订阅cmd_vel主题
  70.         ros::spin();//周期执行
  71.         return 0;
  72.     }

修改CMakeList.txt:

  1.     cmake_minimum_required(VERSION 2.8.3)
  2.     project(ros_car_pkg)
  3.     find_package(catkin REQUIRED COMPONENTS
  4.       message_generation
  5.       roscpp
  6.       rospy
  7.       std_msgs
  8.       serial
  9.       tf
  10.       nav_msgs
  11.     )
  12.     include_directories(
  13.     # include
  14.       ${catkin_INCLUDE_DIRS}
  15.       ${serial_INCLUDE_DIRS}
  16.     )
  17.     add_message_files(FILES MsgCar.msg)
  18.     generate_messages(DEPENDENCIES std_msgs)
  19.     add_executable(base_controller src/base_controller.cpp)
  20.     target_link_libraries(base_controller ${catkin_LIBRARIES})
  21.     add_dependencies(base_controller ros_car_pkg_generate_messages_cpp)
  22.     catkin_package(CATKIN_DEPENDS roscpp rospy std_msgs)

    
单独编译ros_car_pkg包:

  1.     $ catkin_make -DCATKIN_WHITELIST_PACKAGES='ros_car_pkg'

二、控制原理:

  • 当我们按下键盘时,teleop_twist_keyboard 包会发布 /cmd_vel 发布速度主题
  • 在 base_controller 节点订阅这个话题,接收速度数据,转换成字节数据,然后写入串口
  • 通过USB转串口线,连接到板子的UART串口,在beaglebone中读取串口数据
  • 将串口数据转换成pwm信号,并加载设备树,控制电机运转,从而实现键盘控制小车的移动

1.设置beaglebone串口:


    查询手册,选择UART4,其中TXD(发送数据引脚)为P9-13,RXD(接受数据引脚)p9-11
    实验室的usb转串口线为:蓝色对应数据接受端,接RXD;白色对应发送数据端,接TXD,      黑色和红色一定要悬空!!!
    将串口线的USB端插上电脑,启动板子,在ubuntu中登录板子


        $ ssh [email protected]
    测试的时候先手动加载UART4设备树(后面串口配置成功之后,可以通过程序直接启动)    
        $ cd /sys/devices/bone_capemgr.9/
        $ echo BB-UART4 > slots    
        $ cat slots
    如果加载成功,在/dev下会出现ttyO4串口
        $ cd /dev    
        $ ls tty*
    先使用screen或者minicom监测该串口
        $ sudo screen /dev/ttyO4 115200

设置ubuntu中的ros串口:
    如果usb转串口线没坏的话,在/dev下看到ttyUSB0
        $ cd /dev    
        $ ls tty*
        $ sudo chmod 666 /dev/ttyUSB0 
    如果该步骤设置成功的话,通过往ros串口发数据,可以在上述screen监测的串口看到发送的数据
        $ echo "Hello HFUT" > /dev/ttyUSB0


    至此,串口设置完成

三、建立ros通信:


1.ubuntu中的ros端操作:    

  1.     $ roscore 
  2.     $ rosrun teleop_twist_keyboard teleop_twist_keyboard.py
  3.     $ rosrun ros_car_pkg base_controller


2.beaglebone终端操作:
    运行代码加载设备树并读串口数据用于控制PWM,进而控制小车运动

  1.     #include<stdio.h>  
  2.     #include<fcntl.h>  
  3.     #include<unistd.h>  
  4.     #include<termios.h> 
  5.     #define SLOTS   "/sys/devices/bone_capemgr.9/slots"
  6.     int main()  
  7.     {
  8.           int fd, count_r,count_t,i;
  9.           unsigned char buff[100];  // the reading & writing buffer
  10.           struct termios opt;       //uart  confige structure
  11.           //加载设备树
  12.           if ((fd = open(SLOTS, O_WRONLY)) < 0) 
  13.           { 
  14.               perror("SLOTS: Failed to open the file. \n"); 
  15.               return -1; 
  16.           }
  17.           if ((count_t = write(fd, "BB-UART4",8))<0) //8ge zi fu 
  18.           {
  19.               perror("SLOTS:Failed to write to the file\nFailed to mount the UART4"); 
  20.               return -1; 
  21.           }
  22.           close(fd); 
  23.           //设置串口
  24.           if ((fd = open("/dev/ttyO4", O_RDWR | O_NOCTTY )) < 0) 
  25.           { 
  26.                perror("UART: Failed to open the UART device:ttyO4.\n"); 
  27.                return -1; 
  28.           }
  29.           tcgetattr(fd, &opt); // get the configuration of the UART
  30.           opt.c_cflag = B115200| CS8 | CREAD | CLOCAL; 
  31.           // 115200 baud, 8-bit, enable receiver, no modem control lines    
  32.           opt.c_iflag = IGNPAR | ICRNL; 
  33.           // ignore partity errors, CR -> newline
  34.           opt.c_iflag &= ~(IXON | IXOFF | IXANY);
  35.           //turn off software stream control
  36.           opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);  
  37.           tcflush(fd,TCIOFLUSH);        // 清理输入输出缓冲区
  38.           tcsetattr(fd, TCSANOW, &opt); // changes occur immmediately 
  39.           //读串口
  40.           while(1)
  41.          {
  42.               if ((count_r = read(fd,(void*)buff,100))<0){
  43.                   perror("ERR:No data is ready to be read\n"); 
  44.                   return -1;
  45.               }
  46.               if (count_r == 0){ 
  47.                   printf("ERR:No data is ready to be read\n"); 
  48.               }
  49.               else 
  50.               { 
  51.               printf("The following was read in [%d]:%X\n",count_r,buff); //具体格式是字节
  52.               } 
  53.               
  54.               //发送PWM
  55.               if (buff != NULL)
  56.               {
  57.                   if ((fd = open(SLOTS, O_WRONLY)) < 0)
  58.                   {
  59.                       perror("SLOTS: Failed to open the file. \n");
  60.                       return -1;
  61.                   }
  62.                   if ((count_t = write(fd, "bone_pwm_P9_22",14))<0) //8ge zi fu 
  63.                   {
  64.                       perror("SLOTS:Failed to write to the file\nFailed to mount the bone_pwm_P9_22"); 
  65.                       return -1;
  66.                   }
  67.                   if ((count_t = write(fd, "bone_pwm_P9_16",14))<0) //8ge zi fu 
  68.                   {
  69.                       perror("SLOTS:Failed to write to the file\nFailed to mount the bone_pwm_P9_16"); 
  70.                       return -1;             
  71.                   }
  72.                   if ((count_t = write(fd, "am33xx_pwm",10))<0) //8ge zi fu 
  73.                   {
  74.                       perror("SLOTS:Failed to write to the file\nFailed to mount the PWM"); 
  75.                       return -1;             
  76.                   }
  77.                   close(fd);
  78.                   
  79.                   
  80.                   if ((fd = open(p922,O_WRONLY))<0)
  81.                   {
  82.                       perror("p922: Failed to open the file. \n");
  83.                       return -1;
  84.                   }
  85.                   if((count_t= write(fd,"1",1))<0) //8ge zi fu 
  86.                   {
  87.                       perror("p922run:Failed to write to the file\nFailed to mount the p9223");
  88.                       return -1;
  89.                   }
  90.                   close(fd);
  91.                   if ((fd = open(p916,O_WRONLY))<0)
  92.                   {
  93.                       perror("p916: Failed to open the file. \n");
  94.                       return -1;
  95.                   }
  96.                   if((count_t= write(fd,"1",1))<0) //8ge zi fu 
  97.                   {
  98.                       perror("p916run:Failed to write to the file\nFailed to mount the p9223");
  99.                       return -1;
  100.                   }
  101.                   close(fd);
  102.                   usleep(50000000);
  103.           }
  104.           return 0; 
  105.     }

猜你喜欢

转载自www.cnblogs.com/dingyc/p/10675295.html