로봇팔 코드

/*

web site : http://www.7gp.cn

pins: 
11/10/9/5 : Servo base/left/right/gripper
*/
#include <Servo.h> 
#include <SoftwareSerial.h>

SoftwareSerial mySerial(12, 13);     // hc06 bluetooth rx/tx
const int SERVOS = 4, MAXSPEED = 10; // servo pin 11/10/9/5 base/left/right/gripper
int PIN[SERVOS], value[SERVOS], currentAngle[SERVOS], MIN[SERVOS], MAX[SERVOS], INITANGLE[SERVOS];
Servo myservo[SERVOS];
int aOrg[] = {90, 90, 90};  // initial angle for base/left/right arm arm
int demoActions[9][4] = { { 90,  55, 165, 30},    // demo mode by pressing right button when boot 
                          { 45, 145,  90,  0},
                          { 90,  55, 165,  0},
                          {135, 145,  90, 30},
                          { 90,  55, 165, 30},
                          {135, 145,  90,  0},
                          { 90,  55, 165,  0},
                          { 45, 145,  90, 30},
                          { 90,  55, 165, 30}                          
                       };
                      
int DELAYTIME = 200;
int servo_moving[SERVOS] = {0,0,0,0};
boolean stringComplete = false;
int bt_servo = 0;
int bt_move = 0;
int idle[] = {0,0,0,0};
boolean learningMode = false, autoPlayMode = false, autoDemoMode = false;
boolean clawClosed = false, bootbuttonPressed = false;
int const maxAutoActions = 100;
int autoAction[maxAutoActions][SERVOS];  // can record up to 20 actions
int actionIndex = 0;  // total steps of an movement
int buttonPreState = 0;
int buttonL = 2, buttonR = 4;
int threshL = 300, threshR = 700;
int clawOpenangle = 10, clawCloseangle = 102;
int demospeed = 1;  //1 for 1x, 2 for 2x...

void setup() {
  Serial.begin(9600);    // RX/TX = D0/D1
  pinMode(2, INPUT_PULLUP);  //2 to memorize 
  pinMode(4, INPUT_PULLUP);  //4 to start actions
  pinMode(3, OUTPUT);  
  digitalWrite(3, HIGH);
  Serial.print(digitalRead(buttonL));
  Serial.print(" , ");
  Serial.println(digitalRead(buttonR));
  
  mySerial.begin(38400); // RX/TX = D12/D13 for bluetooth 
  
  init_Pins();
  cutcut();              

  // long press left button for recording mode
  if (!digitalRead(buttonL)) {
    learningMode = true;
    buttonPreState = 1;
    delay(1000);
    digitalWrite(3, LOW);
    Serial.println("learningMode!!");
  }
  
  // long press right button for demo mode
  if (!digitalRead(buttonR)) {
    autoDemoMode = true;
    buttonPreState = 1;
    auto_mode();
  }
}

void loop() {
  move_bt();            // move based on instruction from bluetooth
  move_joy();           // move based on instruction from joystick
  move_mem();           // move based on instruction from recording
}

void init_Pins(){
  PIN[0] = 11;          // pin to attach servo
  MIN[0] = 10;           // minimal angle of this servo based on mechanic structure
  MAX[0] = 140;         // maximum angle of this servo based on mechanic structure
  INITANGLE[0] = 90;    // initial angle at start up
  PIN[1] = 10;
  MIN[1] = 10;
  MAX[1] = 179;
  INITANGLE[1] = 90;
  PIN[2] = 9;
  MIN[2] = 40;
  MAX[2] = 170;
  INITANGLE[2] = 90;
  PIN[3] = 5;
  MIN[3] = 0;
  MAX[3] = 70;
  INITANGLE[3] = 60;
  //set motors to initial angles
  initMotors();
  
  // reset autoaction angles to record
  for (int i = 0 ; i < maxAutoActions; i++){
    for (int j = 0 ; j < SERVOS; j++){
      autoAction[i][j] = 0;
    }
  }
  // set autoAction[0][] = aOrg[];
  for (int i = 0 ; i < SERVOS-1; i++){
    autoAction[0][i] = aOrg[i];
  }
  autoAction[0][SERVOS-1] = clawOpenangle;
}

void move_bt(){ 
  checkSoftSerial();  // read bluetooth and set servo_moving[i] for each servo, format +1/0/-1

  for (int i = 0; i < SERVOS; i++){
    currentAngle[i] = myservo[i].read();  // get existing serveo angle
    
    if (servo_moving[i] != 0){
      currentAngle[i] += servo_moving[i];  // +/- angles based on the info from bluetooth
      currentAngle[i] = currentAngle[i] > MAX[i] ? --currentAngle[i] : currentAngle[i];  // ensure target angle within safe range 
      currentAngle[i] = currentAngle[i] < MIN[i] ? ++currentAngle[i] : currentAngle[i];
      myservo[i].write(currentAngle[i]);  // rotate each servo
      delay(20);
    }
  }
}

// read from bluetooth and illustrate into angle change
// the format is 2 digit like "31", the first digit is servo , the 2nd digit is 1 or 2 for +/- angle
void checkSoftSerial() {
  String str = "";
  
  if (mySerial.available()){
    for (int i = 0 ; i < 2; i++){
      str += (char)mySerial.read(); 
    }
    // the servo to move
    int value = str.toInt();
    bt_servo = value / 10;
    
    // the direction to move
    int angle = value % 10;
    if (angle == 2) bt_move = 1;
    else if (angle == 1) bt_move = -1;
    else bt_move = 0;

    servo_moving[bt_servo] = bt_move;  // so we set +1/0/-1 into array to be used in move_bt() 
  }
}

void move_joy(){
  boolean joyChanged = false;
  
  for (int i = 0; i < SERVOS; i++){
    value[i] = analogRead(i);              // read the joystick value from analog port 0~3
    delay(2);
    currentAngle[i] = myservo[i].read();   // get existing angles    
   
      if (value[i] > threshR) {
        idle[i] = 0;      // reset idle because someone touch the joystick
        joyChanged = true;
        if (currentAngle[i] > MIN[i]) --currentAngle[i]; // adjust the angle according to joystick direction
        if (i == SERVOS-1) currentAngle[i] = clawCloseangle;            // for claw, only open/close mode
      } else if (value[i] < threshL) {
        idle[i] = 0;
        joyChanged = true;
        if (currentAngle[i] < MAX[i]) ++currentAngle[i]; 
        if (i == SERVOS-1) currentAngle[i] = clawOpenangle;
      } else {
        ++idle[i];22;
        //myservo[i].detach();  // optional: detach servo after idle for a while
        idle[i] = 0;
      }
 
  }      
  if (joyChanged){  
    for (int i = 0 ; i < SERVOS; i++){
      // before write angle , let's attach servo if not
      if (!myservo[i].attached()) myservo[i].attach(PIN[i]);      
      myservo[i].write(currentAngle[i]);
    }  
  }
  delay(20);
}

// memorize the actions
void move_mem(){
  if (!autoPlayMode){
    if (learningMode){
      //Serial.println("learningMode");
      // if one of any button pressed, memorize the angles
      if (!digitalRead(buttonR)) {
        // done recoding, going to auto play
        autoPlayMode = true;
        return;
      }
      int buttonPressed = !digitalRead(buttonL);
      //Serial.print("buttonPressed = ");
      //if (buttonPressed) Serial.println("buttonPressed");
      delay(1);
      
      
      if (buttonPreState && buttonPressed) return; // repeated count of the same press
      else if (!buttonPreState && buttonPressed){  // Left button pressed to record
      actionIndex++;
        buttonPreState = true;
        if (actionIndex < maxAutoActions){
          Serial.print("actionIndex = ");
          Serial.println(actionIndex);
          for(int i = 0; i < SERVOS; i++){
            int tmp = myservo[i].read();
            Serial.print(tmp);
            Serial.print(" , ");
            autoAction[actionIndex][i] = tmp;
          }
          Serial.println("");
          
          
          if (actionIndex == maxAutoActions) autoPlayMode = true;
        }
      } else buttonPreState = buttonPressed;
      
      if (!digitalRead(buttonR)) { // Right button pressed
        autoPlayMode = true;
      }
    }
  } else {
    // auto Playing Mode
    autoPlay();
  }
  //delay(100);
}

// open and close the claw 2 times
void cutcut(){
  delay(1000);
  for (int i = 0; i < 2; i++){
    closeclaw(true);
    delay(150);
    closeclaw(false);
    delay(150);
  }
}

// auto mode for demo purpose, can be paused any time if joystick is touched
void auto_mode(){
  int elements = sizeof(demoActions) / (4*sizeof(int));
  Serial.print("elements = ");
  Serial.println(elements);
  cutcut();
  while(1){
    for (int i = 0; i < elements-1; i++){
      if (buttonPressed()) {
        learningMode = false;
        autoPlayMode = false;
        autoDemoMode = false;
        return;  
      }
      armfromto(demoActions[i], demoActions[i+1]);
    }
  } 
}

//play recorded mode
void autoPlay(){
  digitalWrite(3, HIGH);
  // moving from current to the first position
  //Serial.print("autoPlay: last one to 0 : total ");
  //Serial.println(actionIndex);
  //armfromto(autoAction[actionIndex], autoAction[0]);
  initMotors();
  delay(1000);
  cutcut();  
  
  while(1){    
    for (int i = 0; i < actionIndex; i++){     
      Serial.println("start playing...");
      
      // pause if joystick touched, resume if touch again
      if (buttonPressed()) {
        learningMode = false;
        autoPlayMode = false;
        autoDemoMode = false;
        return;
      }
      Serial.print("autoplay : ============="); 
      Serial.println(i);
      armfromto(autoAction[i], autoAction[i+1]);
    }
    delay(500/demospeed);
    armfromto(autoAction[actionIndex], autoAction[0]);  //back to the first action
    delay(500/demospeed);
  }
}

// rotate all servos at a time smoothly by using "for" loop and delay(30) 
void armfromto(int *arrf, int *arrt){
  int maxAngles = 0;
  float lp[4];

  // adjust speed
  adjustSpeed();
      
  maxAngles = max(max(abs(arrt[0] - arrf[0]), abs(arrt[1] - arrf[1])), abs(arrt[2] - arrf[2]));
  maxAngles /= demospeed;
  maxAngles = maxAngles < 1 ? 1 : maxAngles;  
  Serial.print("speed = ");
  Serial.println(demospeed); 
  
  for (int i = 0; i < SERVOS-1; i++){  
   // Serial.print(arrt[i] - arrf[i]);
   // Serial.print(" "); 
  }
  //Serial.println(" === Delta");
  
  for (int i = 0; i < SERVOS-1; i++){    
    lp[i] = float(arrt[i] - arrf[i])/float(maxAngles);
    //Serial.print(lp[i]);
    //Serial.print(" "); 
    //Serial.println();
  }
  
  for (int j = 1; j <= maxAngles; j++){

    for (int i = 0; i < SERVOS-1; i++){
      
      //Serial.print(arrf[i]+j*lp[i]); 
      //Serial.print(" "); 
      myservo[i].write(arrf[i]+j*lp[i]);      
    }
   // Serial.print(" === "); 
   // Serial.println(j); 
    
    delay(20);
  } 
  // the claw
  myservo[SERVOS-1].write(arrt[SERVOS-1]);
  delay(20);  
    
  if (autoPlayMode || autoDemoMode){
    //Serial.print("claw angle: ");
    //Serial.println(clawCloseangle);
    //myservo[SERVOS-1].write(arrt[SERVOS-1]);
    //delay(20);  
  }
}

// close the claw
void closeclaw(boolean op){
  if (op){
    myservo[SERVOS-1].write(clawCloseangle);
  } else {
    myservo[SERVOS-1].write(clawOpenangle);
  }
}

// check if joystick touched to stop the auto mode
boolean joystickTouched(){
  int tmp = 500;
  
  for (int i = 0; i < SERVOS; i++){
    tmp = analogRead(i);
    delay(1);
    if (tmp > threshR || tmp < threshL) return true;
  }
  
  return false;
}

void initMotors(){
  // attach servos to pins
  for (int i = 0; i < SERVOS; i++){
    myservo[i].attach(PIN[i]);
    myservo[i].write(INITANGLE[i]);
    value[i] = 0;
    idle[i] = 0;
  }  
}

void adjustSpeed(){
  //if (learningMode) {
    for (int i = 0; i < SERVOS; i++){
  //    if(i>0){
        if (analogRead(i) > threshR) demospeed++;
        if (analogRead(i) < threshL) demospeed--;
  //    }
  //    if(i=0){
  //      if (analogRead(i) < threshR) demospeed++;
  //      if (analogRead(i) > threshL) demospeed--;
  //    }
    }
    demospeed = demospeed < 1 ? 1 : demospeed;
    demospeed = demospeed > MAXSPEED ? MAXSPEED : demospeed;
  //}
}

boolean buttonPressed(){
  //return true when any button pressed and not previously pressed
  if(!buttonPreState && (!digitalRead(buttonR) || !digitalRead(buttonL))) {
    buttonPreState = 1;
    return true;
  } else if (digitalRead(buttonR) && digitalRead(buttonL)){
    buttonPreState = 0;
  }
  return false;  
}