打印
[活动]

瑞萨FPB_RA6E2用Arduino驱动舵机的过程和代码

[复制链接]
125|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
丙丁先生|  楼主 | 2024-12-10 19:47 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
/*
MeArm机械臂控制程序-6
by 太极创客 (2017-06-02)
www.taichi-maker.com

本程序用于太极创客《零基础入门学用Arduino教程 - MeArm篇》。
1   使用串口获得电机数据,设置机械臂动作
    将串口指令解读改写为函数,加入状态汇报函数reportStatus
2   加入servoCmd函数控制电机速度
3   加入判断人类指令是否超出舵机限值
4   MeArm执行一系列动作(执行程序) armIniPos - 1 (一维数组)
5   MeArm执行一系列动作(执行程序) armIniPos - 2 (二维数组)
6   加入手柄控制模式
    加入机器判断:人类输入信息错误检查

如需要获得具体电路连接细节,请查阅太极创客制作的
《零基础入门学用Arduino教程 - MeArm篇》页面。

*/
#include <Servo.h>                //使用servo库

Servo myservo; // 创建一个Servo对象

Servo base, fArm, rArm, claw ;    //创建4个servo对象

/*Servo baseServo,rArmServo,fArmServo,clawServo; // 在全局作用域中声明变量
*/

// 创建四个Servo对象
Servo baseServo;
Servo shoulderServo;
Servo elbowServo;
Servo wristServo;

  char command; // 声明变量command

//Servo myservo; // 创建一个Servo对象
const int minAngle = 0; // 舵机的最小角度限制
const int maxAngle = 180; // 舵机的最大角度限制

// 创建两个Servo对象
/*Servo myservo1;
Servo myservo2;*/

// 定义连接到Arduino的LED引脚
int ledPin = 3;

// 定义摇杆的模拟输入引脚
/*const int potX = A0; // 左摇杆X轴连接到A0
const int potY = A1; // 左摇杆Y轴连接到A1
const int potRightX = A2; // 右摇杆X轴连接到A2
const int potRightY = A3; // 右摇杆Y轴连接到A3*/

// 定义摇杆的模拟输入引脚
const int potBase = A0;
const int potShoulder = A1;
const int potElbow = A3;
const int potWrist = A2;

// 定义舵机连接的数字引脚
const int basePin = 11;
const int shoulderPin = 10;
const int elbowPin = 9;
const int wristPin = 8;

//存储电机极限值(const指定该数值为常量,常量数值在程序运行中不能改变)
const int baseMin = 0;
const int baseMax = 180;
const int rArmMin = 45;
const int rArmMax = 180;
const int fArmMin = 35;
const int fArmMax = 120;
const int clawMin = 25;
const int clawMax = 100;

int DSD = 15; //Default Servo Delay (默认电机运动延迟时间)
              //此变量用于控制电机运行速度.增大此变量数值将
              //降低电机运行速度从而控制机械臂动作速度。
bool mode;  //mode = 1: 指令模式,  mode = 0: 手柄模式
int moveStep = 3;  // 每一次按下手柄按键,舵机移动量(仅适用于手柄模式)

void servoCmd(char servoName, int toPos, int servoDelay){  
  Servo servo2go;  //创建servo对象

  //串口监视器输出接收指令信息
  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){
        servo2go = base;
        fromPos = base.read();  // 获取当前电机角度值用于“电机运动起始角度值”
        break;
      } else {
        Serial.println("+Warning: Base Servo Value Out Of Limit!");
        return;
      }
  
    case 'c':
      if(toPos >= clawMin && toPos <= clawMax){   
        servo2go = claw;
        fromPos = claw.read();  // 获取当前电机角度值用于“电机运动起始角度值”
        break;
      } else {
        Serial.println("+Warning: Claw Servo Value Out Of Limit!");
        return;        
      }

    case 'f':
      if(toPos >= fArmMin && toPos <= fArmMax){
        servo2go = fArm;
        fromPos = fArm.read();  // 获取当前电机角度值用于“电机运动起始角度值”
        break;
      } else {
        Serial.println("+Warning: fArm Servo Value Out Of Limit!");
        return;
      }
         
    case 'r':
      if(toPos >= rArmMin && toPos <= rArmMax){
        servo2go = rArm;
        fromPos = rArm.read();  // 获取当前电机角度值用于“电机运动起始角度值”
        break;
      } else {
        Serial.println("+Warning: rArm Servo Value Out Of Limit!");
        return;
      }      
  }

  //指挥电机运行
  if (fromPos <= toPos){  //如果“起始角度值”小于“目标角度值”
    for (int i=fromPos; i<=toPos; i++){
      servo2go.write(i);
      delay (servoDelay);
    }
  }
  else { //否则“起始角度值”大于“目标角度值”
    for (int i=fromPos; i>=toPos; i--){
      servo2go.write(i);
      delay (servoDelay);
    }
  }
}

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("");
}

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++){
    servoCmd(robotIniPosArray[0], robotIniPosArray[1], robotIniPosArray[2]);
  }
}

void armDataCmd(char command);
         
void setup(){

  // 初始化串行通信
  Serial.begin(9600);

  // 将舵机连接到数字引脚
  baseServo.attach(basePin);
  shoulderServo.attach(shoulderPin);
  elbowServo.attach(elbowPin);
  wristServo.attach(wristPin);

  /*myservo.attach(7); // 将舵机连接到数字引7
  
  base.attach(11);     // base 伺服舵机连接引脚targetAngle11 舵机代号'b'
  delay(20);          // 稳定性等待
  rArm.attach(10);     // rArm 伺服舵机连接引脚10 舵机代号'r'
  delay(20);          // 稳定性等待
  fArm.attach(9);      // fArm 伺服舵机连接引脚9  舵机代号'f'
  delay(20);          // 稳定性等待
  claw.attach(8);      // claw 伺服舵机连接引脚6  舵机代号'c'
  delay(20);          // 稳定性等待
  */
/*
  base.write(90);
  delay(10);
  fArm.write(90);
  delay(10);
  rArm.write(90);
  delay(10);
  claw.write(90);  
  delay(10); */

  Serial.begin(9600);
  Serial.println("Welcome to Taichi-Maker Robot Arm Tutorial");
  Serial.println("Input mode: 1 (armDataCmd) & 0 (armJoyCmd)");
  delay(1000); // 等待3秒

   // 检查串行缓冲区是否有数据可读
  if (Serial.available() > 0){  
// 读取一个字符
    char serialCmd = Serial.read();
    // 打印接收到的命令到串行监视器,用于调试
    Serial.println("Received command: " + String(serialCmd));
    // 如果模式为1,调用armDataCmd函数处理命令
    if( mode == 1 ){
      armDataCmd(serialCmd); //指令模式
    }
   
      digitalWrite(LED_BUILTIN, HIGH); // 打开内置LED灯
      delay(1000); // 等待1秒
      digitalWrite(LED_BUILTIN, LOW); // 关闭内置LED灯   
  }
  else {
//      armJoyCmd(serialCmd); //手柄模式     
    }
pinMode(ledPin, OUTPUT); // 设置LED引脚为输出模式
  
}

void armDataCmd(char serialCmd){ //Arduino根据串行指令执行相应操作
                                 //指令示例:b45 底盘转到45度角度位置
                                 //          o 输出机械臂舵机状态信息
  //判断人类是否因搞错模式而输入错误的指令信息(指令模式下输入手柄按键信息)
  if (   serialCmd == 'w' || serialCmd == 's' || serialCmd == 'a' || serialCmd == 'd'
      || serialCmd == '5' || serialCmd == '4' || serialCmd == '6' || serialCmd == '8' ){
    Serial.println("+Warning: Robot in Instruction Mode...");
    delay(10);
    while(Serial.available()>0) char wrongCommand = Serial.read();  //清除串口缓存的错误指令
    return;
  }
                             
  if (serialCmd == 'b' || serialCmd == 'c' || serialCmd == 'f' || serialCmd == 'r'){
    int servoData = Serial.parseInt();
    servoCmd(serialCmd, servoData, DSD);  // 机械臂舵机运行函数(参数:舵机名,目标角度,延迟/速度)
  }
  else {
    switch(serialCmd){  

       // 使用switch语句根据接收到的命令执行不同的操作
  //switch (command) {
    case '1':
    // 如果命令是'1',打印信息并打开LED灯
    Serial.println("Command 'A' received: LED ON");
    digitalWrite(ledPin, HIGH); // 设置LED引脚为高电平,打开LED灯
    break; // 退出switch语句
    case 'B':
      // 如果命令是'c',打印信息并关闭LED灯
      Serial.println("Command 'c' received: LED OFF");
      digitalWrite(ledPin, LOW); // 设置LED引脚为低电平,关闭LED灯
      break; // 退出switch语句
      default:
      // 如果命令不是'A'或'B',打印未知命令信息
      Serial.println("Unknown command received");
      break; // 退出switch语句
     case 'm' :   //切换至手柄模式
        mode = 0;
        Serial.println("Command: Switch to Joy-Stick Mode.");
        break;
         
      case 'o':  // 输出舵机状态信息
        reportStatus();
        break;

      case 'i':
        armIniPos();  
        break;

          }
    }
  }  
void armJoyCmd(char serialCmd){ //Arduino根据手柄按键执行相应操作

     // 读取左摇杆的X轴和Y轴位置
  int leftX = analogRead(A0); // X轴位置
  int leftY = 1023 - analogRead(A1); // Y轴位置(取反)

  // 读取右摇杆的X轴和Y轴位置
  int rightX = analogRead(A3); // X轴位置
  int rightY = 1023 - analogRead(A2); // Y轴位置(取反)

  Serial.println("Command received: " + String(command));

  // 打印摇杆位置到串行监视器
  Serial.print("Left X: ");
  Serial.print(leftX);
  Serial.print(", Left Y: ");
  Serial.print(leftY);
  Serial.print(", Right X: ");
  Serial.print(rightX);
  Serial.print(", Right Y: ");
  Serial.println(rightY);

  delay(100); // 稍作延迟

  // 读取左摇杆的X轴和Y轴位置
/*  leftX = analogRead(potX);
  leftY = analogRead(potY);*/

  // 读取右摇杆的X轴和Y轴位置
/*  rightX = analogRead(potRightX);
  rightY = analogRead(potRightY);*/

  // 将模拟值映射到舵机角度(0-180度)
/*  int angleLeftX = map(leftX, 0, 1023, 0, 180);
  int angleLeftY = map(leftY, 0, 1023, 0, 180);
  int angleRightX = map(rightX, 0, 1023, 0, 180);
  int angleRightY = map(rightY, 0, 1023, 0, 180);*/

  // 打印摇杆位置到串行监视器
/* Serial.print("Left X: ");
  Serial.print(leftX);
  Serial.print(", Left Y: ");
  Serial.print(leftY);
  Serial.print(", Right X: ");
  Serial.print(rightX);
  Serial.print(", Right Y: ");
  Serial.println(rightY);*/

  // 根据摇杆位置设置舵机角度
/*myservo1.write(angleLeftX); // 控制左摇杆X轴对应的舵机
  myservo2.write(angleLeftY); // 控制左摇杆Y轴对应的舵机*/
  // 如果需要,也可以根据右摇杆的位置来控制舵机
   //myservo1.write(angleRightX);
   //myservo2.write(angleRightY);

  delay(15); // 等待舵机到达指定位置


  //判断人类是否因搞错模式而输入错误的指令信息(手柄模式下输入舵机指令)
  if (serialCmd == 'b' || serialCmd == 'c' || serialCmd == 'f' || serialCmd == 'r'){
    Serial.println("+Warning: Robot in Joy-Stick Mode...");
    delay(50);
    while(Serial.available()>0) char wrongCommand = Serial.read();  //清除串口缓存的错误指令
    return;
  }
     
  int baseJoyPos;
  int rArmJoyPos;
  int fArmJoyPos;
  int clawJoyPos;
  switch(serialCmd){

case '1' :   //切换至命令模式
        mode = 1;
        Serial.println("Command: Switch to armDataCmd Mode.");
        break;
   
    case 'a':  // Base向左
      Serial.println("Received Command: Base Turn Left");               
      baseJoyPos = base.read() - moveStep;
      servoCmd('b', baseJoyPos, DSD);
      break;  
      
    case 'd':  // Base向右
      Serial.println("Received Command: Base Turn Right");               
      baseJoyPos = base.read() + moveStep;
      servoCmd('b', baseJoyPos, DSD);
      break;        

    case 's':  // rArm向下
    Serial.println("Received Command: Rear Arm Down");               
      rArmJoyPos = rArm.read() + moveStep;
      servoCmd('r', rArmJoyPos, DSD);
      break;  
                  
    case 'w':  // rArm向上
      Serial.println("Received Command: Rear Arm Up");     
      rArmJoyPos = rArm.read() - moveStep;
      servoCmd('r', rArmJoyPos, DSD);
      break;  

    case '8':  // fArm向上
      Serial.println("Received Command: Front Arm Up");        
      fArmJoyPos = fArm.read() + moveStep;
      servoCmd('f', fArmJoyPos, DSD);
      break;  
      
    case '5':  // fArm向下
      Serial.println("Received Command: Front Arm Down");        
      fArmJoyPos = fArm.read() - moveStep;
      servoCmd('f', fArmJoyPos, DSD);
      break;  
      
    case '4':  // Claw关闭
      Serial.println("Received Command: Claw Close Down");        
      clawJoyPos = claw.read() + moveStep;
      servoCmd('c', clawJoyPos, DSD);
      break;  
      
    case '6':  // Claw打开
      Serial.println("Received Command: Claw Open Up");     
      clawJoyPos = claw.read() - moveStep;
      servoCmd('c', clawJoyPos, 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 loop(){
  // 读取摇杆的位置
  int basePos = analogRead(potBase);
  int shoulderPos = analogRead(potShoulder);
  int elbowPos = analogRead(potElbow);
  int wristPos = analogRead(potWrist);
  
/*int targetAngle = analogRead(A2); // 从模拟脚A0读取值,范围是0-1023
  // 将读取的模拟值映射到舵机的角度范围,并添加角度限制
  targetAngle = map(targetAngle, 0, 1023, minAngle, maxAngle);
  // 限制角度在0到180度之间
  targetAngle = constrain(targetAngle, 0, 180);
   myservo.write(targetAngle); // 设置舵机角度
delay(3); // 等待15毫秒观察效果*/

// 将摇杆的位置映射到舵机的角度范围
  basePos = map(basePos, 0, 1023, 0, 180);
  shoulderPos = map(shoulderPos, 0, 1023, 0, 180);
  elbowPos = map(elbowPos, 0, 1023, 0, 180);
  wristPos = map(wristPos, 0, 1023, 0, 180);

/*  int basePosition = map(analogRead(potX), 0, 1023, baseMin, baseMax);
  int rArmPosition = map(analogRead(potY), 0, 1023, rArmMin, rArmMax);
  int fArmPosition = map(analogRead(potRightX), 0, 1023, fArmMin, fArmMax);
  int clawPosition = map(analogRead(potRightY), 0, 1023, clawMin, clawMax);
*/

  // 设置舵机的角度
  baseServo.write(basePos);
  shoulderServo.write(shoulderPos);
  elbowServo.write(elbowPos);
  wristServo.write(wristPos);

/*  baseServo.write(basePosition);
  rArmServo.write(rArmPosition);
  fArmServo.write(fArmPosition);
  clawServo.write(clawPosition);*/

  // 打印摇杆的位置到串行监视器,用于调试
  Serial.print("Base: ");
  Serial.print(basePos);
  Serial.print(", Shoulder: ");
  Serial.print(shoulderPos);
  Serial.print(", Elbow: ");
  Serial.print(elbowPos);
  Serial.print(", Wrist: ");
  Serial.println(wristPos);
  
  if (Serial.available() > 0) {
    command = Serial.read();
    Serial.println("Received command: " + String(command));
  }

   // 呼吸灯效果:逐渐增加亮度,然后逐渐减少亮度
  for (int brightness = 0; brightness <= 200; brightness++) {
    // 设置LED的亮度
    analogWrite(ledPin, brightness);
    // 等待一段时间,以便人眼可以感知亮度变化
    delay(10);
  }
  for (int brightness = 200; brightness >= 0; brightness--) {
    // 设置LED的亮度
    analogWrite(ledPin, brightness);
    // 等待一段时间,以便人眼可以感知亮度变化
    delay(10);
  }
}

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

616

主题

2137

帖子

5

粉丝