我正在尝试使用从互联网上获得的代码通过串行通信接收命令来控制2个电机,目标是将ESP32与在Ubuntu 20.04中运行ROS2 Foxy的Raspberry Pi 4连接。我稍微修改了代码以与 ESP32 配合使用,因为它是为 arduino 板制作的(我也使用 ZS-X11H BLDC 电机驱动器,因为我使用的是悬浮滑板电机)。我在串行监视器中得到了这个:
模式:DIO,时钟分频:1 负载:0x3fce3818,长度:0x508 负载:0x403c9700,长度:0x4 负载:0x403c9704,长度:0xad0 负载:0x403cc700,长度:0x29e4 条目 0x403c9880 ESP-ROM:esp32s3-20210327
/*********************************************************************
* ROSArduinoBridge
A set of simple serial commands to control a differential drive
robot and receive back sensor and odometry data. Default
configuration assumes use of an Arduino Mega + Pololu motor
controller shield + Robogaia Mega Encoder shield. Edit the
readEncoder() and setMotorSpeed() wrapper functions if using
different motor controller or encoder method.
Created for the Pi Robot Project: http://www.pirobot.org
and the Home Brew Robotics Club (HBRC): http://hbrobotics.org
Authors: Patrick Goebel, James Nugen
Inspired and modeled after the ArbotiX driver by Michael Ferguson
Software License Agreement (BSD License)
Copyright (c) 2012, Patrick Goebel.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and/or other materials
provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT 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) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY 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
/* ZS-X11H Motor driver*/
#define ZS_X11H_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 115200
/* Maximum PWM signal */
#define MAX_PWM 255
#include <Arduino.h>
/* 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"
/* 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 cmdIndex = 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;
cmdIndex = 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:
Serial0.println(BAUDRATE);
break;
case ANALOG_READ:
Serial0.println(analogRead(arg1));
break;
case DIGITAL_READ:
Serial0.println(digitalRead(arg1));
break;
case ANALOG_WRITE:
analogWrite(arg1, arg2);
Serial0.println("OK");
break;
case DIGITAL_WRITE:
if (arg2 == 0) digitalWrite(arg1, LOW);
else if (arg2 == 1) digitalWrite(arg1, HIGH);
Serial0.println("OK");
break;
case PIN_MODE:
if (arg2 == 0) pinMode(arg1, INPUT);
else if (arg2 == 1) pinMode(arg1, OUTPUT);
Serial0.println("OK");
break;
case PING:
Serial0.println(Ping(arg1));
break;
#ifdef USE_SERVOS
case SERVO_WRITE:
servos[arg1].setTargetPosition(arg2);
Serial0.println("OK");
break;
case SERVO_READ:
Serial0.println(servos[arg1].getServo().read());
break;
#endif
#ifdef USE_BASE
case READ_ENCODERS:
Serial0.print(readEncoderLeft());
Serial0.print(" ");
Serial0.println(readEncoderRight());
break;
case RESET_ENCODERS:
resetEncoders();
resetPID();
Serial0.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;
Serial0.println("OK");
break;
case MOTOR_RAW_PWM:
/* Reset the auto stop timer */
lastMotorCommand = millis();
resetPID();
moving = 0; // Sneaky way to temporarily disable the PID
setMotorSpeeds(arg1, arg2);
Serial0.println("OK");
break;
case UPDATE_PID:
while ((str = strtok_r(p, ":", &p)) != nullptr) {
pid_args[i] = atoi(str);
i++;
}
Kp = pid_args[0];
Kd = pid_args[1];
Ki = pid_args[2];
Ko = pid_args[3];
Serial0.println("OK");
break;
#endif
default:
Serial0.println("Invalid Command");
break;
}
yield(); // Add yield to allow other tasks to run
}
/* Setup function--runs once at startup. */
void setup() {
Serial0.begin(BAUDRATE);
// Initialize the motor controller if used */
#ifdef USE_BASE
initMotorController();
resetPID();
initEncoders(); // Initialize encoders
#endif
/* Attach servos if used */
#ifdef USE_SERVOS
int 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 port
and run any valid commands. Run a PID calculation at the target
interval and check for auto-stop conditions.
*/
void loop() {
while (Serial0.available() > 0) {
// Read the next character
chr = Serial0.read();
// Terminate a command with a CR
if (chr == 13) {
if (arg == 1) argv1[cmdIndex] = NULL;
else if (arg == 2) argv2[cmdIndex] = NULL;
runCommand();
resetCommand();
}
// Use spaces to delimit parts of the command
else if (chr == ' ') {
// Step through the arguments
if (arg == 0) arg = 1;
else if (arg == 1) {
argv1[cmdIndex] = NULL;
arg = 2;
cmdIndex = 0;
}
continue;
}
else {
if (arg == 0) {
// The first arg is the single-letter command
cmd = chr;
}
else if (arg == 1) {
// Subsequent args are the command parameters
argv1[cmdIndex] = chr;
cmdIndex++;
}
else if (arg == 2) {
argv2[cmdIndex] = chr;
cmdIndex++;
}
}
yield(); // Add yield to allow other tasks to run
}
#ifdef USE_BASE
/* Are we due for another PID calculation? */
if (millis() > nextPID) {
updatePID();
nextPID += PID_INTERVAL;
}
/* Have we exceeded the auto-stop interval? */
if ((millis() - lastMotorCommand) > AUTO_STOP_INTERVAL) {
setMotorSpeeds(0, 0);
resetPID();
moving = 0;
}
yield(); // Add yield to allow other tasks to run
#endif
}
一直在网上寻找解决方案,例如添加yield()或使用Serial0而不是Serial,但没有解决。现在是凌晨 5 点,我迫切需要一个解决方案,我需要在两周内展示这个项目才能通过我的移动机器人课程,压力的增加是疯狂的。这是程序的其他文件的主要代码,在本次讨论中它们附加在 .zip 文件中(https://github.com/espressif/arduino-esp32/discussions/9993),因为我不这样做不想显示巨大的文本。
您是否尝试过使用SoftwareSerial库,对于ESP32,有一个名为:https://github.com/plerup/espsoftwareserial的特定库 我希望这能解决问题,祝你好运!