esp32舵机机械臂

本文详细介绍了如何使用ESP32控制meArm机械臂,包括设置四个舵机,实现串口和蓝牙通信,以及在手柄模式和命令模式下的伺服动作控制。
摘要由CSDN通过智能技术生成

前言

参考【太极创客】零基础入门学用Arduino 第二部分 meArm机械臂 合辑_哔哩哔哩_bilibili

主要是使用esp32控制四个舵机,学会使用串口通讯以及蓝牙通讯。

代码部分

#include <ESP32Servo.h>
#include <Arduino.h>
#include <BluetoothSerial.h>


#define SERVO_base   2   //电机接口
#define SERVO_rArm   4
#define SERVO_fArm   5
#define SERVO_claw   18
#define MAX_WIDTH   2500 //脉宽范围50ms~2500ms
#define MIN_WIDTH   500

//存储电机极限值(const指定该数值为常量,常量数值在程序运行中不能改变)
const int baseMin = 0;
const int baseMax = 180;
const int rArmMin = 30;
const int rArmMax = 180;
const int fArmMin = 50;
const int fArmMax = 180;
const int clawMin = 70;
const int clawMax = 100;
int DSD = 15; //Default Servo Delay (默认电机运动延迟时间)
int moveStep = 3;  //手柄模式步进角度
bool mode = 0; //手柄与命令模式 0手柄 1命令
// 定义 servo 对象
Servo base, rArm, fArm, claw;  //建立4个电机对象  底座、大臂、小臂、夹子
BluetoothSerial SerialBT;  //蓝牙对象
void reportStatus();  //舵机状态信息
void servoMove(char servoName, int toPos, int servoDelay);  //电机移动
void armCmd(char serialCmd);   //命令模式
void armJoy(char serialCmd); //手柄模式
void armIniPos();   //初始化电机角度

void setup()
{
  Serial.begin(9600); //开启串口
  // 分配硬件定时器
  ESP32PWM::allocateTimer(0);
  // 设置频率
  base.setPeriodHertz(50);
  rArm.setPeriodHertz(50);
  fArm.setPeriodHertz(50);
  claw.setPeriodHertz(50);
  // 关联 servo 对象与 GPIO 引脚,设置脉宽范围
  base.attach(SERVO_base, MIN_WIDTH, MAX_WIDTH);
  rArm.attach(SERVO_rArm, MIN_WIDTH, MAX_WIDTH);
  fArm.attach(SERVO_fArm, MIN_WIDTH, MAX_WIDTH);
  claw.attach(SERVO_claw, MIN_WIDTH, MAX_WIDTH);
  //初始化电机角度
  base.write(90); 
  delay(10);
  fArm.write(90); 
  delay(10);
  rArm.write(90); 
  delay(10);
  claw.write(90);  
  delay(10); 
 
  reportStatus();//输出当前电机角度信息
  Serial.begin(9600);
  SerialBT.begin("eh"); // 如果没有参数传入则默认是蓝牙名称是: "ESP32"
  Serial.printf("BT initial ok and ready to pair. \r\n");
}

void loop()
{
    if (Serial.available()>0) {  
      char serialCmd = Serial.read();
      delay(10);
      SerialBT.write(serialCmd);
      delay(10);
      if( mode == 1 ){
        armCmd(serialCmd); //指令模式
      } else {
        armJoy(serialCmd); //手柄模式
      }
    }
    
    if (SerialBT.available())
    {
        //Serial.write(SerialBT.read());
        char serialCmd = SerialBT.read();
        Serial.print("  ");
        Serial.write(serialCmd);
        Serial.println("  ");
        if( mode == 1 ){
          armCmd(serialCmd); //指令模式
        } else {
          armJoy(serialCmd); //手柄模式
        }
    }

}

void armJoy(char serialCmd) //手柄模式
{
  int baseJoyPos;
  int rArmJoyPos;
  int fArmJoyPos;
  int clawJoyPos;
  switch(serialCmd)
  {
    case 'a':
      Serial.println("Received Command: a");
      baseJoyPos = base.read()+moveStep;
      servoMove('b',baseJoyPos,DSD);
      break;
    case 'd':
      Serial.println("Received Command: d");
      baseJoyPos = base.read()-moveStep;
      servoMove('b',baseJoyPos,DSD);
      break;
    case 'w':
      Serial.println("Received Command: w");
      baseJoyPos = rArm.read()+moveStep;
      servoMove('r',baseJoyPos,DSD);
      break;
    case 's':
      Serial.println("Received Command: s");
      baseJoyPos = rArm.read()-moveStep;
      servoMove('r',baseJoyPos,DSD);
      break;
    case '8':
      Serial.println("Received Command: 8");
      baseJoyPos = fArm.read()+moveStep;
      servoMove('f',baseJoyPos,DSD);
      break;
    case '5':
    Serial.println("Received Command: 5");
    baseJoyPos = fArm.read()-moveStep;
    servoMove('f',baseJoyPos,DSD);
    break;
    case '4':
    Serial.println("Received Command: 4");
    baseJoyPos = claw.read()+moveStep;
    servoMove('c',baseJoyPos,DSD);
    break;
    case '6':
    Serial.println("Received Command: 6");
    baseJoyPos = claw.read()-moveStep;
    servoMove('c',baseJoyPos,DSD);
    break;
     case 'm' :   //切换至指令模式 
      mode = 1; 
      Serial.println("Command: Switch to Instruction Mode.");
      break;
    case 'o':  
      reportStatus();
      break;
    case 'i':  
      armIniPos();
      break;
    default:
      Serial.println("Unknown Command.");
      return;
      
  }
}

void armCmd(char serialCmd)   //命令模式
{
    if (serialCmd == 'b' || serialCmd == 'c' || serialCmd == 'f' || serialCmd == 'r'){
    int servoData = Serial.parseInt();
    servoMove(serialCmd, servoData, DSD);  // 机械臂舵机运行函数(参数:舵机名,目标角度,延迟/速度)
  } else {
    switch(serialCmd){    
      case 'o':  // 输出舵机状态信息
        reportStatus();
        break;
      case 'i':
        armIniPos();  
        break;
      case 'm' :   //切换至手柄模式 
        mode = 0; 
        Serial.println("Command: Switch to Joy-Stick Mode.");
        break; 
      default:  //未知指令反馈
        Serial.println("Unknown Command.");
    }
  } 
}


void armIniPos(){   //初始化电机角度
  Serial.println("+Command: Restore Initial Position.");
  int robotIniPosArray[4][3] = {
    {'b', 90, DSD},
    {'r', 90, DSD},
    {'f', 90, DSD},
    {'c', 90, DSD} 
  };   
 
  for (int i = 0; i < 4; i++){
    servoMove(robotIniPosArray[i][0], robotIniPosArray[i][1], robotIniPosArray[i][2]);
  }
}

void servoMove(char servoName, int toPos, int servoDelay)  //电机移动
{
  //串口监视器输出接收指令信息
  Serial.println("");
  Serial.print("+Command: Servo ");
  Serial.print(servoName);
  Serial.print(" to ");
  Serial.print(toPos);
  Serial.print(" at servoDelay value ");
  Serial.print(servoDelay);
  Serial.println(".");
  Serial.println("");  

  int fromPos; //建立变量,存储电机起始运动角度值
  switch(servoName){
    case 'b':
      if(toPos >= baseMin && toPos <= baseMax){
        fromPos = base.read();  // 获取当前电机角度值用于“电机运动起始角度值”
        if (fromPos <= toPos){  //如果“起始角度值”小于“目标角度值”
              for (int i=fromPos; i<=toPos; i++){
                base.write(i);
                delay (servoDelay);
                //Serial.println(base.read());
            }
            }  else { //否则“起始角度值”大于“目标角度值”
              for (int i=fromPos; i>=toPos; i--){
                base.write(i);
                delay (servoDelay);
                //Serial.println(base.read());
              }
            
          }
        break;
      } else {
        Serial.println("+Warning: Base Servo Value Out Of Limit!");
        return;
      }
 
    case 'c':
      if(toPos >= clawMin && toPos <= clawMax){
        fromPos = claw.read();  // 获取当前电机角度值用于“电机运动起始角度值”
        if (fromPos <= toPos){  //如果“起始角度值”小于“目标角度值”
              for (int i=fromPos; i<=toPos; i++){
                claw.write(i);
                delay (servoDelay);
                //Serial.println(claw.read());
            }
            }  else { //否则“起始角度值”大于“目标角度值”
              for (int i=fromPos; i>=toPos; i--){
                claw.write(i);
                delay (servoDelay);
               // Serial.println(claw.read());
              }
            
          }
        break;
      } else {
        Serial.println("+Warning: Claw Servo Value Out Of Limit!");
        return;        
      }
 
    case 'f':
      if(toPos >= fArmMin && toPos <= fArmMax){
        fromPos = fArm.read();  // 获取当前电机角度值用于“电机运动起始角度值”
        if (fromPos <= toPos){  //如果“起始角度值”小于“目标角度值”
              for (int i=fromPos; i<=toPos; i++){
                fArm.write(i);
                delay (servoDelay);
                //Serial.println(fArm.read());
            }
            }  else { //否则“起始角度值”大于“目标角度值”
              for (int i=fromPos; i>=toPos; i--){
                fArm.write(i);
                delay (servoDelay);
                //Serial.println(fArm.read());
              }
            
          }
        break;
      } else {
        Serial.println("+Warning: fArm Servo Value Out Of Limit!");
        return;
      }
         
    case 'r':
      if(toPos >= rArmMin && toPos <= rArmMax){
        fromPos = rArm.read();  // 获取当前电机角度值用于“电机运动起始角度值”
        if (fromPos <= toPos){  //如果“起始角度值”小于“目标角度值”
              for (int i=fromPos; i<=toPos; i++){
                rArm.write(i);
                delay (servoDelay);
                //Serial.println(rArm.read());
            }
            }  else { //否则“起始角度值”大于“目标角度值”
              for (int i=fromPos; i>=toPos; i--){
                rArm.write(i);
                delay (servoDelay);
                //Serial.println(rArm.read());
              }
            
          }
        break;
      } else {
        Serial.println("+Warning: rArm Servo Value Out Of Limit!");
        return;
      }      
  }

}

void reportStatus(){  //舵机状态信息
  Serial.println("");
  Serial.println("");
  Serial.println("+ Robot-Arm Status Report +");
  Serial.print("Claw Position: "); Serial.println(claw.read());
  Serial.print("Base Position: "); Serial.println(base.read());
  Serial.print("Rear  Arm Position:"); Serial.println(rArm.read());
  Serial.print("Front Arm Position:"); Serial.println(fArm.read());
  Serial.println("++++++++++++++++++++++++++");
  Serial.println("");
}

  • 16
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值