第 8 章 机器人底盘Arduino端入口(自学二刷笔记)

重要参考:

课程链接:https://www.bilibili.com/video/BV1Ci4y1L7ZZ

讲义链接:Introduction · Autolabor-ROS机器人入门课程《ROS理论与实践》零基础教程

8.4.2 底盘实现_01Arduino端入口

ros_arduino_bridge/ros_arduino_firmware/src/libraries/ROSArduinoBridge下的RosArduinoBridge.ino是Arduino端程序的主入口,

源文件(添加中文注释)内容如下:

/**********************************************************************  ROSArduinoBridge可以通过一组简单的串口命令来控制差分机器人并接收回传的传感器与里程计数据,默认使用的是 Arduino Mega + Pololu电机驱动模块,如果使用其他的编码器或电机驱动需要重写readEncoder()与setMotorSpeed()函数A set of simple serial commands to control a differential driverobot and receive back sensor and odometry data. Default configuration assumes use of an Arduino Mega + Pololu motorcontroller shield + Robogaia Mega Encoder shield.  Edit thereadEncoder() and setMotorSpeed() wrapper functions if using different motor controller or encoder method.Created for the Pi Robot Project: http://www.pirobot.organd the Home Brew Robotics Club (HBRC): http://hbrobotics.orgAuthors: Patrick Goebel, James NugenInspired and modeled after the ArbotiX driver by Michael FergusonSoftware License Agreement (BSD License)Copyright (c) 2012, Patrick Goebel.All rights reserved.Redistribution and use in source and binary forms, with or withoutmodification, are permitted provided that the following conditionsare met:* Redistributions of source code must retain the above copyrightnotice, this list of conditions and the following disclaimer.* Redistributions in binary form must reproduce the abovecopyright notice, this list of conditions and the followingdisclaimer in the documentation and/or other materials providedwith the distribution.THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOTLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESSFOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THECOPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVERCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICTLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING INANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE*  POSSIBILITY OF SUCH DAMAGE.*********************************************************************/
//是否启用基座控制器
//#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/* L298 Motor driver*///#define L298_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/* Maximum PWM signal */
//最大PWM值
#define MAX_PWM        255//根据Arduino型号来包含对应的头文件
#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 <Servo.h>#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" //PID调速/* 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 commandin 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;case PIN_MODE:if (arg2 == 0) pinMode(arg1, INPUT);else if (arg2 == 1) pinMode(arg1, OUTPUT);Serial.println("OK");break;case PING:Serial.println(Ping(arg1));break;
#ifdef USE_SERVOScase SERVO_WRITE:servos[arg1].setTargetPosition(arg2);Serial.println("OK");break;case SERVO_READ:Serial.println(servos[arg1].getServo().read());break;
#endif#ifdef USE_BASEcase READ_ENCODERS:Serial.print(readEncoder(LEFT));Serial.print(" ");Serial.println(readEncoder(RIGHT));break;case RESET_ENCODERS:resetEncoders();resetPID();Serial.println("OK");break;case MOTOR_SPEEDS: //传入电机控制命令/* Reset the auto stop timer */lastMotorCommand = millis();if (arg1 == 0 && arg2 == 0) {setMotorSpeeds(0, 0);resetPID();moving = 0;}else moving = 1;leftPID.TargetTicksPerFrame = arg1;rightPID.TargetTicksPerFrame = arg2;Serial.println("OK"); break;case UPDATE_PID:while ((str = strtok_r(p, ":", &p)) != '\0') {pid_args[i] = atoi(str);i++;}Kp = pid_args[0];Kd = pid_args[1];Ki = pid_args[2];Ko = pid_args[3];Serial.println("OK");break;
#endifdefault:Serial.println("Invalid Command");break;}
}/* Setup function--runs once at startup. */
void setup() {Serial.begin(BAUDRATE);// Initialize the motor controller if used */
#ifdef USE_BASE#ifdef ARDUINO_ENC_COUNTER//set as inputsDDRD &= ~(1<<LEFT_ENC_PIN_A);DDRD &= ~(1<<LEFT_ENC_PIN_B);DDRC &= ~(1<<RIGHT_ENC_PIN_A);DDRC &= ~(1<<RIGHT_ENC_PIN_B);//enable pull up resistorsPORTD |= (1<<LEFT_ENC_PIN_A);PORTD |= (1<<LEFT_ENC_PIN_B);PORTC |= (1<<RIGHT_ENC_PIN_A);PORTC |= (1<<RIGHT_ENC_PIN_B);// tell pin change mask to listen to left encoder pinsPCMSK2 |= (1 << LEFT_ENC_PIN_A)|(1 << LEFT_ENC_PIN_B);// tell pin change mask to listen to right encoder pinsPCMSK1 |= (1 << RIGHT_ENC_PIN_A)|(1 << RIGHT_ENC_PIN_B);// enable PCINT1 and PCINT2 interrupt in the general interrupt maskPCICR |= (1 << PCIE1) | (1 << PCIE2);#endifinitMotorController(); //初始化电机控制resetPID(); //重置 PID
#endif/* Attach servos if used */#ifdef USE_SERVOSint i;for (i = 0; i < N_SERVOS; i++) {servos[i].initServo(servoPins[i],stepDelay[i],servoInitPosition[i]);}#endif
}/* Enter the main loop.  Read and parse input from the serial portand run any valid commands. Run a PID calculation at the targetinterval and check for auto-stop conditions.
*/
void loop() {//读取串口命令while (Serial.available() > 0) {// Read the next characterchr = Serial.read();// Terminate a command with a CRif (chr == 13) {if (arg == 1) argv1[index] = NULL;else if (arg == 2) argv2[index] = NULL;runCommand();resetCommand();}// Use spaces to delimit parts of the commandelse if (chr == ' ') {// Step through the argumentsif (arg == 0) arg = 1;else if (arg == 1)  {argv1[index] = NULL;arg = 2;index = 0;}continue;}else {if (arg == 0) {// The first arg is the single-letter commandcmd = chr;}else if (arg == 1) {// Subsequent arguments can be more than one characterargv1[index] = chr;index++;}else if (arg == 2) {argv2[index] = chr;index++;}}}// If we are using base control, run a PID calculation at the appropriate intervals
#ifdef USE_BASEif (millis() > nextPID) {updatePID();//PID调速nextPID += PID_INTERVAL;}// Check to see if we have exceeded the auto-stop intervalif ((millis() - lastMotorCommand) > AUTO_STOP_INTERVAL) {;setMotorSpeeds(0, 0);moving = 0;}
#endif// Sweep servos
#ifdef USE_SERVOSint i;for (i = 0; i < N_SERVOS; i++) {servos[i].doSweep();}
#endif
}

这其中,需要关注的是基座控制器以及串口命令的相关部分,而由于没有使用舵机,所以舵机控制器部分暂不介绍。

1.串口命令

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

  • w 可以用于控制引脚电平
  • x 可以用于模拟输出

以LED灯控制为例,通过串口监视器录入命令:

  • w 13 0 == LED灯关闭
  • w 13 1 == LED灯打开
  • x 13 50 == LED灯PWM值为50
2.启用基座控制器

源码默认没有启用基座控制器、启用了舵机,我们需要启用基座控制器,禁用舵机。修改后代码如下:

#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/* L298 Motor driver*///#define L298_MOTOR_DRIVER
#endif//#define USE_SERVOS  // Enable use of PWM servos as defined in servos.h
#undef USE_SERVOS     // Disable use of PWM servos

注意:我们没有使用官方的电机驱动模块以及编码器,后期需要自定义电机驱动与编码器实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/10197.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android APP读写外置SD卡无权限 java.io.IOException: Permission denied

在物联网应用里&#xff0c;app需要对挂载SD卡读写文件&#xff0c;从 Android 4.4&#xff08;KitKat&#xff09;版本开始&#xff0c;Google 引入了一项名为 "Storage Access Framework" 的新功能&#xff0c;该功能限制了应用对外部存储的直接读写权限,要不然就是…

引入Minio

前置条件 官网&#xff1a;https://www.minio.org.cn/download.shtml#/kubernetes 命令 # 查看系统上的网络连接和监听端口信息 netstat -tpnl # 检查系统的指定端口占用情况 sudo netstat -tuln | grep 9000systemctl status firewalld # 临时关闭 systemctl stop firewall…

生信人写程序1. Perl语言模板及配置

生物信息领域常用语言 个人认为&#xff1a;是否能熟悉使用Shell(项目流程搭建)R(数据统计与可视化)Perl/Python/Java…(胶水语言&#xff0c;数据格式转换&#xff0c;软件间衔接)三门语言是一位合格生物信息工程师的标准。 生物信息常用语言非常广泛&#xff0c;我常用的有…

在macOS中开发的Django项目部署到局域网的Win10服务器上

由于windows10是日常办公电脑&#xff0c;没有服务器基本环境&#xff0c;部署工程耗费不少时间&#xff0c;记录一下。 1、安装Python 访问Python官方下载页面&#xff1a;Python Downloads&#xff0c;下载适用于Windows的安装程序并按照提示进行安装。开发环境python版本是…

Python可以自学但是千万不要乱学,避免“埋头苦学”的陷阱!

前言 Python可以自学但是千万不要乱学&#xff01; 归根结底因为学习是个反人性的过程&#xff01; 复盘没学下去的网课&#xff0c;都有以下特点&#xff1a; &#x1f605; 臣妾听不懂啊&#xff01; 初次接触编程遇到太多抽象高深的概念&#xff0c;不了解老师口中的一个…

基于51单片机的二氧化碳检测及调节系统仿真

基于51单片机的二氧化碳检测及调节系统 &#xff08;仿真&#xff0b;程序&#xff09; 功能介绍 具体功能&#xff1a; 1.二氧化碳传感器测得二氧化碳数据后经过单片机处理。 2.LCD1602实时显示&#xff0c;第一行显示测得的浓度值&#xff0c;第二行显示报警阈值。 3.测…

棱镜七彩参编《网络安全技术 软件供应链安全要求》国家标准发布

据全国标准信息公共服务平台消息显示&#xff0c;《网络安全技术 软件供应链安全要求》&#xff08;GB/T 43698-2024&#xff09;国家标准已于2024年4月25日正式发布&#xff0c;并将于2024年11月1日正式实施。棱镜七彩作为主要编制单位之一参与该国家标准的编制&#xff0c;为…

Taro 快速开始

大家好我是苏麟 , 今天聊聊Trao. 官网 : Taro 介绍 | Taro 文档 (jd.com) 点击快速开始 全局安装 CLI 初始化一个项目 选择配置 : 根据自己需求选择 安装失败先不用管 , 用前端工具打开项目 npm install 安装 , 显示安装失败 怎么解决 ? : 查看报错信息 百度 , 问 AI 工具 运…

算法练习第六十天|84. 柱状图中最大的矩形

84. 柱状图中最大的矩形 柱状图中最大的矩形 class Solution {public int largestRectangleArea(int[] heights) {int[] newHeight new int[heights.length 2];System.arraycopy(heights, 0, newHeight, 1, heights.length);newHeight[heights.length1] 0;newHeight[0] 0;…

算法学习笔记(最短路——spfa)

前置&#xff1a;bellman-ford s p f a spfa spfa是 B e l l m a n − F o r d Bellman-Ford Bellman−Ford算法的改进。在 B e l l m a n − F o r d Bellman-Ford Bellman−Ford中&#xff0c;我们在每一轮中枚举了每一条边&#xff0c;但是实际上&#xff0c;在上一轮中没有…

睿尔曼机械臂ROS控制

下载git工程 git clone https://github.com/RealManRobot/rm_robot.git安装配置 catkin build rm_msgs source devel/setup.bash catkin build source setup.bash这里注意&#xff0c;如果采用setup.sh多半不会成功&#xff0c;必须要source setup.bash文件&#xff0c;ros才…

train_gpt2_fp32.cu

源程序 llm.c/test_gpt2_fp32.cu at master karpathy/llm.c (github.com) #include <stdio.h> #include <stdlib.h> #include <math.h> #include <time.h> #include <assert.h> #include <float.h> #include <string.h> #include…

二叉树的最小深度和二叉树的节点数

二叉数的最小深度&#xff1a; 思路&#xff1a;和最大深度一样需要用到回溯递归的方法 代码大致内容 判断函数是否为空&#xff0c;如果是空return 0&#xff1b; 定义一个变量接收递归函数返回的值&#xff08;左&#xff09; 定义一个变量接收递归函数返回的值&#xf…

力扣每日一题-收集垃圾的最少总时间-2024.5.11

力扣题目&#xff1a;收集垃圾的最少总时间 题目链接: 2391.收集垃圾的最少总时间 题目描述 代码纯享版 class Solution {public int garbageCollection(String[] garbage, int[] travel) {int sum 0;int last_M -1,last_P -1, last_G -1;for(int i 0; i < garbage.…

以Azure为例的SSO

由于文章的篇幅有限&#xff0c;无法将全部的代码贴上来&#xff0c;如想要看完整案例&#xff0c;请在公众号文章中留言(其他平台很少看…毕竟最近印度同事的UI组件库搞得我好烦) 1.关于SSO 单点登录又称之为SSO,全称为 Single Sign On &#xff0c;一般在多个应用系统中&…

Github2024-05-10开日报 Top10

根据Github Trendings的统计&#xff0c;今日(2024-05-10统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量Python项目4TypeScript项目4JavaScript项目1Lua项目1C项目1Rust项目1Dart项目1 RustDesk: 用Rust编写的开源远…

U盘文件剪切丢失怎么办?揭秘原因并给出恢复方法

在日常生活和工作中&#xff0c;U盘已成为我们不可或缺的数据存储和传输工具。但有时候&#xff0c;我们在对U盘中的文件进行剪切操作时&#xff0c;会遇到文件丢失的情况。这种突如其来的数据消失往往会让人感到惊慌和困惑。那么&#xff0c;为什么U盘剪切时文件会丢失呢&…

运营模型—归因分析(Attribution Analysis)

运营模型—归因分析(Attribution Analysis) 随着互联网技术和业务的发展,广告投放相关的业务也随之兴起。那么广告投放的效果评估也就随之而来。广告的投放一般都是收费模式,所以选中的渠道商的好坏直接和自己的利益挂钩。于是,「归因分析」便最早应用在了广告投放行业。(…

IDEA 常见设置问题

OutOfMemoryError IDEA 第一次运行项目时&#xff0c;会报错误 - java.lang.OutOfMemoryError: Java heap space / insufficient memory&#xff0c;解决办法是&#xff1a; 将图示部分由默认的 700 改为 2048。 import * 工程lint检查时不允许使用import *&#xff0c;IDE…

Python中如何读取文件夹及其文件:使用os模块详解

路径os Python中如何读取文件夹及其文件&#xff1a;使用os模块详解引入os模块读取文件夹获取当前工作目录更改工作目录列出目录内容 读取文件夹下的文件检查是文件还是目录使用os.path.join()**重点内容**&#xff1a;**使用os模块来读取和管理文件及目录&#xff0c;特别是os…