第 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.pswp.cn/web/10197.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/10197.shtml
英文地址,請注明出處:http://en.pswp.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…