Arduino基础学习:太极创客第二部分 – meArm机械臂详解

面包板电源模块为机器臂单独供电,机器臂本身有四个小电机驱动作用,如果单独靠arduino来为这四个小电机供电,机器臂可能不会稳定工作,将会抖动。

机械臂的四个动作主要靠四个电机来控制,这四个电机主要连接在我们的arduino控制器上,通过audino的编程,可以对这四个电机发送相应的指令,然后电机就会驱动机械臂做出相应的动作。

伺服电机

这四个电机学名叫做直流伺服电机(舵机)(下图为其结构)。

 输出轴上往往会加上一个摇臂,摇臂就会驱动我们想用电机驱动的那些外界的装置了,输出轴下面连接了一个电位器,输出轴在转动的时候,底下电位器也会跟着旋转,电位器旋转的过程中,电压信号就会随之改变,电压信号发送到控制电路上面,控制电路根据接受的信号判断我们的输出是否跟arduino上控制的信号相同,从而调整电机。

 

#include <Servo.h>

Servo myservo;  // create servo object to control a servo
// twelve servo objects can be created on most boards

int pos = 0;    // variable to store the servo position

void setup() {
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
}

void loop() {
  for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
    // in steps of 1 degree
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    //Serial.print(pos);
    delay(15);                       // waits 15 ms for the servo to reach the position
  }
  for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(15);                       // waits 15 ms for the servo to reach the position
  }
}

串口通讯

 

 

 

 

 

 

 

 

 

 

上面返回值是一个数字(代表有几个字节),下面返回值是一个字符型数值。 

 ​​​​​​​​​​​​​​

读取的完整过程: 

 

 如果串口接收的是多个字节:逐个进行读取,读取一个清除一个

 

 ​​​​​​​

 

 

  

控制伺服电机

控制一个电机

#include<Servo.h>

Servo myServo; //创建Servo对象myServo

int dataIndex = 0; //存储输入数据序列号
void setup(){
  myServo.attach(6);
  Serial.begin(9600); //启动串口通讯
  Serial.println(" Please input serial data.");
}

void loop(){ //检查串口缓存是否有数据等待传输
  if(Serial.available()>0){
    daaIndex++; //处理数据序列号并通过串口监视器显示
    Serial.print("dataIndex: ");
    Serial.print(dataIndex);
    Serial.print(",");

    int pos = Serial.parseInt(); //解析串口数据中的整数信息并赋值给变量pos
    Serial.print("Set servo postion:");
    Serial.println(pos); //通过串口监视器显示
    myServo.write(pos); //使用pos变量数值设置伺服电机
    delay(15);
  }
}

 结果图:

 控制四个电机

 

#include<Servo.h>

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

int dataIndex = 0; //存储输入数据序列号
void setup(){
  base.attach(11); //base 伺服电机链接引脚11  b
  rArm.attach(10); //rArm 伺服电机连接引脚10  r
  fArm.attach(9);  //fArm 伺服电机连接引脚9   f
  claw.attach(6);  //claw 伺服电机链接引脚6   c
  Serial.begin(9600); //启动串口通讯
  Serial.println(" Please input serial data.");
}

void loop(){ //检查串口缓存是否有数据等待传输
  if(Serial.available()>0){
    char servoName = Serial.read();//获取电机指令中电机编号信息
    
    Serial.print("servoName: ");
    Serial.print(servoName);
    Serial.print(",");

    int data = Serial.parseInt(); //获取电机指令中电机角度信息

    switch(servoName){ //根据电机指令中电机信息决定对哪一个电机进行角度设置
      case 'b': //电机指令b,设置base电机角度
        base.write(data);
        Serial.print("Set base servo value: ");
        Serial.pritnln(data);
        break;
      case 'r': //电机指令r,设置rArm电机角度
        rArm.write(data);
        Serial.print("Set rArm servo value: ");
        Serial.pritnln(data);
        break;
      case 'f': //电机指令f,设置rArm电机角度
        rArm.write(data);
        Serial.print("Set rArm servo value: ");
        Serial.pritnln(data);
        break;
      case 'c': //电机指令b,设置claw电机角度
        claw.write(data);
        Serial.print("Set claw servo value: ");
        Serial.pritnln(data);
        break;
    }
    
    Serial.print("Set servo postion:");
    Serial.println(pos); //通过串口监视器显示
    myServo.write(pos); //使用pos变量数值设置伺服电机
    delay(15);
  }
}

 meArm机械臂组装

调试meArm机械臂

#include <Servo.h>                //使用servo库
Servo base, fArm, rArm, claw ;    //创建4个servo对象
  
// 建立4个int型变量存储当前电机角度值
// 初始角度值为设备启动后初始状态所需要的电机角度数值
int basePos = 90;
int rArmPos = 90;
int fArmPos = 90;
int clawPos = 90;
 
//存储电机极限值(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;
 
void setup(){
  base.attach(11);     // base 伺服舵机连接引脚11 舵机代号'b'
  delay(200);          // 稳定性等待
  rArm.attach(10);     // rArm 伺服舵机连接引脚10 舵机代号'r'
  delay(200);          // 稳定性等待
  fArm.attach(9);      // fArm 伺服舵机连接引脚9  舵机代号'f'
  delay(200);          // 稳定性等待
  claw.attach(6);      // claw 伺服舵机连接引脚6  舵机代号'c'
  delay(200);          // 稳定性等待
  Serial.begin(9600); 
  Serial.println("Welcome to Taichi-Maker Robot Arm Tutorial.");   
}
 
void loop(){
  if (Serial.available()>0) {      //使用串口监视器输入电机指令控制机械臂电机
    char serialCmd = Serial.read();//指令举例: b45,将底盘舵机调整到45度位置
    armDataCmd(serialCmd);
  }
  base.write(basePos); 
  delay(10);
  fArm.write(fArmPos); 
  delay(10);
  rArm.write(rArmPos); 
  delay(10);
  claw.write(clawPos);  
  delay(10);   
}
 
void armDataCmd(char serialCmd){
   
  Serial.print("serialCmd = ");
  Serial.print(serialCmd);  
 
  int servoData = Serial.parseInt(); 
  switch(serialCmd){
    case 'b':  
      basePos = servoData;
      Serial.print("  Set base servo value: ");
      Serial.println(servoData);
      break;
    case 'c':  
      clawPos = servoData;
      Serial.print("  Set claw servo value: ");
      Serial.println(servoData);
      break;
    case 'f':  
      fArmPos = servoData;
      Serial.print("  Set fArm servo value: ");
      Serial.println(servoData);
      break;
    case 'r':  
      rArmPos = servoData;
      Serial.print("  Set rArm servo value: ");
      Serial.println(servoData);
      break;
    case 'o':  
      reportStatus();
      break;
    default:
      Serial.println(" Unknown Command.");
  }  
}
 
void reportStatus(){
  Serial.println("");
  Serial.println("");
  Serial.println("++++++ Robot-Arm Status Report +++++");
  Serial.print("Claw Position: clawPos = "); Serial.println(claw.read());
  Serial.print("Base Position: basePos = "); Serial.println(base.read());
  Serial.print("Rear  Arm Position: rArmPos = "); Serial.println(rArm.read());
  Serial.print("Front Arm Position: fArmPos = "); Serial.println(fArm.read());
  Serial.println("++++++++++++++++++++++++++++++++++++");
  Serial.println("");
}

 控制机械臂运行速度(顺畅完成指令)

 就是要进行舵机转动速度控制

#include <Servo.h>                //使用servo库
Servo base, fArm, rArm, claw ;    //创建4个servo对象
 
// 建立4个int型变量存储当前电机角度值
// 初始角度值为设备启动后初始状态所需要的电机角度数值
int basePos = 90;
int rArmPos = 90;
int fArmPos = 90;
int clawPos = 90;
 
//存储电机极限值(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;
 
void setup(){
  base.attach(11);     // base 伺服舵机连接引脚11 舵机代号'b'
  delay(200);          // 稳定性等待
  rArm.attach(10);     // rArm 伺服舵机连接引脚10 舵机代号'r'
  delay(200);          // 稳定性等待
  fArm.attach(9);      // fArm 伺服舵机连接引脚9  舵机代号'f'
  delay(200);          // 稳定性等待
  claw.attach(6);      // claw 伺服舵机连接引脚6  舵机代号'c'
  delay(200);          // 稳定性等待
  Serial.begin(9600); 
  Serial.println("Welcome to Taichi-Maker Robot Arm Tutorial");   
}
 
void loop(){
  if (Serial.available()>0) {      //使用串口监视器输入电机指令控制机械臂电机
    char serialCmd = Serial.read();//指令举例: b45,将底盘舵机(舵机代号'b')调整到45度位置
    armDataCmd(serialCmd);
  }
 
  base.write(basePos); 
  delay(10);
  fArm.write(fArmPos); 
  delay(10);
  rArm.write(rArmPos); 
  delay(10);
  claw.write(clawPos);  
  delay(10);   
}
 
void armDataCmd(char serialCmd){ 
  Serial.print("serialCmd = ");
  Serial.print(serialCmd);  

  int fromPos; //起始位置
  int toPos; //目标位置
  
  int servoData = Serial.parseInt(); 
  switch(serialCmd){
    case 'b':  
      fromPos = base.read();//把舵机底盘当前的位置信息读出来
      toPos = servoData;
      //流畅过度到目标位置
//      for(int i =fromPos;i<=toPos;i++){ //b135->b90,这个便不执行
//        base.write(i);
//        delay(15);
//      }
      if(fromPos<=toPos){
        for(int i =fromPos;i<=toPos;i++){ //b135->b90,这个便不执行
          base.write(i);
          delay(15);
        }
      }
      else{
         for(int i =fromPos;i>=toPos;i--){ //b135->b90,这个便不执行
          base.write(i);
          delay(15);
        }
      }
      basePos = servoData;
      Serial.print("  Set base servo value: ");
      Serial.println(servoData);
      break;
    case 'c':  
      clawPos = servoData;
      Serial.print("  Set claw servo value: ");
      Serial.println(servoData);
      break;
    case 'f':  
      fArmPos = servoData;
      Serial.print("  Set fArm servo value: ");
      Serial.println(servoData);
      break;
    case 'r':  
      rArmPos = servoData;
      Serial.print("  Set rArm servo value: ");
      Serial.println(servoData);
      break;
    case 'o':  
      reportStatus();
      break;
    default:
      Serial.println(" Unknown Command.");
  }  
}
 
void reportStatus(){
  Serial.println("");
  Serial.println("");
  Serial.println("++++++ Robot-Arm Status Report +++++");
  Serial.print("Claw Position: clawPos = "); Serial.println(claw.read());
  Serial.print("Base Position: basePos = "); Serial.println(base.read());
  Serial.print("Rear  Arm Position: rArmPos = "); Serial.println(rArm.read());
  Serial.print("Front Arm Position: fArmPos = "); Serial.println(fArm.read());
  Serial.println("++++++++++++++++++++++++++++++++++++");
  Serial.println("");
}

 开发机械臂程序

控制机械臂速度函数封装优化:

#include <Servo.h>                //使用servo库
Servo base, fArm, rArm, claw ;    //创建4个servo对象
 
//存储电机极限值(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 (默认电机运动延迟时间)
              //此变量用于控制电机运行速度.增大此变量数值将
              //降低电机运行速度从而控制机械臂动作速度。
 
void setup(){
  base.attach(11);     // base 伺服舵机连接引脚11 舵机代号'b'
  delay(200);          // 稳定性等待
  rArm.attach(10);     // rArm 伺服舵机连接引脚10 舵机代号'r'
  delay(200);          // 稳定性等待
  fArm.attach(9);      // fArm 伺服舵机连接引脚9  舵机代号'f'
  delay(200);          // 稳定性等待
  claw.attach(6);      // claw 伺服舵机连接引脚6  舵机代号'c'
  delay(200);          // 稳定性等待
 
  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");   
}
 
 
void loop(){
  if (Serial.available()>0) {  
    char serialCmd = Serial.read();
    armDataCmd(serialCmd);
  }
}
 
void armDataCmd(char serialCmd){ //Arduino根据串行指令执行相应操作
                                 //指令示例:b45 底盘转到45度角度位置
                                 //          o 输出机械臂舵机状态信息
  if (serialCmd == 'b' || serialCmd == 'c' || serialCmd == 'f' || serialCmd == 'r'){
    int servoData = Serial.parseInt();
    servoCmd(serialCmd, servoData, DSD);  // 机械臂舵机运行函数(参数:舵机名,目标角度,延迟/速度)
  } else {
    switch(serialCmd){    
      case 'o':  // 输出舵机状态信息
        reportStatus();
        break;
      default:  //未知指令反馈
        Serial.println("Unknown Command.");
    }
  }  
}
 
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("");
}

键盘控制机械臂程序初版

#include <Servo.h>                //使用servo库
Servo base, fArm, rArm, claw ;    //创建4个servo对象
 
//存储电机极限值(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 (默认电机运动延迟时间)
              //此变量用于控制电机运行速度.增大此变量数值将
              //降低电机运行速度从而控制机械臂动作速度。
 
void setup(){
  base.attach(11);     // base 伺服舵机连接引脚11 舵机代号'b'
  delay(200);          // 稳定性等待
  rArm.attach(10);     // rArm 伺服舵机连接引脚10 舵机代号'r'
  delay(200);          // 稳定性等待
  fArm.attach(9);      // fArm 伺服舵机连接引脚9  舵机代号'f'
  delay(200);          // 稳定性等待
  claw.attach(6);      // claw 伺服舵机连接引脚6  舵机代号'c'
  delay(200);          // 稳定性等待
 
  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");   
}
 
 
void loop(){
  if (Serial.available()>0) {  
    char serialCmd = Serial.read();
    armDataCmd(serialCmd);
  }
}
 
void armDataCmd(char serialCmd){ //Arduino根据串行指令执行相应操作
                                 //指令示例:b45 底盘转到45度角度位置
                                 //          o 输出机械臂舵机状态信息
  if (serialCmd == 'b' || serialCmd == 'c' || serialCmd == 'f' || serialCmd == 'r'){
    int servoData = Serial.parseInt();
    servoCmd(serialCmd, servoData, DSD);  // 机械臂舵机运行函数(参数:舵机名,目标角度,延迟/速度)
  } else {
    switch(serialCmd){    
      case 'o':  // 输出舵机状态信息
        reportStatus();
        break;
 
      case 'i':
        armIniPos();  
        break;
 
      case 'p':
        playDice();  
        break;
         
      default:  //未知指令反馈
        Serial.println("Unknown Command.");
    }
  }  
}
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[i][0], robotIniPosArray[i][1], robotIniPosArray[i][2]);
  }
}
void playDice(){
  Serial.println("+Command: Let's play some dice!");
  
  armIniPos();
  
  int diceMove1[21][3] = {
    {'c', 30, DSD},
    {'b', 90, DSD},
    {'f', 43, DSD},
    {'r', 126, DSD}, 
    {'c', 90, DSD},    
    {'r', 90, DSD},
    {'b', 60, DSD},  
    {'f', 36, DSD},  
    {'r', 135, DSD},   
    {'c', 30, DSD},
    {'r', 90, DSD},  
    {'b', 90, DSD}, 
    {'f', 36, DSD},  
    {'r', 135, DSD},  
    {'c', 90, DSD},  
    {'r', 90, DSD},
    {'b', 60, DSD},   
    {'f', 48, DSD},  
    {'r', 123, DSD},    
    {'c', 30, DSD},  
    {'r', 90, DSD}, 
  };
  for (int i = 0; i < 21; i++){
    servoCmd(diceMove1[i][0], diceMove1[i][1], diceMove1[i][2]);
    delay(200);
  }     
  
  armIniPos();
 
  int diceMove2[21][3]{
    {'c', 30, DSD}, 
    {'b', 58, DSD},     
    {'f', 48, DSD},  
    {'r', 120, DSD},     
    {'c', 90, DSD},  
    {'r', 90, DSD},  
    {'b', 90, DSD},   
    {'f', 36, DSD},   
    {'r', 135, DSD},  
    {'c', 30, DSD},
    {'r', 90, DSD},    
    {'b', 60, DSD},  
    {'f', 36, DSD},
    {'r', 135, DSD},   
    {'c', 95, DSD},    
    {'r', 90, DSD},    
    {'b', 90, DSD},     
    {'f', 43, DSD},  
    {'r', 125, DSD},   
    {'c', 30, DSD},  
    {'r', 90, DSD},      
  };
  
  for (int i = 0; i < 21; i++){
    servoCmd(diceMove2[i][0], diceMove2[i][1], diceMove2[i][2]);
    delay(200);
  }   
 
  armIniPos();  
}

键盘控制机械臂程序终版(灵活版,不固定位置)

#include <Servo.h>                //使用servo库
Servo base, fArm, rArm, claw ;    //创建4个servo对象

//存储电机极限值(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 setup(){
  base.attach(11);     // base 伺服舵机连接引脚11 舵机代号'b'
  delay(200);          // 稳定性等待
  rArm.attach(10);     // rArm 伺服舵机连接引脚10 舵机代号'r'
  delay(200);          // 稳定性等待
  fArm.attach(9);      // fArm 伺服舵机连接引脚9  舵机代号'f'
  delay(200);          // 稳定性等待
  claw.attach(6);      // claw 伺服舵机连接引脚6  舵机代号'c'
  delay(200);          // 稳定性等待

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

void loop(){
  if (Serial.available()>0) {  
    char serialCmd = Serial.read();
    if( mode == 1 ){
      armDataCmd(serialCmd); //指令模式
    } else {
      armJoyCmd(serialCmd); //手柄模式
    }
  }
}

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(100);
    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){   

      case 'm' :   //切换至手柄模式 
        mode = 0; 
        Serial.println("Command: Switch to Joy-Stick Mode.");
        break;
        
      case 'o':  // 输出舵机状态信息
        reportStatus();
        break;

      case 'i':
        armIniPos();  
        break;
         
      default:  //未知指令反馈
        Serial.println("Unknown Command.");
    }
  }  
}

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

  //判断人类是否因搞错模式而输入错误的指令信息(手柄模式下输入舵机指令)
  if (serialCmd == 'b' || serialCmd == 'c' || serialCmd == 'f' || serialCmd == 'r'){
    Serial.println("+Warning: Robot in Joy-Stick Mode...");
    delay(100);
    while(Serial.available()>0) char wrongCommand = Serial.read();  //清除串口缓存的错误指令
    return;
  } 
 
  
  int baseJoyPos;
  int rArmJoyPos;
  int fArmJoyPos;
  int clawJoyPos;
  switch(serialCmd){
    case 'a':  // Base向左
      Serial.println("Received Command: Base Turn Left");                
      baseJoyPos = base.read() - moveStep; //read获取角度
      ser voCmd('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 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[i][0], robotIniPosArray[i][1], robotIniPosArray[i][2]);
  }
}

HC06蓝牙模块——仅作为一个传输工具,无另外的程序编写

 

 

 

 
/*
---- 电路连接 ---- 
HC-06     Arduino Uno R3 引脚
TX                0 (RX)  
RX                1 (TX)
VCC              +5v
GND              GND
 
LED       Arduino Uno R3 引脚
 +                11 (RX) 
 -                GND (通过220欧姆限流电阻)
 
注意:
1. 须使用分压电路,确保HC-06 RX信号电压为3.3伏特。
2. 须先将此程序上传至ARDUINO后,再将HC-06连接在ARDUINO开发板的串口引脚上。
   否则程序将无法正常上传。
 
*/
int brightness;  //LED亮度变量
int serialData;  //串口数据变量
 
void setup() {
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(11, OUTPUT);
}
 
void loop(){
  if( Serial.available()>0 ){             //如果串口缓存有数据
    serialData =  Serial.parseInt();      //将串口缓存数值存储到serialData变量
    Serial.print("serialData = "); Serial.println(serialData);  
    if (serialData >=0 && serialData <= 255) {  
      if (serialData >= brightness){       //逐渐调节LED亮度
        for (brightness; brightness <= serialData; brightness++){
          analogWrite(11, brightness); 
          Serial.print("brightness = "); Serial.println(brightness);  
          delay(5);
        }      
      } else {
        for (brightness; brightness >= serialData; brightness--){
          analogWrite(11, brightness); 
          Serial.print("brightness = "); Serial.println(brightness);          
          delay(5);          
        }        
      }       
    }     
  }   
}

 

 

物联沃分享整理
物联沃-IOTWORD物联网 » Arduino基础学习:太极创客第二部分 – meArm机械臂详解

发表评论