<!-- .slide: data-background="https://i.imgur.com/gJLfldF.jpg" data-background-color="#111111" data-background-opacity="0.2" -->
###### tags: `iot-car` `lab` 返回[物聯網智慧自走車](/s/5c7ggGf0Spqql5Gy31Cqzg)
## 智慧物流 <br> <span style="color:#F9BF45;">自動化搬運系統</span>
###### [點我開啟簡報模式](/@BEExANT-ta/SJSxfhoOF#)
###### <kbd>ESC</kbd> 鍵進入總覽模式
###### <kbd>←</kbd> <kbd>↑</kbd> <kbd>↓</kbd> <kbd>→</kbd> 切換頁面
---
<center><img src="https://i.imgur.com/cB7XLlQ.jpg" width=30%></img></center>
每間大賣場都有自己的物流中心,每天要處理非常大量的貨,而其中的人力成本也是非常可觀,所以各大公司都會發展自己的自動化處理流程。
這單元將搭配[第一套教具的機械手臂](https://hackmd.io/@BEExANT-ta/js-iot/%2Fs%2F9ntHyjh0RBWR2NewpjNQLw),使自走車移動至取貨點時,控制手臂搬貨,再移動至卸貨點等待下一次取貨。
----
:::info
:globe_with_meridians: 參考資源
- [亞馬遜機器人 - 維基百科](https://en.wikipedia.org/wiki/Amazon_Robotics)
- [亞馬遜倉庫的「小革命」:服務好機器人,才能讓人類更安全](https://technews.tw/2019/01/25/amazon-built-an-electronic-vest-to-improve-worker-robot-interactions/)
:::
---
## 目標
**在任一車格旁擺放第一套教具的機械手臂作為搬貨點,另外一個車格作為卸貨點,使自走車能移動至搬貨點等待手臂搬貨完畢,再移動至卸貨點等待,重複以上動作至少三次。**
---
## 設計原理
- 網路設定請參考 [遠程控制網路設定](/s/UrpBFetqTfagugoaksoDCg)。
- 手臂遠程控制參考 [傑出的一手! - 遠程手臂控制](/s/s2K5DrGBTXmf8fdqP0l8Hg)。
- 指定顏色車格停車參考 [打造簡易車位辨識系統?! - 指定顏色區域停車](/s/J2S3MJ-vS5KM-0VFDUZDEA)。
- 結合以上實作,定義不同狀態來控制自走車與手臂。
---
## 流程圖
<center><img src="https://i.imgur.com/g95ZeSo.jpg"></img></center>
---
## 範例程式碼
新增程式檔並命名 ==自動化搬運系統==,將以下程式碼複製貼上程式編輯區執行。
```javascript=
window.state = "初始化";
window.enter_dir = "";
let armTop = 7;
let armMiddle = 6;
let armBottom = 5;
let idle_color = "黃";
let work_color = "綠";
let F = DATA.colorF[3];
let B = DATA.colorB[3];
let L = DATA.colorL[3];
let R = DATA.colorR[3];
let speed = 30;
console.log("目前狀態: " + state);
if(state == "等待卸貨"){
console.log("卸貨中...");
delay(3000);
led_color.set("綠");
delay(300);
state = "卸貨完畢";
console.log("卸貨完畢,準備退出卸貨點。");
}
if(state == "開始搬貨"){
console.log("搬貨中...");
remote_servo[armTop].set(60);
delay(1000);
remote_servo[armMiddle].set(30);
delay(1000);
remote_servo[armBottom].set(30);
delay(1000);
remote_servo[armMiddle].set(0);
delay(1000);
remote_servo[armTop].set(0);
delay(1000);
remote_servo[armMiddle].set(30);
delay(1000);
remote_servo[armBottom].set(160);
delay(1000);
remote_servo[armMiddle].set(0);
delay(1000);
led_color.set("綠");
delay(300);
state = "搬貨完畢";
console.log("搬貨完畢,準備退出搬貨點。");
}
if(F == idle_color && B == idle_color && L == idle_color && R == idle_color && state == "進入卸貨點")
{
state = "等待卸貨";
move_stop.set();
delay(300);
led_color.set("紅");
}
if(F == work_color && B == work_color && L == work_color && R == work_color && state == "進入搬貨點")
{
state = "開始搬貨";
move_stop.set();
delay(300);
led_color.set("紅");
}
if(F == "紫")
{
console.log("前方觸碰邊界,往後方移動");
move_backward.set(speed);
}
if(B == "紫")
{
console.log("後方觸碰邊界,往前方移動");
move_forward.set(speed);
}
if(state == "初始化")
{
state = "前往搬貨點";
move_forward.set(speed);
}
if(L == "白" && R == "黑" && (state == "前往搬貨點" || state == "前往卸貨點") )
{
console.log("車身向左偏移,向右校正");
move_right.set(speed);
delay(500);
}
if(L == "黑" && R == "白" && (state == "前往搬貨點" || state == "前往卸貨點") )
{
console.log("車身向右偏移,向左校正");
move_left.set(speed);
delay(500);
}
if(R == "黑" && L == work_color && state == "前往搬貨點")
{
state = "進入搬貨點";
enter_dir = "左";
delay(300);
move_stop.set();
delay(300);
move_left.set(speed);
}
if(L == "黑" && R == work_color && state == "前往搬貨點")
{
state = "進入搬貨點";
enter_dir = "右";
delay(300);
move_stop.set();
delay(300);
move_right.set(speed);
}
if(R == "黑" && L == idle_color && state == "前往卸貨點")
{
state = "進入卸貨點";
enter_dir = "左";
move_stop.set();
delay(300);
move_left.set(speed);
}
if(L == "黑" && R == idle_color && state == "前往卸貨點")
{
state = "進入卸貨點";
enter_dir = "右";
move_stop.set();
delay(300);
move_right.set(speed);
}
if(state == "搬貨完畢")
{
state = "退出搬貨點";
if(enter_dir == "左"){
move_right.set(speed);
}
else{
move_left.set(speed);
}
}
if(state == "卸貨完畢")
{
state = "退出卸貨點";
if(enter_dir == "左"){
move_right.set(speed);
}
else{
move_left.set(speed);
}
}
if(F == "黑" && B == "黑" && (L == "黑" || R == "黑") && state == "退出搬貨點")
{
state = "前往卸貨點";
delay(1200);
move_forward.set(speed);
}
if(F == "黑" && B == "黑" && (L == "黑" || R == "黑") && state == "退出卸貨點")
{
state = "前往搬貨點";
delay(1200);
move_forward.set(speed);
}
```
---
## 程式解說
逐行講解程式意義。
----
```javascript=
window.state = "初始化";
window.enter_dir = "";
```
- 定義全域變數state,記錄目前模式的變數。
- 定義全域變數enter_dir,記錄進入車格時的方向。
----
```javascript=
let armTop = 7;
let armMiddle = 6;
let armBottom = 5;
let idle_color = "黃";
let work_color = "綠";
let F = DATA.colorF[3];
let B = DATA.colorB[3];
let L = DATA.colorL[3];
let R = DATA.colorR[3];
let speed = 30;
```
- armTop、armMiddle、armBottom 分別代表控制手臂夾爪、中間、底部的伺服馬達腳位,這裡設定的765會對應到876這三個腳位。
- idle_color與work_color 分別代表卸貨區與搬貨區的顏色。
- F、B、L、R 為四個方向的顏色值。
- speed 為車子移動時的速度。
----
```javascript=
console.log("目前狀態: " + state);
```
- 每次迴圈皆會顯示目前state中的值。
----
```javascript=
if(state == "等待卸貨"){
console.log("卸貨中...");
delay(3000);
led_color.set("綠");
delay(300);
state = "卸貨完畢";
console.log("卸貨完畢,準備退出卸貨點。");
}
```
- 當 state 等於 等待卸貨 時,訊息顯示卸貨中,等待3秒後將led燈設為綠色,設定state為 卸貨完畢。
----
```javascript=
if(state == "開始搬貨"){
console.log("搬貨中...");
remote_servo[armTop].set(60);
delay(1000);
remote_servo[armMiddle].set(30);
delay(1000);
remote_servo[armBottom].set(30);
delay(1000);
remote_servo[armMiddle].set(0);
delay(1000);
remote_servo[armTop].set(0);
delay(1000);
remote_servo[armMiddle].set(30);
delay(1000);
remote_servo[armBottom].set(160);
delay(1000);
remote_servo[armMiddle].set(0);
delay(1000);
led_color.set("綠");
delay(300);
state = "搬貨完畢";
console.log("搬貨完畢,準備退出搬貨點。");
}
```
- 當 state 等於 開始搬貨 時,訊息顯示搬貨中,使用remote_servo[].set()發送遠端控制命令,中括號內的值對應到控制伺服馬達的腳位,小括號內的值則為角度。
- 結束後將led設為綠色,state設為 搬貨完畢。
----
```javascript=
if(F == idle_color && B == idle_color && L == idle_color && R == idle_color && state == "進入卸貨點")
{
state = "等待卸貨";
move_stop.set();
delay(300);
led_color.set("紅");
}
if(F == work_color && B == work_color && L == work_color && R == work_color && state == "進入搬貨點")
{
state = "開始搬貨";
move_stop.set();
delay(300);
led_color.set("紅");
}
```
- 當四個方向的顏色皆等於 卸貨區顏色idle_color 時,將state設為 等待卸貨,控制車子停止移動並將led設為紅色。
- 當四個方向的顏色皆等於 搬貨區顏色work_color 時,將state設為 開始搬貨,控制車子停止移動並將led設為紅色。
----
```javascript=
if(F == "紫")
{
console.log("前方觸碰邊界,往後方移動");
move_backward.set(speed);
}
if(B == "紫")
{
console.log("後方觸碰邊界,往前方移動");
move_forward.set(speed);
}
```
- 當前方顏色為紫時,控制車子往反方向移動,反之亦然。
----
```javascript=
if(state == "初始化")
{
state = "前往搬貨點";
move_forward.set(speed);
}
```
- 一開始state為 初始化 時,將state設為 前往搬貨點,控制車子向前移動。
----
```javascript=
if(L == "白" && R == "黑" && (state == "前往搬貨點" || state == "前往卸貨點") )
{
console.log("車身向左偏移,向右校正");
move_right.set(speed);
delay(500);
}
if(L == "黑" && R == "白" && (state == "前往搬貨點" || state == "前往卸貨點") )
{
console.log("車身向右偏移,向左校正");
move_left.set(speed);
delay(500);
}
```
- 當車子在車道上移動時,其中一方的顏色感測為白色時,控制車子往黑色的方向移動回到車道上。
----
```javascript=
if(R == "黑" && L == work_color && state == "前往搬貨點")
{
state = "進入搬貨點";
enter_dir = "左";
delay(300);
move_stop.set();
delay(300);
move_left.set(speed);
}
if(L == "黑" && R == work_color && state == "前往搬貨點")
{
state = "進入搬貨點";
enter_dir = "右";
delay(300);
move_stop.set();
delay(300);
move_right.set(speed);
}
```
- 當state為 前往搬貨點 且 左或右的顏色等於 搬貨區顏色work_color時,將state 設為 進入搬貨點,方向記錄enter_dir 設為進入的方向,控制車子暫停一下後進入車格。
----
```javascript=
if(R == "黑" && L == idle_color && state == "前往卸貨點")
{
state = "進入卸貨點";
enter_dir = "左";
move_stop.set();
delay(300);
move_left.set(speed);
}
if(L == "黑" && R == idle_color && state == "前往卸貨點")
{
state = "進入卸貨點";
enter_dir = "右";
move_stop.set();
delay(300);
move_right.set(speed);
}
```
- 當state為 前往卸貨點 且 左或右的顏色等於 卸貨區顏色idle_color時,將state 設為 進入卸貨點,方向記錄enter_dir 設為進入的方向,控制車子暫停一下後進入車格。
----
```javascript=
if(state == "搬貨完畢")
{
state = "退出搬貨點";
if(enter_dir == "左"){
move_right.set(speed);
}
else{
move_left.set(speed);
}
}
if(state == "卸貨完畢")
{
state = "退出卸貨點";
if(enter_dir == "左"){
move_right.set(speed);
}
else{
move_left.set(speed);
}
}
```
- 當狀態為 搬貨完畢 時,將state 設為 退出搬貨點,往進入時的反方向移動退出車格。
- 當狀態為 卸貨完畢 時,將state 設為 退出卸貨點,往進入時的反方向移動退出車格。
----
```javascript=
if(F == "黑" && B == "黑" && (L == "黑" || R == "黑") && state == "退出搬貨點")
{
state = "前往卸貨點";
delay(1200);
move_forward.set(speed);
}
if(F == "黑" && B == "黑" && (L == "黑" || R == "黑") && state == "退出卸貨點")
{
state = "前往搬貨點";
delay(1200);
move_forward.set(speed);
}
```
- 當前後方向且左或右其中一個為黑色 且 state 為 退出搬貨點時,表示車子已從車格退出至車道上,設定1.2秒的延遲使車子能先回到車道中間,這裡delay時間若越長,車子退出車格時的移動距離就會越長,最後再控制向前移動。
---
## 參數修改
為方便實作,以下會將範例程式中可修改的參數標示出來,進行實作時只需修改對應參數,並觀察結果即可。
:::warning
:zap: 詳細內建JS參數參考 - [內建Js參數及功能總覽](/s/wlfjvQBzRPCmJ8LCL3f2Fg)
:::
----
:::success
**let idle_color = "黃";
let work_color = "綠";**
:::
- idle_color 表示卸貨區車格的顏色,可更換成其他車格的顏色,不可與搬貨區顏色相同。
- work_color 表示搬貨區車格的顏色,可更換成其他車格的顏色,不可與卸貨區顏色相同。
----
:::success
**let armTop = 7;
let armMiddle = 6;
let armBottom = 5;**
:::
- armTop 表示控制手臂夾爪的腳位,設定7表示控制第8個馬達的腳位。
- armMiddle 表示控制手臂中間馬達的腳位,設定6表示控制第7個馬達的腳位。
- armBottom 表示控制手臂底部馬達的腳位,設定5表示控制第6個馬達的腳位。
---
## 範例影片
{%youtube KBZ87Y4ZDrM %}
<a class="btn btn-warning" style="width:100%;color:#333333;" href="/s/5c7ggGf0Spqql5Gy31Cqzg" role="button"> 物聯網智慧自走車 **⇨** </a>
<a class="btn btn-primary" style="width:100%;" href="/s/rVVZVo_rTg201uLszRsOYg" role="button"> **⇦** 自動停車系統
</a>
{"metaMigratedAt":"2023-06-16T15:09:33.689Z","metaMigratedFrom":"YAML","title":"智慧物流 - 自動化搬運系統","breaks":true,"slideOptions":"{\"transition\":\"slide\",\"transitionSpeed\":\"fast\",\"theme\":\"league\"}","contributors":"[{\"id\":\"a1db0c29-d848-4070-be84-9191a2398ca8\",\"add\":14070,\"del\":4312}]"}