• 2.树莓派4b+ubuntu18.04(ros版本melodic)+arduino mega自制两轮差速小车,实现建图导航功能


    这篇文章介绍arduino使用和安装arduino_bridge

    将arduino与树莓派连接
    查看arduino的端口号,我们这里查看到的时ttyUSB0

    ll /dev/ttyUSB*
    

    在这里插入图片描述
    将当前用户添加进dialout组

    sudo usermod -a -G dialout your_user_name
    

    然后重启树莓派,然后才能生效
    然后如果你可以在列出的组中找到dialout,这就说明你已经加入到dialout中了
    group
    在这里插入图片描述

    安装arduino

    1.下载arduino ide安装包
    官方下载链接:https://www.arduino.cc/en/Main/Software
    在这里插入图片描述
    2.使用tar命令对压缩包解压

    tar -xvf arduino-1.x.y-linux64.tar.xz
    

    3.将解压后的文件移动到/opt下

    sudo mv arduino-1.x.y /opt
    

    4.进入安装目录,对install.sh添加可执行权限,并执行安装

    cd /opt/arduino-1.x.y
    sudo chmod +x install.sh
    sudo ./install.sh
    

    5.启动并配置 Arduino IDE
    在命令行直接输入:arduino,或者点击左下的显示应用程序搜索 arduino IDE。启动如下:
    在这里插入图片描述

    // 初始化函数
    void setup() {
       
      //将LED灯引脚(引脚值为13,被封装为了LED_BUTLIN)设置为输出模式
      pinMode(LED_BUILTIN, OUTPUT);
    }
    
    // 循环执行函数
    void loop() {
       
      digitalWrite(LED_BUILTIN, HIGH);   // 打开LED灯
      delay(1000);                       // 休眠1000毫秒
      digitalWrite(LED_BUILTIN, LOW);    // 关闭LED灯
      delay(1000);                       // 休眠1000毫秒
    }
    

    在这里插入图片描述
    开发板选择Arduino mega,端口号选择/dev/ttyUSB0
    上传该代码,观察arduino板载灯闪烁
    到此arduino的安装就结束了

    接下来安装ros_arduino_bridge

    该功能包包含Arduino库和用来控制Arduino的ROS驱动包,它旨在成为在ROS下运行Arduino控制的机器人的完整解决方案。

    其中当前主要关注的是:功能包集中一个兼容不同驱动的机器人的基本控制器(base controller),它可以接收ROS Twist类型的消息,可以发布里程计数据。上位机需要使用ROS(建议 melodic);

    1.下载

    新建ROS工作空间

    mkdir -p catkin_ws/src
    cd catkin_ws
    catkin_make
    

    进入ROS工作空间的src目录,输入命令:

    cd catkin_ws/src
    git clone https://github.com/hbrobotics/ros_arduino_bridge.git
    

    2.ros_arduino_bridge 架构
    文件结构说明在这里插入代码片 ├── ros_arduino_bridge # metapackage (元功能包)
    │ ├── CMakeLists.txt
    │ └── package.xml
    ├── ros_arduino_firmware #固件包,更新到Arduino
    │ ├── CMakeLists.txt
    │ ├── package.xml
    │ └── src
    │ └── libraries #库目录
    │ ├── MegaRobogaiaPololu #针对Pololu电机控制器,MegaRobogaia编码器的头文件定义
    │ │ ├── commands.h #定义命令头文件
    │ │ ├── diff_controller.h #差分轮PID控制头文件
    │ │ ├── MegaRobogaiaPololu.ino #PID实现文件
    │ │ ├── sensors.h #传感器相关实现,超声波测距,Ping函数
    │ │ └── servos.h #伺服器头文件
    │ └── ROSArduinoBridge #Arduino相关库定义
    │ ├── commands.h #定义命令
    │ ├── diff_controller.h #差分轮PID控制头文件
    │ ├── encoder_driver.h #编码器驱动头文件
    │ ├── encoder_driver.ino #编码器驱动实现, 读取编码器数据,重置编码器等
    │ ├── motor_driver.h #电机驱动头文件
    │ ├── motor_driver.ino #电机驱动实现,初始化控制器,设置速度
    │ ├── ROSArduinoBridge.ino #核心功能实现,程序入口
    │ ├── sensors.h #传感器头文件及实现
    │ ├── servos.h #伺服器头文件,定义插脚,类
    │ └── servos.ino #伺服器实现
    ├── ros_arduino_msgs #消息定义包
    │ ├── CMakeLists.txt
    │ ├── msg #定义消息
    │ │ ├── AnalogFloat.msg #定义模拟IO浮点消息
    │ │ ├── Analog.msg #定义模拟IO数字消息
    │ │ ├── ArduinoConstants.msg #定义常量消息
    │ │ ├── Digital.msg #定义数字IO消息
    │ │ └── SensorState.msg #定义传感器状态消息
    │ ├── package.xml
    │ └── srv #定义服务
    │ ├── AnalogRead.srv #模拟IO输入
    │ ├── AnalogWrite.srv #模拟IO输出
    │ ├── DigitalRead.srv #数字IO输入
    │ ├── DigitalSetDirection.srv     #数字IO设置方向
    │ ├── DigitalWrite.srv #数字IO输入
    │ ├── ServoRead.srv #伺服电机输入
    │ └── ServoWrite.srv #伺服电机输出
    └── ros_arduino_python #ROS相关的Python包,用于上位机,树莓派等开发板或电脑等。
    ├── CMakeLists.txt
    ├── config #配置目录
    │ └── arduino_params.yaml #定义相关参数,端口,rate,PID,sensors等默认参数。由arduino.launch调用
    ├── launch
    │ └── arduino.launch #启动文件
    ├── nodes
    │ └── arduino_node.py #python文件,实际处理节点,由arduino.launch调用,即可单独调用。
    ├── package.xml
    ├── setup.py
    └── src #Python类包目录
    └── ros_arduino_python
    ├── arduino_driver.py #Arduino驱动类
    ├── arduino_sensors.py #Arduino传感器类
    ├── base_controller.py #基本控制类,订阅cmd_vel话题,发布odom话题
    └── init.py #类包默认空文件

    上述目录结构虽然复杂,但是关注的只有两大部分:

    ros_arduino_bridge/ros_arduino_firmware/src/libraries/ROSArduinoBridge
    ros_arduino_bridge/ros_arduino_python/config/arduino_params.yaml

    接下来我们对代码进行测试

    1.串口命令

    在主程序中,包含了 commands.h,该文件中包含了当前程序预定义的串口命令,可以编译程序并上传至 Arduino 电路板,然后打开串口监视器测试(当前程序并未修改,所以并非所有串口可用):

    w 可以用于控制引脚电平
    x 可以用于模拟输出
    以LED灯控制为例,通过串口监视器录入命令:

    w 13 0 == LED灯关闭
    w 13 1 == LED灯打开
    x 13 50 == LED灯PWM值为50
    2.修改主程序入口,主要是添加
    #define Tb6612_MOTOR_DRIVER

    /*********************************************************************
     *  ROSArduinoBridge
     
       控制差速驱动机器人的Arduino程序,允许通过一组简单的串行命令来控制机器人,并接收传感器和里程数据。
       该程序默认配置假定使用Arduino Mega、Pololu电机控制器盾和Robogaia Mega编码器盾。
       如果使用不同的电机控制器或编码器方法,可以编辑readEncoder()和setMotorSpeed()包装函数。
     *********************************************************************/
    //是否启用基座控制器
    #define USE_BASE      // Enable the base controller code
    //#undef USE_BASE     // Disable the base controller code
    
    /* Define the motor controller and encoder library you are using */
    
    启用基座控制器需要设置的电机驱动以及编码器驱
    #ifdef USE_BASE
       /* The Pololu VNH5019 dual motor driver shield */
       //#define POLOLU_VNH5019
    
       /* The Pololu MC33926 dual motor driver shield */
       //#define POLOLU_MC33926
    
       /* The RoboGaia encoder shield */
       //#define ROBOGAIA
       
       /* Encoders directly attached to Arduino board */
       //#define ARDUINO_ENC_COUNTER
       //1.添加自定义编码器驱动
       #define ARDUINO_MY_COUNTER
    
       
       /* L298 Motor driver*/
       //#define L298_MOTOR_DRIVER
       #define Tb6612_MOTOR_DRIVER
    #endif
    //是否启用舵机
    //#define USE_SERVOS  // Enable use of PWM servos as defined in servos.h
    #undef USE_SERVOS     // Disable use of PWM servos
    
    
    //波特率
    /* Serial port baud rate */
    #define BAUDRATE     57600
    //最大PWM值
    /* Maximum PWM signal */
    #define MAX_PWM        255
    
    #if defined(ARDUINO) && ARDUINO >= 100
    #include "Arduino.h"
    #else
    #include "WProgram.h"
    #endif
    
    /* Include definition of serial commands */
    #include "commands.h"
    
    /* Sensor functions */
    #include "sensors.h"
    
    /* Include servo support if required */
    #ifdef USE_SERVOS
       #include 
       #include "servos.h"
    #endif
    
    
    
    //
    #ifdef USE_BASE
      /* Motor driver function definitions */
      #include "motor_driver.h"
    
      /* Encoder driver function definitions */
      #include "encoder_driver.h"
    
      /* PID parameters and functions */
      #include "diff_controller.h"
    
      /* Run the PID loop at 30 times per second */
      #define PID_RATE           30     // Hz
    
      /* Convert the rate into an interval */
      const int PID_INTERVAL = 1000 / PID_RATE;
      
      /* Track the next time we make a PID calculation */
      unsigned long nextPID = PID_INTERVAL;
    
      /* Stop the robot if it hasn't received a movement command
       in this number of milliseconds */
      #define AUTO_STOP_INTERVAL 2000
      long lastMotorCommand = AUTO_STOP_INTERVAL;
    #endif
    
    /* Variable initialization */
    
    // A pair of varibles to help parse serial commands (thanks Fergs)
    int arg = 0;
    int index = 0;
    
    // Variable to hold an input character
    char chr;
    
    // Variable to hold the current single-character command
    char cmd;
    
    // Character arrays to hold the first and second arguments
    char argv1[16];
    char argv2[16];
    
    // The arguments converted to integers
    long arg1;
    long arg2;
    //重置命令
    /* Clear the current command parameters */
    void resetCommand() {
       
      cmd = NULL;
      memset(argv1, 0, sizeof(argv1));
      memset(argv2, 0, sizeof(argv2));
      arg1 = 0;
      arg2 = 0;
      arg = 0;
      index = 0;
    }
    
    /* Run a command.  Commands are defined in commands.h */
    //执行串口命令
    int runCommand() {
       
      int i = 0;
      char *p = argv1;
      char *str;
      int pid_args[4];
      arg1 = atoi(argv1);
      arg2 = atoi(argv2);
      
      switch(cmd) {
       
      case GET_BAUDRATE:
        Serial.println(BAUDRATE);
        break;
      case ANALOG_READ:
        Serial.println(analogRead(arg1));
        break;
      case DIGITAL_READ:
        Serial.println(digitalRead(arg1));
        break;
      case ANALOG_WRITE:
        analogWrite(arg1, arg2);
        Serial.println("OK"); 
        break;
      case DIGITAL_WRITE:
        if (arg2 == 0) digitalWrite(arg1, LOW);
        else if (arg2 == 1) digitalWrite(arg1, HIGH);
        Serial.println("OK"); 
        break;
      <
  • 相关阅读:
    【云原生 | Kubernetes 系列】--Gitops持续交付 ArgoCD自动同步策略
    美团前端二面常考react面试题(附答案)
    分类预测 | MATLAB实现KOA-CNN-BiLSTM开普勒算法优化卷积双向长短期记忆神经网络数据分类预测
    JS常用的函数
    代码随想录算法训练营第五十九天 | 647. 回文子串 & 516.最长回文子序列
    【Eigen】旋转方向及eulerAngles函数参数说明
    4.7拆解复杂问题-实现计算器
    (有什么区别)Python中return self和return None或者return或者不写
    深度清洁,清洗小物件的好助手——希亦CG超声波清洗机体验
    【Linux】谈谈shell外壳是什么?
  • 原文地址:https://blog.csdn.net/m0_63715549/article/details/139903731