---
# System prepended metadata

title: 機器人專題
tags: [arduino]

---

---
title: 機器人專題
tags: arduino

---
## 簡介
此課程我們使用 4DOF Mechanical Arm Kit V2.0 機器手臂套組來模擬怪手的機器運作原理，同時運用 Arduino 程式控制相關的操作，並以木塊當作夾取的物品。

---

## 使用材料
1. Arduino Uno V4.0 開發板
2. 擴充版
3. 機器手臂組
4. 馬達
5. 蘑菇鈕
6. 電池盒、電池
7. 一些電線和螺絲、螺帽
8. 藍芽模組 ([操作介面app](https://play.google.com/store/apps/details?id=com.keyestudio.keyes_arm_123&pli=1))
---

詳細材料規格如下圖:
![](https://i.imgur.com/1AMvIU7.jpg)

---

## 製作過程

---

### 組裝步驟
依照參考資料中的組裝步驟進行組裝，組裝完成後依照下表進行接線，並且編寫程式。




| 部件            | 連接腳位    |
| --------------- | ----------- |
| 遙控器Left X軸  | A2          |
| 底座馬達        | A0          |
| 遙控器Left Y軸  | A3          |
| 前手臂馬達      | A1          |
| 遙控器Right X軸 | A5          |
| 夾爪馬達        | 7(數字腳位) |
| 遙控器Right Y軸 | A4          |
| 後手臂馬達      | 6            |

---


### 程式編寫思維
1. 引入 Servo.h 函式庫
```arduino=1
#include<Servo.h>
```

---

2. 宣告四個變數 L_X, L_Y, R_X, R_Y，分別代表四個搖桿的讀值。
```arduino=3
int L_X =0;
int L_Y =0;
int R_X =0;
int R_Y =0;
```

---

3. 宣告四個變數 pos_LX, pos_LY, pos_RX, pos_RY，分別代表四個伺服馬達的初始位置。
```arduino=9
int pos_LX = 90;
int pos_LY = 60;
int pos_RX = 90;
int pos_RY = 45;
```

---

4. 宣告 Servo 型別的四個變數 MOTOR_LX, MOTOR_LY, MOTOR_RX, MOTOR_RY，分別代表四個伺服馬達。
```arduino=15
Servo MOTOR_LX,MOTOR_LY,MOTOR_RY,MOTOR_RX;
```

---

5. 分別定義四個函數`bottom()` `rear_hand()` `claw()` `rear_arm()` ，用來控制前手臂馬達、後手臂馬達、底座馬達、夾爪馬達，並且對個別馬達的轉動角度進行校正，最後個別設定馬達的延遲時間，因為篇幅的關係，底下的程式只列出其中馬達的函式，其他三個函式可見頁尾的完成程式碼區。
```arduino=17
void bottom(){
  L_X = analogRead(A2);
  // 搖桿向左
  if(L_X<50){
    if(pos_LX < 0){
      pos_LX = 0;
    
    }
    else{
      pos_LX=pos_LX-1;
      MOTOR_LX.write(pos_LX);
      delay(10);
  
    }
  }
  // 搖桿向右
  if(L_X>650){
    if(pos_LX > 180){
      pos_LX = 180;
    
      }
    else{
      pos_LX++;
      MOTOR_LX.write(pos_LX);
      delay(10);
  
    }
  }
}
```

---

6. 在 setup() 函式中，宣告並初始化四個伺服馬達，以及設定與電腦的溝通路徑和速度，如下:
```arduino=139
void setup() {
  MOTOR_LX.attach(A0);
  MOTOR_LY.attach(A1);
  MOTOR_RX.attach(7);
  MOTOR_RY.attach(6);
  Serial.begin(9600);
 }
```

---

7. 在 loop() 函式中，利用 Serial.println() 指令印出 pos_RY 的值，並依序執行前面定義的四個函式，最後延遲 10 毫秒。重複進行以上動作，如下:
```arduino=149
void loop(){
  Serial.println(pos_LY);
  claw();
  rear_arm();
  bottom();
  rear_hand();
}
```

---

## 遇到的困難

---

1. 底座組裝問題
原本按照組裝說明書一步步的安裝，但後來準備安裝開發板時發現無法安裝，後來仔細研究組裝的方位才發現原來一開始的底板裝錯方向，導致需要拆開重新組裝，造成進度嚴重落後

---

2. 馬達組裝問題
再安裝馬達的時候裝錯方向，導致編寫程式時，馬達超出轉動角度的限制，造成馬達過熱，後來經由微調程式改變馬達的角度建置，校正馬達回歸正常的運轉角度。

---

3. 組裝電路失誤
剛開始我們以為每個腳位皆可接受類比訊號，後來發現只有 Analog pin 的腳位才可以接收

4. RX TX 占用問題
如果項目中需要使用TX，RX口，那麼在上傳的時候一定不能把這兩個插上，否則會報錯，而且是各種奇怪的錯誤，典型就是會顯示：項目上傳出錯。
解決:等項目上傳成功後，再將TX，RX口插上。就好了
參考: [串口通信或TX/RX顯示上傳項目出錯](https://www.twblogs.net/a/5ef4daa7a383f019dfff0961)


---



## 參考資料
::: spoiler 手臂組裝與按鈕
<iframe src="https://drive.google.com/file/d/1vnT4L-yzVJtonMbBu-Fe49ow11-V5m-a/preview" width="640" height="480" allow="autoplay"></iframe>
:::

:::spoiler 延伸模組
<iframe src="https://drive.google.com/file/d/1etJxT14MhvON35VsX2gAK0TfDcTT6pIA/preview" width="640" height="480" allow="autoplay"></iframe>
:::

---

## 操作影片
:::spoiler 搖桿控制
<iframe src="https://drive.google.com/file/d/1xb5TNAyGyFC_sEF2SgTz1Tc26aD2tcOG/preview" width="640" height="480" allow="autoplay"></iframe>
:::

:::spoiler 藍芽模組控制
<iframe src="https://drive.google.com/file/d/1VUJ5it1U1nlBNwX_bN8sfEG3L4oI-xgY/preview" width="640" height="480" allow="autoplay"></iframe>
:::


---

## 分工表


| 項目              | 31312 邱紹瑋 | 31316 張閔盛 | 31322 黃冠霖 |
| ----------------- |:------------:|:------------:|:------------:|
| 組裝機械手臂      |      O       |      O       |      O       |
| 電路連接          |      O       |      O       |      O       |
| 編寫程式碼        |      O       |              |              |
| 簡報製作          |      O       |      O       |      O       |
| Hackmd 文字稿製作 |      O       |              |              |
| 上臺分享          |              |      O       |      O       |

---

## 機械手臂完整程式碼:
:::spoiler 遙感控制
 

```arduino=
#include<Servo.h>

int L_X =0;
int L_Y =0;
int R_X =0;
int R_Y =0;


int pos_LX = 90;
int pos_LY = 60;
int pos_RX = 90;
int pos_RY = 45;


Servo MOTOR_LX,MOTOR_LY,MOTOR_RY,MOTOR_RX;

void bottom(){
  L_X = analogRead(A2);
  // 搖桿向左
  if(L_X<50){
    if(pos_LX < 0){
      pos_LX = 0;
    
    }
    else{
      pos_LX=pos_LX-1;
      MOTOR_LX.write(pos_LX);
      delay(10);
  
    }
  }
  // 搖桿向右
  if(L_X>650){
    if(pos_LX > 180){
      pos_LX = 180;
    
      }
    else{
      pos_LX++;
      MOTOR_LX.write(pos_LX);
      delay(10);
  
    }
  }
}

void rear_hand(){
  L_Y = analogRead(A3);
  // 搖桿向下
  if(L_Y > 700){
    if(pos_LY < 0){
      pos_LY = 0;
    
    }
    else{
      pos_LY=pos_LY-1;
      MOTOR_LY.write(pos_LY);
      delay(15);
  
    }
  }
  // 搖桿向上
  if(L_Y < 300){
    if(pos_LY > 180){
      pos_LY = 180;
    
      }
    else{
      pos_LY++;
      MOTOR_LY.write(pos_LY);
      delay(15);
  
    }
  }  
  
  
}

void claw(){
  R_X = analogRead(A5);
  // 搖桿向左
  if(R_X<=300){
    if(pos_RX < 0){
      pos_RX = 0;
    
    }
    else{
      pos_RX=pos_RX-1;
      MOTOR_RX.write(pos_RX);
      delay(10);
  
    }
  }
  // 搖桿向右
  if(R_X>700){
    if(pos_RX > 180){
      pos_RX = 180;
    
      }
    else{
      pos_RX++;
      MOTOR_RX.write(pos_RX);
      delay(10);
  
    }
  }
}
void rear_arm(){
  R_Y = analogRead(A4);
  // 搖桿向下
  if(R_Y > 700){
    if(pos_RY > 90){
      pos_RY = 90;
    
    }
    else{
      pos_RY=pos_RY+1;
      MOTOR_RY.write(pos_RY);
      delay(15);
  
    }
  }
  // 搖桿向上
  if(R_Y < 400){
    if(pos_RY < 0){
      pos_RY = 0;
    
      }
    else{
      pos_RY--;
      MOTOR_RY.write(pos_RY);
      delay(15);
  
    }
  }
}


void setup() {
  // put your setup code here, to run once:
  MOTOR_LX.attach(A0);
  MOTOR_LY.attach(A1);
  MOTOR_RX.attach(7);
  MOTOR_RY.attach(6);

  Serial.begin(9600);
}

void loop() {
//  L_Y = analogRead(A3);
//  Serial.print("L_X:");
//  Serial.println(L_X);
//  Serial.print("L_Y:");
//  Serial.println(L_Y);

  Serial.println(pos_LY);
  claw();
  rear_arm();
  bottom();
  rear_hand();
  
}
```
:::

:::spoiler 藍芽控制
```arduino=
#include<Servo.h>

int L_X =0;
int L_Y =0;
int R_X =0;
int R_Y =0;


int pos_LX = 90;
int pos_LY = 60;
int pos_RX = 90;
int pos_RY = 45;

char val;
Servo MOTOR_LX,MOTOR_LY,MOTOR_RY,MOTOR_RX;

void left_XL(){
  pos_LX++;
  MOTOR_LX.write(pos_LX);
  delay(10);
  // 搖桿向左
  if(pos_LX < 0){
    pos_LX = 0;
    
  }

}


void left_XR(){
  pos_LX--;
  MOTOR_LX.write(pos_LX);
  delay(10);
  // 搖桿向右
  if(pos_LX > 180){
    pos_LX = 180;
    }
}

void left_YB(){
  // 搖桿向下
    pos_LY=pos_LY-1;
    MOTOR_LY.write(pos_LY);
    delay(10);
    if(pos_LY < 0){
      pos_LY = 0;
    }
}
  

void left_YF(){
  // 搖桿向上
    pos_LY++;
    MOTOR_LY.write(pos_LY);
    delay(10);
    if(pos_LY > 180){
      pos_LY = 180;
    }
}

void right_XL(){
  // 搖桿向左
    pos_RX=pos_RX-1;
    MOTOR_RX.write(pos_RX);
    //delay(10);
    
    if(pos_RX < 0){
      pos_RX = 0;
    }
}

void right_XR(){
  // 搖桿向右
    pos_RX++;
    MOTOR_RX.write(pos_RX);
    //delay(10);
    if(pos_RX > 60){
      pos_RX = 60;
      }
  }
void right_YB(){
  // 搖桿向下
    if(pos_RY > 90){
      pos_RY = 90;
    }
    pos_RY=pos_RY+1;
    MOTOR_RY.write(pos_RY);
    delay(10);
  }

void right_YF(){
  // 搖桿向上

    if(pos_RY < 0){
      pos_RY = 0;
    }
      pos_RY--;
      MOTOR_RY.write(pos_RY);
      delay(10);
}
    


void setup() {
  // put your setup code here, to run once:
  MOTOR_LX.attach(A0);
  MOTOR_LY.attach(A1);
  MOTOR_RX.attach(7);
  MOTOR_RY.attach(6);

  Serial.begin(9600);
}

void loop() {
//  L_Y = analogRead(A3);
//  Serial.print("L_X:");
//  Serial.println(L_X);
//  Serial.print("L_Y:");
//  Serial.println(L_Y);

  //Serial.println(pos_LY);
// 一般控制
//  claw();
//  rear_arm();
//  bottom();
//  rear_hand();
// 藍芽控制
Serial.println(pos_RX);
if(Serial.available()){
  val = Serial.read();
  Serial.println(val);
  }

switch(val)
{
  case 'L':
    while(val != 'S'){
      if(Serial.available()){
        val = Serial.read();
        Serial.println(val);
        }
      left_XL(); 
      } 
    break; //claw opens
  case 'R': 
    while(val != 'S'){
        if(Serial.available()){
          val = Serial.read();
          Serial.println(val);
        }
        left_XR(); 
      }
    break; //claw closes
  case 'F': 
    while(val != 'S'){
        if(Serial.available()){
          val = Serial.read();
          Serial.println(val);
        }
      left_YF();
      }
    break; //left servo swings forward
  case 'B': 
    while(val != 'S'){
        if(Serial.available()){
          val = Serial.read();
          Serial.println(val);
          
        }
        left_YB();
      } 
    break; //left servo swings back ward
  case 'f': 
    while(val != 'S'){
        if(Serial.available()){
          val = Serial.read();
          Serial.println(val);
        }
      right_YF(); 
      } 
    break; //right servo stretches out
  case 'b': 
    while(val != 'S'){
        if(Serial.available()){
          val = Serial.read();
          Serial.println(val);
          
        }
      right_YB();
      }  
    break; //right servo draws back
  case 'l': 
    while(val != 'S'){
        if(Serial.available()){
          val = Serial.read();
          Serial.println(val);
          
        }
      right_XL(); 
      
      } 
    break; //base servo turns left
  case 'r': 
    while(val != 'S'){
        if(Serial.available()){
          val = Serial.read();
          Serial.println(val);
          
        }
      right_XR(); 
      } 
    
    break; //base servo turns right
}
  
}
```
:::


---

## 作品照片

---

![](https://i.imgur.com/EfVP1BO.jpg)

---

![](https://i.imgur.com/HKv0JMj.jpg)

