---
# System prepended metadata

title: 109-2 電資工程入門設計與實作 第六組 工作紀錄簿
tags: [109-2, 電資工程入門設計與實作]

---

# 109-2 電資工程入門設計與實作 第六組 工作紀錄簿

## 成員

* 班別：週三上午班
* 組員1：楊　珩 B09901029
* 組員2：徐以帆 B09901023
* 組員3：張哲銘 B09901156

---

```mermaid
gantt
    dateFormat  MM-DD
    axisFormat  %b-%d
    title       車車課的歷史演變
    excludes    weekends
    section 軟體
    馬達控制程式    :done, 03-31,04-01
    循跡(P,PD)    :done, 03-31,04-08
    藍芽連線       :done, 04-09,04-21
    讀懂sample code    :done, 04-20,04-28
    地圖尋路分析    :crit, done, 04-28,05-07
    優化程式&架構改良    :done, 05-02,05-08
    自選題控制程式    :crit, active, 05-25,06-05
    控制優化    :future, 06-01,06-20

    section 硬體
    基礎車體組裝    :done, 03-22,03-31
    車體改良    :crit, done, 04-28,05-04
    自選題車體改良    :crit, active, 05-25,06-05
    車體優化    :future, 06-01,06-20

    section 討論
    CHECKPOINT!    :done,  05-03,05-05
    指定題比賽    :crit, done, 05-10,05-12
    指定題檢討    :done, 05-13,05-17
    自選題發想    :active, 05-18, 05-28
    自選題proposal    :crit, future, 05-24,05-26
    自選題demo    :crit, future, 06-29,07-01
```

---

## 第四週紀錄 - BFS

* BFS concept  
  ![BFS example](https://i.imgur.com/IhpqoiY.gif)

* pytest  
  ![pytest all pass](https://i.imgur.com/2npwUYL.jpg)

* 需要寫的程式碼如下:

  ```python
  def get_shortest_path(self, nd_from, nd_to):
    if nd_from == nd_to:
      print(0)
      return [nd_to]
    data_queue = queue.PriorityQueue()
    data_queue.put((0, nd_from))
  
    pi_function = dict()
    pi_function[nd_from] = None
  
    arrived = False
    while (not data_queue.empty()) and (not arrived):
      cur_data = data_queue.get()
      cur_len = cur_data[0]
      cur_nd = cur_data[1]
      nd_list = self.adjacency_list[cur_nd].get_neighbors()
      for next_nd in nd_list:
        if not next_nd in pi_function:
          next_len = cur_len + 1
          data_queue.put((next_len, next_nd))
          pi_function[next_nd] = cur_nd
          if next_nd == nd_to:
            arrived = True
            length = next_len
            break
  
    path = list()
    nd = nd_to
    while nd:
      path.append(nd)
      nd = pi_function[nd]
    path.reverse()
    
    return path
  ```

## 第五週紀錄 - 組車

* 課堂應完成事項(**下課前必須找助教檢查**)
  * 車子組裝完成Part 1(前側柱、馬達座)
  * 車子組裝完成Part 2(下盤)
  * 車子組裝完成Part 3(中盤)
  * 車子組裝完成Part 4(上蓋)
  * 車子通電可動作

> 給助教檢查
> 組裝完成
> 電池通電完成
> 訊號線未完成
> [name=呂英弘]

### 3/24課堂

* **實際達成事項 (必填)**
  * 底板、側板、ㄇ形板及前板等**車體結構組裝完成**
  * 電源接頭、開關及馬達**電線焊接完成**
  * 電源、開關、降壓模組、L298N控制模組、馬達、紅外線感應模組、RFID感應模組及Arduino開發板等**電子元件安裝完成**
  * 前輪(金屬萬向輪)及後輪(橡膠輪)安裝完成
  * **高壓電路**(電池、開關、降壓模組、L298N控制模組、馬達及Arduino開發板電源)**接線完成**  
  ![車體組裝成品](https://i.imgur.com/0Va0L1v.jpg)
* **組內討論事項 (必填，如問題、構想、分工合作、時間安排...等等)**
  * 問題
    * **焊錫較難附著**於車體上的部分金屬(如連接Arduino板的插孔頭)
    * 部分元件內的導線非常靠近，**容易短路**
    * 安裝好紅外線模組後，**擔心**安裝其他元件時**施壓會損壞感應器**
    * 擴充板針腳多，安裝時**不方便施壓**
    * 組裝側板時，要留意四個角落螺帽的擺放位置，若放置**傾斜**會導致螺絲無法順利轉入。且側板的三片木板須**彼此鎖緊**，否則在鎖四個角落的螺帽時會發生**空轉**的情形
    * **按照投影片指示**的電線長度製作，實際**接線時卻發現長度不夠**
    * 部分**螺絲孔的位置被側板包圍**，無法順利用手將螺絲擺入螺絲孔
  * 分工合作
    * 兩位組員負責取材料，一位拿取一位點收，**增加效率**，另一位組員先行組裝不會用到螺絲的部分(如ㄇ型板)，其餘步驟如下詳細說明
  * 時間安排
    * 因本組本週有兩位組員遲到，因此到班時先深刻檢討自己的過失，並保證以後絕對會**提早到班**，此關乎學習態度問題
    * 課堂上先知道可能會有課堂上無法組裝完成的可能性，因此先討論出**在晚上(禮拜三)open lab時段進行趕工**，順便討論今天組裝所發生的問題以及相關解決方案
  * 美觀
    * 觀察雷切木板的兩側，選取**變色痕跡較少的那側朝外**(在兩側都能夠使用的前提下進行)
    * 電線顏色要用相對應顏色的絕緣膠帶進行包覆
    * 電線必須要**排列整齊**，除了美觀外也考慮到後續遇到問題時**解決問題的便利性**
* **組員分工 (必填)**
  * 分頭進行車體組裝
    * 左側板、右側板、ㄇ型板，因ㄇ型板組裝較為簡單，所以組裝完成先進行焊接步驟
    * 完整車體組裝時，一名組員負責指導步驟，另外兩位組員進行車體組裝。
  * 電源相關焊接及各模組安裝
    * 因銲槍數量有限，一組員在進行焊接時，其他組員則開始進行紅外線等模組的安裝以避免浪費時間
* **遇到問題之處理狀況、解決方式 (必填)**
  * 焊錫難附著
    * 先**將電線纏繞固定**以此增加穩定度，或者由另一人負責固定
  * 導線容易短路
    * 貼上**絕緣膠帶**
  * 擔心感應器受損
    * 使用充電器外盒當作**車體支架**
  * 安裝擴充板
    * 使用內附的**保麗龍墊片**
  * 螺帽角度傾斜
    * 在將螺帽安裝進木板時，必須**確認螺帽的角度能與上下板平行**，之後在鎖螺絲時才能順利轉入
  * 電線長度不足
    * **焊接一段電線**延長  
      ![焊接電線](https://i.imgur.com/8PDe2pc.jpg)
  * 螺絲孔被遮擋
    * **用老虎鉗**夾緊螺絲釘頭並放入相對應螺絲孔
* **課程建議 (選填)**
  * Arduino電源使用的電線需要改為 20~25 cm 才夠長
* **想說的話 (選填)**
  * 待填

### 3/24 open lab

* **實際達成事項 (必填)**
  * **藍牙模組安裝完成**
  * **低壓電路**(Arduino開發板相關I/O)**接線完成**  
    **=> 車體完全組裝完成**
  * **上傳測試程式**(包含RFID、藍牙、紅外線、馬達)至Arduino開發板  
    **=> 測試成功**
* **組內討論事項 (必填，如問題、構想、分工合作、時間安排...等等)**
  * 問題
    * 安插杜邦線時容易**對錯插孔**
  * 觀察
    * 實際進行車體運行測試時，發現車體在以自己為中心**旋轉時的軸心並不是車體的對稱中心**，推論原因為**車體配重不均**，左輪負重較大導致右輪打滑或左輪轉速較慢
  * 自選題發想
    * 升降平台 -> X型升降機構 -> 螺桿 or 氣壓缸
* **遇到問題之處理狀況、解決方式 (必填)**
  * 杜邦線
    * 從整排杜邦線上直接**拔取相鄰的線**，不僅可以避免杜邦線變得鬆散錯亂不易整理，同時也能**清楚辨識顏色的不同，以及所對應的插孔**，如此一來在定義腳位時也能夠清楚分辨

## 第五週批閱區 - 組車

* 助教批閱欄
  * 助教回饋
    * 紀錄的很完整，有進度，也有發現到的問題以及解決方法。使用粗體字標記重點對於快速看懂蠻有幫助的，放置圖片也讓了解內文變得更容易。[name=呂英弘]

> [name=助教姓名] 車體ok 電源ok 杜邦線還沒 蔡昀哲
> [name=宋馨慈] 2021/03/24 21:29 全部完成

* 教授批閱欄
  * 評分等第 A-
  * 教授回饋
    * 完整詳實，解決組裝問題能力明顯成長。
    * 若能有心得分享或課程建議則更加。

> [name=張時中]

## 第六週紀錄 - 循跡

* 課堂應完成事項(**下課前必須找助教檢查**)
  * 可不輔助、不出軌，連續繞行橢圓狀地圖2圈

> 給助教檢查
    >
    > * 成功使用p control順利完成圓形跑道及進階跑道
> [name=蔡昀哲]

### 3/31 課堂

* **實際達成事項 (必填)**
  * 三位組員皆**提早到班**
  * 紅外線感測器**靈敏度調校**完成
  * 直線行走**馬達出力校正**完成
  * 完成橢圓形跑道測試
  * 完成C型軌道測試(有時會出現bug)
* **組內討論事項 (必填，如問題、構想、分工合作、時間安排...等等)**  
  ***在以下的討論提及紅外線感測器，一慮用 0,1,2,3,4 號分別代表由右至左的五個感測器***
  1. **檢查紅外線感測器**  
  
     為了確認感測器能準確分辨白色區域與黑色區域，一開始將一整排紅外線感測器對準軌道的U型部分，當車體由U型下側往上移動時，**中間**的感測器應最先發生變化，在來是**中間的兩側**，最後則是**最外兩側**的感測器發生亮暗變化。  

     若是由上而下經過U型部分軌道則是從最兩側的感測器先發生變化，最後是中間的。  

     為了確保萬無一失，我們也**將整排紅外線感測器側向通過直線軌道**，發生亮暗變化應為:  (4)(4,3)(3)(3,2)(2)(2,1)(1)(1,0)(0)  

     {%youtube Jmx4PnwKz5k %}

  2. **校正馬達輸出**  
  
     因電池以及其他模組**擺放位置與重量不對稱**，因此當左右輪馬達電壓值調為相同時，實際上左輪會因為負重較大而導致轉速較慢。  

     因此在不斷的修正參數後發現當左輪馬達的電壓值為右輪馬達的約1.25倍時能夠在地面直行前進(偏移極少)  

     另外，馬達輸出**電壓值過小時無法帶動車子**行走，而且可能燒壞馬達，因此我們定義```vL```和```vR```為**校正過後可以驅動車子的最小輸出**。所以在```ControlMotor```中使用不為0的數字可以確保馬達的功率可以使車子移動，而當使用0的數字時則**直接停止馬達的運作**(```analogWrite(ENLeft, 0)```、```analogWrite(ENRight, 0)```)，以避免發生馬達空轉的情況。  

     綜合以上兩點，完成控制馬達轉速的函數:

     ```cpp
     const int vL = 100;
     const int vR = 80;
     void ControlMotor(double _rL, double _rR)
     {
       if(_rL >= 0)
       {
         digitalWrite(L1, HIGH);digitalWrite(L2, LOW);
       }
       else
       {
         digitalWrite(L1, LOW);digitalWrite(L2, HIGH);
         _rL *= -1;
       }
       if(_rL == 0)
         analogWrite(ENLeft, 0);
       else 
         analogWrite(ENLeft, vL + _rL*(255-vL));
     
       if(_rR>=0)
       {
         digitalWrite(R1, HIGH);digitalWrite(R2, LOW);
       }
       else
       {
         digitalWrite(R1, LOW);digitalWrite(R2, HIGH);
         _rR*=-1;
       }
       if(_rR == 0)
         analogWrite(ENRight, 0);
       else 
         analogWrite(ENRight, vR + _rR*(204-vR));
     }
     ```

  3. **討論循跡方法**  
  
     如果是**左側感受到黑線**，那表示**車身偏右**，必須將**右側的速度加快**；如果是右側感受到黑線，那表示車身偏左，必須將左側的速度加快。  
  
     依據**感測程度的不同**可以**調整不同的馬達轉速**。如:感測到(1)時的變化應該比感測到(1,2)劇烈。  

     若使用**窮舉法**，不僅程式**執行時間會加長**導致無法即時判定前進方向；另外之後的測試一定會有許多更為複雜的結構，若用窮舉法則可能**無法把所有情況都完整列入**。  

     因此我們從**一開始即構想出**利用**加權參數**來改變馬達電壓大小，利用調整權重的參數來使得車車能夠順利沿著橢圓軌跡行走。

     * **第一次嘗試**  
       僅使用P control:

       ```cpp
       void TracePath(int _IN0, int _IN1, int _IN2, int _IN3, int _IN4) //from right to left
       {
         double para = 0.4/2.0 * (_IN0*2 + _IN1*1 + _IN2*0 + _IN3*-1 + _IN4*-2) / double(_IN0+_IN1+_IN2+_IN3+_IN4);
         ControlMotor(0.4+para, 0.4-para);
       }
       ```

       如此一來，九種情況所對應的```para```如下。
       | (0) | (0,1) | (1) | (1,2) | (2) | (2,3) | (3)  | (3,4) | (4) |
       |:---:|:-----:|:---:|:-----:|:---:|:-----:|:----:|:-----:|:---:|
       |  1  | 0.75  | 0.5 | 0.25  |  0  | -0.25 | -0.5 | -0.75 | -1  |

       {%youtube hpEp0z5mAGg %}

       在**教授講解至此之前即在第一次測試成功**將基礎跑道跑完，但在進階跑道上彎度過大之處會卡住。遇到的**問題**包括:

       1. **轉彎衝出跑道**  
          {%youtube 30oTTxcdT6s %}
          * 一開始的設定會使得感測到0,1,2或2,3,4號感測器時轉彎的幅度小於0,1或3,4，因為我們會**除以感應到的感測器數量**，導致轉彎幅度除以3，反而比除以二更小，但實際上若發生此種情形時應為接近直角的轉彎，因此會衝出跑道。  
          * 另外的可能性是**權重比例錯誤**，外側的感測器所占比例不夠大，導致程式即使判斷正確也來不及轉回軌道上的狀況。
       2. **馬達空轉**
          * 由於車身**重量不足**且輪胎及地面**材質較硬**，導致輪胎**抓地力不足**，有時會出現明顯**打滑**現象，甚至一側輪胎完全空轉。

     * **第二次嘗試**  

       但我們認為在後面要補上轉彎時額外的參數(在```ControlMotor```中，```para```前面額外補上的比例係數1.1)，而導致車身**搖擺程度增加(很像酒駕)**，容易掃描並且**調大轉彎的幅度**比重至3，使得感應的轉動幅度比較大。  

       {%youtube UCrG26k7OVo %}  

       此外，我們的判別也加上了直線的情況```(para==0)```，可以使整體的運作情況更為順暢。

       ```cpp
       void TracePath(int _IN0, int _IN1, int _IN2, int _IN3, int _IN4) //from right to left
       {
         double para = 0.7/3.0 * (_IN0*3 + _IN1*1 + _IN2*0 + _IN3*-1 + _IN4*-3) / min(2, _IN0+_IN1+_IN2+_IN3+_IN4);
         if(para == 0)
           ControlMotor(0.1, 0.1);
         else if(para > 0)
           ControlMotor(0.1+1*para, 0.1-1.1*para);
         else
           ControlMotor(0.1+1.1*para, 0.1-1*para);
       }
       ```

* **組員分工 (必填)**
  * 一開始我們一位組員先調整紅外線感測器，同時另外兩位組員思考循跡演算法，在差不多調整好感測器時，我們即測試**加權方式**的演算法，雖然第一次就成功，但發現在順時針方向有時候會跑出軌道，原因是最右側的紅外線**感應器過於靈敏**，將其再次微調後即可成功。
  * 到了測試C型軌道時，三位組員分頭想有沒有哪些參數需要被考慮進去，在進行腦力激盪後，不斷修正出最適當的程式碼，雖然可以成功運行，但在穩定度以及其軌跡上仍有部分需要微調之處。
* **遇到問題之處理狀況、解決方式 (必填)**
  * 轉彎衝出跑道
    1. 因為轉彎過程中速度越快則需要越強的轉向力，且**馬達輸出的回應不夠即時**，可能因此衝出跑道，因此我們**調低基本車速**。
    2. 轉彎幅度較大時，左右輪速差需要更高**甚至內側輪反轉**，因此**調高0,4號感測器權重**。
  * 馬達空轉  
    我們嘗試在車身後方**添加重物**(如:手機、充電器等方便取得的物品)**提升抓地能力**。日後加裝更多功能後，車體重量應該也會上升，就不須另外放置重物。
* **課程建議 (選填)**  
  * 希望軌道圖紙能夠再大張一點點，讓紙張邊緣距離軌道至少三分之二個車身距離，不然有時候在實測車子時會因其中一輪跑出紙張到教室地面而打滑。
  * 在控制循跡的函數中，應**對感測到的紅外線模組數目**進行平均，以獲得更加精確的轉彎程度  
    課堂上的範例是:  

    ```cpp
        double error = 0.7/3.0 * (_IN0*3 + _IN1*1 + _IN2*0 + _IN3*-1 + _IN4*-3)
    ```

    而我們認為可以改良成:  

    ```cpp
        double error = 0.7/3.0 * (_IN0*3 + _IN1*1 + _IN2*0 + _IN3*-1 + _IN4*-3) / min(2, _IN0+_IN1+_IN2+_IN3+_IN4);
    ```  
  
    因為只有1號感測器感應到軌道與1,2號同時感測到所應轉彎的幅度不應一樣，但是因為2號感測器的權重為0，導致程式會判定這兩種狀況為一樣的，所以加上**除以感測到軌道的感測器數目**即可解決此問題。
  * 建議直接將窮舉法自課程中移除，因為窮舉法會使得定義各個定義的參數的方式沒有規律。移除窮舉法的時間可以拿來講PID control。此外，希望能夠不要太常打斷學生實際操作的時間，可能可以合併講的，就一次講，這樣小組也比較有充分的時間可以進行討論與實際的操作。  
* **想說的話 (選填)**
  * 張哲銘:  
    這次上課讓我們學習自己用已知的工具來完成特定的功能，雖然說原理是簡單的，但是要產生令人滿意的結果卻是困難的。希望接下來要處理各種車子的功能時也能夠自行推敲出原理，並慢慢的藉由調整好對的參數來使其更加完美。
  * 徐以帆:  
    本週課程內容有別於前幾次需按照標準流程完成要求，而是多了許多讓各組發揮創意的空間，雖然基本的作法相似，但是各參數的調整方式及考量是否周全都需要各組自行努力，不難想像期末時各組的成果會有巨大差異，令人期待。
  * 楊珩:  
    本次課程能夠讓各組自行討論演算法，進行腦力激盪，是相當不錯的體驗，然而知道演算法卻不知道參數為何是非常苦惱的事，太大或太小都會讓車子的轉彎幅度或行走軌跡出錯。因此止能夠不斷測試不斷微調。希望在之後的幾週都能夠順順利利的進行、開開心心的寫程式。

### 3/31 open lab

* **實際達成事項 (必填)**
  * 完成遇到**全黑判斷停止**(node預備)
    * **問題** : 車子停止位置並不是紅外線全數感測到黑線的位置(車子在煞車過程仍會滑行)
  * 完成**斷軌循跡**(自行用絕緣膠帶貼出軌道)  
    {%youtube XAqddBM4XDc %}
  * 完成**垂直軌道循跡**
  * 整合**RFID感測**(將學生證放在軌道正下方，車子經過時能夠讀取卡片)  
    {%youtube awoKmcKPc7M %}  

  ```cpp
  int TracePath(int _IN0, int _IN1, int _IN2, int _IN3, int _IN4) //from right to left
  {
    static double error = 0.0;
    if(_IN0&&_IN1&&_IN2&&_IN3&&_IN4)
    {
      error = 0;
      ControlMotor(0.05, 0.05);
      delay(100);
      ControlMotor(0, 0);
      return 0;
    }
    else if(_IN0||_IN1||_IN2||_IN3||_IN4)
      error = 0.7/2.5 * (_IN0*2.5 + _IN1*1 + _IN2*0 + _IN3*-1 + _IN4*-2.5) / min(2, _IN0+_IN1+_IN2+_IN3+_IN4);
    
    if(error == 0)
      ControlMotor(0.3, 0.3);
    else if(error > 0)
      ControlMotor(0.3+1*error, 0.3-1*error);
    else
      ControlMotor(0.3+1*error, 0.3-1*error);
  
    return 1;
  }
  
  void loop()
  {
  /*... do something ...*/
  //L298N-Motor
    if(moving)
      moving = TracePath(digitalRead(IR0), digitalRead(IR1), digitalRead(IR2), digitalRead(IR3), digitalRead(IR4));
  }
  
  ```

* **遇到問題之處理狀況、解決方式 (必填)**
  * 轉彎衝出跑道(con't)

    3. 當感測至全白時，將馬達的輸出調整成負向，這樣車子便會在感應不到任何黑線時倒退，回到軌道時再次進行循跡。雖然非常的有效，但考量到此為作弊行為，因此最後將此方案否決。除此之外，後來我們發現這樣子車子**移動的效率會很低**，因為只要出錯，車子便需要在原地不斷進行修正後才能夠前進。
    4. 因此，我們改**以```static```變數的方式儲存```error```**，若當下未感測到黑線位置，則沿用上一次判斷結果，因此**短時間沒有感測到黑線仍能正常行走**，且移動的方式更為順暢，不會卡死在原地。
  * 遇到全黑格子時的停車位置並不是感測器全暗的位置  
    * 在之後的地圖中，不論是岔路或是死路均是一大格黑色正方形，因此煞車時只要能停在格子正上方就可以，再以一輪為轉軸轉彎即可。
    * 我們不斷**改變煞車時的馬達電壓**，使車子在感應到要停車至完全停止的這段時間能夠**滑行至正確位置**。

### 4/7 open lab

* **實際達成事項 (必填)**
  * 完成PD control 改良車子，使其維持能穩定在軌道上行走的同時，加大車子的基礎速度

    ```cpp
    int TracePath(int _IN0, int _IN1, int _IN2, int _IN3, int _IN4) //from right to left
    {
      static double curError = 0.0, preError = 0.0;
      preError = curError;
      if(_IN0&&_IN1&&_IN2&&_IN3&&_IN4)
      {
        curError = 0;
        ControlMotor(0.05, 0.05);
        delay(100);
        ControlMotor(0, 0);
        return 0;
      }
      else if(_IN0||_IN1||_IN2||_IN3||_IN4)
      {
        curError = 0.6/2.5 * (_IN0*2.5 + _IN1*1 + _IN2*0 + _IN3*-1 + _IN4*-2.5) / min(2, _IN0+_IN1+_IN2+_IN3+_IN4);
        if(curError - preError > 0)
         curError += min(0.1, 0.5 * (curError - preError));
        else  if(curError - preError < 0)
         curError -= min(0.1, 0.5 * abs(curError - preError));
      }
    
      if(abs(curError) <= 0.2)
        ControlMotor(0.7+curError, 0.7-curError);
      else if(abs(curError) <= 0.4)
        ControlMotor(0.5+curError, 0.5-curError);
      else
        ControlMotor(0.3+curError, 0.3-curError);
    
      return 1;
    }
    ```

## 第六週批閱區 - 循跡

* 助教批閱欄
  * 內容詳細，使用很多影片跟程式碼來解釋當天完成的進度，也有把更改的地方還有參數留下來，對未來使用或修該應該蠻有幫助的。很棒，繼續維持~ [name=呂英弘]

>一開始就有實做出P Control而且還蠻穩定的，很棒
> [name=蔡昀哲]

* 教授批閱欄
  * 評分等第
    * A+
  * 教授回饋
    * 工作紀錄具體完整，用心克服問題，不少部分提供計量描述，如同助教指出，有助於系統性累積經驗供課程後續有效運用。心得與建議分享豐富，讚!
    * 建立控制馬達轉速函數的過程有創意。
    * 廣度上，自主嘗試斷軌循跡，並超前部署進行垂直軌道循跡及RFID感測。
    * 深度上，若能比較P和PD controllers對循跡效能的影響則更佳。
    * 除紅外線感測、馬達及控制部分外，車輪、車體結構有無調整之處來達到穩定有效循跡?

> [name=張時中]

## 第八週紀錄 - 指定題介紹

* 課堂應完成事項(**下課前必須找助教檢查**)
  * **問題0**回答、答案訂正  
    $$P=IV=180(mA) \times 6(V)=1.08(W)$$
  * **問題1**回答、答案訂正
    * 1-1  
      電池需要供應的最大功率等於各元件消耗功率的總和，即
        $$P_{tot} =\sum_{i=0}^N P_i = 200 + 33 + 75 \times 5 + 86 + 1080 \times 2 = 2854\: (mW)$$
    * 1-2  
      此時的輸出電流為
        $$I_{out} = \dfrac{2.854\: (W)}{11.1\: (V)} = 0.25712\: (A)$$
    * 1-3  
      由規格可知，使用時長為
        $$T = \dfrac{2250\: (mAh)}{257.12\: (mA)} = 8.75\: (hr)$$
  * **問題2**回答、答案訂正
    * 2-1  
        在Arduino(類似C++)的資料結構中，最多需紀錄每個node四個方向是否有node以及距離兩筆資料，因此
        $$S_{map} = \big[(150 \times 4) \times 2 \big] \times 2 = 2400\: (Bytes)$$
        如果node的名稱(編號)不是連續的，則需要另外儲存node的名稱
        $$S_{node} = 150 \times 2 = 300\: (Bytes)$$

        :::info
        **討論 : python的list結構應該能夠減少使用空間**  
        考慮在python中一個node的adjacency list中的元素必須存取node間的距離、方向與連接的對象(3筆數值)。則
        $$S_{map} = \big[(E \times 2) \times 3 \big] \times 2 = 12E\: (Bytes)$$
        $E$為邊數，在有150個node的情形下$E$最多大約到$300$，而只要$E<200$，此方法的所需空間就較小。
        :::

    * 2-2  
        每個點只能和最多4個node相連，因此```queue```最大只需紀錄大約40個node。另外，還要紀錄每個node是否走訪過及各自的父點，因此
        $$S_{BFS} \approx \big[40 + (150 \times 2)\big] \times 2 = 680 \: (Bytes)$$
    * 2-3  
        Arduino的記憶體存不下
  * **問題3**回答、答案訂正
    * 3-1  
        $$S_{Data} = 1 + 4 + 1 = 6\: (Bytes)$$
        $$Rate = \dfrac{6 \times 8}{0.1} = 480\: (bits/sec)$$
    * 3-2  
        此通訊速度可以支援所需要求
  * 完成甘特圖  
    **(若長寬比顯示怪怪的，可在 <font color="#f00">閱覽模式下</font> 按 <font color="#f00">F5鍵</font> 重整出較好看的甘特圖)**

    ```mermaid
    gantt
        dateFormat  MM-DD
        axisFormat  %b-%d
        title       車車課的歷史演變
        excludes    weekends
    
        section 軟體
        馬達控制程式    :done, 03-31,04-01
        循跡(P,PD)    :done, 03-31,04-08
        藍芽連線       :crit, active, 04-09,04-21
        讀懂sample code    :active, 04-20,04-28
        地圖尋路分析    :crit, future, 04-28,05-07
        自選題控制程式    :future, 05-12,05-26
        控制優化    :future, 06-01,06-20
    
        section 硬體
        基礎車體組裝    :done, 03-22,03-31
        車體改良    :crit, future, 04-28,05-04
        自選題車體改良    :future, 05-12,05-26
        車體優化    :future, 06-01,06-20
        
        section 討論
        CHECKPOINT!    :future,  05-03,05-05
        指定題比賽    :crit, future, 05-10,05-12
        自選題發想    :future, 05-01, 05-15
        自選題proposal    :crit, future, 05-24,05-26
        自選題demo    :crit, future, 06-29,07-01
    ```

  * 完成系統架構圖
    * 關係簡圖(實線為實體接線，需線為藍芽通訊)

      ```mermaid
      graph TB
          A("Arduino")
          S("Sensor(Infrared, RFID)")
          C("Computer(BFS alg. using Python)")
          M("Motor(L298N)")
          
          S--road info. & RFID detail-->A
          A--speed-->M
          A-.node & stop & RFID detail.->C
          C-.direction.->A
      ```

    * 時序圖

      ```mermaid
      sequenceDiagram
          participant C as Computer
          participant A as Arduino
          participant S as Sensor(IR, RFID)
          participant M as Motor(L298N)
          Note over C,A: Communicate through Bluetooth
          
          A->A: Setup
          activate C
          C->C: Process map (read and search)
          deactivate C
          loop
            rect rgba(0, 255, 0, .2)
              Note right of C: Control path
              alt Trace path
                S->>A: (IR)road information
                activate A
                A->>M: speed control
                deactivate A
              else Search path(Node or Deadend)
                S->>A: (IR)road information
                activate A
                A->>C: arrival at the block
                deactivate A
                activate C
                C->>A: direction to go
                deactivate C
                activate A
                A->>M: turning control
                deactivate A
              else Stop
                S->>A: (IR)road info.
                activate A
                A->>M: speed = 0
                deactivate A
                Note right of A: Won't go through "Control path" anymore
              end
            end
            rect rgba(255, 0, 0, .2)
              Note right of C: Read RFID
              opt Card dectected
                S->>A: (RFID)RFID detail
                activate A
                A->>C: RFID detail
                deactivate A
                C->C: add points
              end
            end
          end
      ```

> 給助教檢查
> 有記錄上課問答
> [name=蔡昀哲]

* 實際達成事項 (必填)
  * 完成課堂問答
  * 完成甘特圖
  * 完成系統方塊圖
  * 完成進度報告ppt
* 組內討論事項 (必填，如問題、構想、分工合作、時間安排...等等)
  * 計算所需功率時，**是否需考慮非理想情況下的的功率消耗**(降壓模組、感測器模組等的內部消耗功率)
    * 因為是估計，故不方便精準計算這些參數，但建議可以在原本的估計完成後，**加入一個定值或乘上特定係數來表示**(ref. 安全係數)
  * 儲存地圖時若是**利用linked list可能較節省記憶體空間**
    * **有條件成立**(詳見問題2-1)
  * 甘特圖**時程規劃**
  * 甘特圖及系統方塊圖的**繪製方式**
    * 討論後決定利用HackMD內建的程式語言功能，**使用mermaid繪製**，並**學習相關語法**
* 組員分工 (必填)
  * 製作甘特圖時，一位組員構思想法該如何繪製，一位負責上mermaid官網查詢程式撰寫語法，另一位則負責實作出來。
* 遇到問題之處理狀況、解決方式 (必填)
  * 藍芽模組的通訊功能不完整(**無法自主傳輸訊號給電腦**)
    * 連結傳輸線，並將程式修改為從Serial接受字串再經由藍芽傳輸，則此後Arduino皆可自行主動傳輸藍芽訊號。
* 課程建議 (選填)
  * 目前認為這週的**實作性不高**，雖然說概念上這種設計系統的概念是必要的，但若接下來後面學年的車車課會繼續進化的話（例如：更複雜，更多功能，更多任務），這堂課的**內容可以濃縮一點**，並且將時間拿來**介紹更多種類的模組\其他概念**。
* 想說的話 (選填)
  * 張哲銘:  
    這周上的內容比較偏向是理論的部分。雖然實作的量比較少，但是確定好接下來要如何按部就班地完成任務也的確是非常重要的事情。除此之外，今天也了解到設計系統時電力效率所需要注意的種種事項，這讓我們在進到自選題後能夠更加謹慎的設計我們想加入的模組與功能。
  * 徐以帆:  
    甘特圖和系統架構圖的概念讓我們更加了解需要做甚麼、怎麼做，想必是自選專題順利執行的要件。
  * 楊珩:  
    製作甘特圖與系統方塊圖的同時可以學習不同的程式語法，做出漂亮完美的圖表也讓人看的賞心悅目。在之後自選題的時候也方便查閱進度與應做待做事項。

## 第八週批閱區 - 指定題介紹

* 助教批閱欄
  * 在製作筆記的時候有善用HackMD的功能，看起來蠻清楚地也保留了彈性。如果這兩周在指定專題的進度有前進，也可以補上來喔。[name=呂英弘]

> 系統架構圖跟時序圖做得還不錯
> [name=蔡昀哲]

* 教授批閱欄
  * 評分等第 A
  * 教授回饋 建議把Start/End也加入時序圖。

> [name=盧奕璋]

## 第十週紀錄 - 指定題進度報告

* 預計完成事項 (必填)
  * 成功跑完E字型地圖(全自動，程式寫死)
  * 完成場內考地圖(利用藍芽操控與全自動)
    * 遇到node與dead end時停止並進行判斷
    * 直行前進    GoStraight
    * 左轉彎    Lturn
    * 右轉彎    Rturn
    * 180度迴轉    Uturn
    * 倒車入庫(先左轉再後退)    Bturn
* 實際達成事項 (必填)
  * 4/29課堂上
    * 完成**藍芽通訊**
    * 車車能**以遙控方式跑完地圖**，但有時會脫軌(原因後述)
  * 4/29下午
    * **增加**直行、左右轉彎、迴轉彎的**穩定性**
  * 5/1 open lab
    * 將主程式**切割為模組**
    * **增加**直行、左右轉彎、迴轉彎的**穩定性**
    * 完成**倒車入庫**(有時仍會不穩定，但**原因全部來自車輪打滑**)
    * **優化U turn的執行步驟**，使其更為流暢
    * 完成**RFID感應及UID傳輸**
    * 此為較為完整的場內考試跑影片
      {%youtube S_wFSqPkIiw %}

* 組內討論事項 (必填，如問題、構想、分工合作、時間安排...等等)
  * 前幾週的**藍牙溝通問題**源於Python端接收要收到```\n```才會視為是完整的訊息。
  * 藍牙連線要**採用同步**(block直到訊息完整)**還是異步**(有多少拿多少，後續再想辦法組合)。
    * 預計採用同步，但有時會出現訊息不完整導致Arduino卡死的問題，**考慮加入```timeout```**。
  * 在Arduino的部分，我們一開始先嘗試做「**電腦傳輸指令，車子回應指令**」。在這個階段，我們使用簡單的```GetMessage()```來執行我們的測試，並用傳輸```"arrived;"```來確認有確實抵達node。

    ```cpp
    void GetMessage()
    {
       strcpy(buf, "arrived;");
       if(BTWrite(buf))
       { Serial.println(F("**BT Sent**")); }
 
       while(!BTRead(buf)) {}
 
       if(buf[0] == 'S')      //straight
       {
           ControlMotor(0.7, 0.7);
           delay(300);
           moving = 1;
           return;
       }
       if(buf[0] == 'R')      // right
       {  ...  }
       else if(buf[0] == 'L') // left
       {  ...  }
       else if(buf[0] == 'U') // U turn
       {  ...  }
       else if(buf[0] == 'B') // backward parking
       {  ...  }  
    ```

    在感測到node時，```TracePath()```會將moving設定成0，而使在主程式內的迴圈轉成必須接受電腦給予的指令來進行移動。在進行完指定的移動後，才恢復成循跡模式繼續前進。

    ```cpp
    int TracePath(int _IN0, ..., int _IN4)
    {
        ...
        if(_IN0&&_IN1&&_IN2&&_IN3&&_IN4)
        {
            curError = 0;
            ControlMotor(0.05, 0.05);
            delay(100);
            ControlMotor(0, 0); 
            return 0; //switch to waiting mode
        }
        ...
    }
 
    void loop()
    {
        ...
        if(moving)
            moving = TracePath(digitalRead(IR0), ..., digitalRead(IR4));
        else
            GetMessage();    
    }
    ```

  * 無法得知車車實際轉彎的角度：
    * 在直行時，若在進入node時車體發生歪斜，則在離開node時，因為需要先進行一段沒有循跡的前進才能夠離開node，讓感應器能夠不全為```1```，即有可能在這段時間內，因前進的方向不穩而導致無法循跡。產生的結果包括:

      1. 出黑色方塊時感應不到接續的黑線。
      2. 若時間太短，可能在**還沒出黑色方塊就開始循跡**了，即會在同一個node停兩次
      3. 若時間太長，只要車體稍有歪斜，即可能在**還沒開始循跡前就偏離接續的軌道**了。
      4. 出黑色方塊時進行轉彎。然而因**感測不到**左轉方向的路，因此持續轉彎而沿著反方向回去。
      5. 出黑色方塊時進行轉彎。然而因**太早感測到**左轉方向的路(應該是因為煞車太早，導致擺頭時掃在node內的黑色而進行循跡)，因此提早結束轉彎而沿著錯誤的方向前進接到別的路上。
      6. 在進行B turn時，若無法確定左轉彎為**90±10度**，則在倒車時會發生**斜的入庫的情形**，以至於讀不到端點的RFID。

    * 由於車車**只能感應地面的標線**，而當車車位於node上時感應器讀值全為```1```，因此**難以利用閉迴路控制的方式得知車車旋轉角度**，估計只能經由**調整參數**，或是故意讓車車在剛開node時**利用較大幅度的擺動**以確保能正確找到標線。

    :::info
    **討論：為什麼不在倒退過程中加入循跡?**  

    一開始我們認為只要將馬達供電的正負號改變即可達到一樣的循跡方式。但是後來發現並非如此，而原因就是與**車體本身的結構**有關，因為紅外線感測器的位置在車輪的前方，所以當車子向前進行時，紅外線感測器是在車子的前方，都是先由紅外線判讀完後輪子才經過；但若是**倒退**的話，**紅外線感測器會在車輪的後方，也就是車輪要先經過後紅外線才會感測到**，這樣根本就不是循跡了。
    :::

  * 改變程式寫死方法:  
    原本打算在Arduino中利用已經完成的馬達操控函式將每個步驟一一寫死。

    ```cpp
    if(moving)
        moving = TracePath(digitalRead(IR0), digitalRead(IR1), digitalRead(IR2), digitalRead(IR3), digitalRead(IR4));
    else
        controlpara+=1;//not tracing
        if(moving==0)
        {
             if(controlpara==1)
             {
                GoStraight();
             }
             else if(controlpara==2)
             {
                GoStraight();
             }
             else if(controlpara==3)
             {...}
             ...
         }
    ```

    但後來與組員討論後考慮到再下一週即要進行BFS循跡，若現在用Arduino寫死的話到時候又要重新全部重寫，因此我們改進為**只用Arduino寫好各種控制函式**(直行、左右轉、迴轉、倒車入庫等)，至於**每一個步驟的順序則是寫在python中**，並**利用藍芽傳輸**，讓車子經過每一個節點或死巷時，**Arduino能夠即時向python取得下一步的指令以進行接續動作**，這樣若要改成BFS時就只需要更動python，Arduino一樣只需向python取得下一步指令即可。

    ```python
        msgRead = ""
        msgWrite = ""
        instructions = ["S;", "S;", "S;", "S;", "B;", "S;", "R;", "L;", "R;", "U;", "S;"]
        k = 0

        msgWrite = instructions[k]
        bt.write(msgWrite)
        print(msgWrite)
        k += 1
        while True:
            msgRead = bt.readString()
            if msgRead == "Arrived":
                print(msgRead)
                if k < len(instructions):
                    msgWrite = instructions[k]
                    k += 1
                else:
                    msgWrite = "p;"
                bt.write(msgWrite)
                print(msgWrite)
            elif msgRead == "Card":
                print(msgRead)
            else:
                print(msgRead)
    ```

  * 原先的寫法**迴轉有時不穩定**，因為包含向前微微左轉加上大幅度的右轉。若是**輪子稍微打滑，迴轉半徑會增大**，加上**需要迴轉的區域都很接近紙張邊緣**，很容易跑出紙面(即失敗)，需要構思一個能夠最節省空間且速度也快的迴轉方式。

    ```cpp
    void UTurn(){
      ControlMotor(-0.2, 0.5);  //left
      delay(300);
      ControlMotor(0.7, -0.9);  //right
      delay(1300);
      while(!digitalRead(IR0) && !digitalRead(IR1) && !digitalRead(IR2) && !digitalRead(IR3) && !digitalRead(IR4))
        ControlMotor(0.9, -0.7);
      ControlMotor(0, 0);
      return;
    }
    ```

    此方法是先固定左輪讓**車體向左稍微轉彎**，再固定右輪旋轉回軌道。但若是沒有在車體上壓重物則有一定機率會打滑。
    {%youtube A4qWmhMYu7o %}

    :::info
    **討論 : U turn 為何不定軸旋轉**  
    起初我們認為定軸旋轉式最理想的旋轉方式，**不須利用任何額外空間**，但事實上要使得兩個馬達以相同大小，不同方向同時旋轉，會產生**極大的阻力**，最後結果還是以支撐較重的左輪為軸旋轉。而且結果會變得更加不穩定。  
    :::
* 組員分工 (必填)
  * 一人負責處理藍牙相關問題，同時另外兩位組員討論控制方式並調整各項轉彎參數。
  * open lab無法到場的組員負責調整程式架構(切割為模組等)並優化藍牙傳輸方式。
  * 另兩位組員在open lab期間實際測試車車並調整參數。
* 遇到問題之處理狀況、解決方式 (必填)
  * 藍牙傳輸問題
    * 經討論後決議在Arduino端及Python端**皆以```;```作為訊息傳輸的中止符號**以避免傳輸資訊不完整。

      ```cpp
      // Arduino
      int BTRead(char *input, char seg = ';', int bufSize = BUFSIZE)
      {
        int i = 0;
        char c = '\0';

        if(BT.available())
        {
          while(i < bufSize-1)
          {
            do
            {
              c = BT.read();
            }while(c < 0);

            if(c != seg)
              input[i++] = c;
            else
              break;
          }
        }
        input[i] = '\0';
        return i;
      }
      ```

      ```python
      # python
      def readString(self) -> str:
          # Scan the input buffer until meet a ';'. return none if doesn't exist.
          receiveMsg = ""
          if self.waiting():
              c = self.ser.read().decode("utf-8")
              while c != ';':
                  receiveMsg += c
                  c = self.ser.read().decode("utf-8")
          return receiveMsg
      ```

    * 並在Arduino端及Python端**皆加入```timeout```的設置**以免程式被藍牙通訊卡死過久。

      ```cpp
      // Arduino
      int BTRead(...)
      {
        unsigned long lastTime = millis(), curTime = millis();
        ...
            do
            {
              c = BT.read();
              curTime = millis();
              if(curTime - lastTime > 50)
              {
                input[0] = '\0';
                return 0;
              }
            }while(c < 0);
            lastTime = curTime;
        ...
      }
      ```

      ```python
      # python
      def __init__(self, port: str, baudrate: int = 9600, timeout: float = 2):
          self.ser = serial.Serial(port, baudrate = baudrate, timeout = timeout)
      ```

  * 確保倒車入庫轉彎角度接近90度
    * 由於在倒退時無法進行循跡，必須在左轉時確定能夠轉到與倒車軌道平行。討論後決定在做轉彎結束後**先進行一小段循跡後再倒退**，這樣能夠減少倒車時偏離軌道的情形。
  * 拿捏遇到node時電腦自動判讀的時間
    * 在實際測試下，即便參數一模一樣，每次跑出來的結果幾乎沒有完全一樣的，也就代表調完一次時間參數極有可能在下一次發生錯誤。  

      經討論後決定讓電腦自行判定的時間訂為**300ms(最短不受控的時間)**，剩下的時間若還是在黑色方格上就繼續直行，直到五個紅外線感測器不是全為1後才開始循跡。

      ```cpp
      while(digitalRead(IR0) && ... && digitalRead(IR4))
        ControlMotor(0.7, 0.7);
      ```

  * 最後討論出目前最可行的旋轉方式，改為倒退進行。如下：

    ```cpp
    ControlMotor(0, -0.8);  //left
    delay(650);
    ControlMotor(0.7, 0);  //right
    delay(650);
    while(!digitalRead(IR2) && !digitalRead(IR3) && !digitalRead(IR4))
    {
      ControlMotor(0.7, 0);
    }
    ControlMotor(0, 0);
    ```

    {%youtube 41s5UuEO9cE %}

* 課程建議 (選填)
  * 這周作起來真的非常倉促，雖然說課程已經大部分以實作為主了，但是希望在時間安排上能夠讓自己處理自選題的這些時間能夠拉長，像是前面一些時間能夠更簡潔的在幾堂課內完成，在時間安排上可能會更好。  
* 想說的話 (選填)
  * 張哲銘：  
    雖然之前都是在寫硬體arduino的部分，但這周open lab從熟悉的arduino改成要在不熟悉的python內工作，雖然coding style跟python程式的寫法都還有改善的空間，但是嘗試處理自己比較不熟悉的部分，也算是另類的跨出舒適圈吧!讓自己更有能力去寫python的東西。我覺得現在最希望就是讓這台車子更穩定一點，現在跑出來的結果都沒有再現性 :cry: 希望接下來趕快讓他可以成功的機率從1/10升到1!  

  * 徐以帆：  
    這週由於open lab期間有事無法到場，硬體及參數相關的調整都是由另外兩位組員負責，我則盡量在軟體架構部分幫忙debug及修改，我們即便無法在同時同地一起工作，也能完成共同目標，相信之後的合作都能相當順利。

  * 楊珩：  
    這禮拜課堂上最累人的部分就是調參數，常常發生一開始行得通後來卻會偏離軌道的情形。而且測試的紙張不同，摩擦力也不同，轉彎的幅度與速度也會有些微的不同。從某種程度看來其實還滿靠運氣的，目前我們也不知道為什麼跑兩次一樣的軌道，一樣的程式碼，會有截然不同的結果。

## 第十週批閱區 - 指定題進度報告

* 助教批閱欄
  * 紀錄內容很詳細，把細節跟相關的改動都有完整寫下來，蠻容易可以follow你們的進度的。確實就像你們講的，轉換程式語言、調參數等等蠻不容易的，幾乎所有project都會有這樣的困難，不過你們看起來也在這幾周解決了不少問題了，繼續加油~~

> [name=呂英弘]

* 教授批閱欄
  * 評分等第 A+
  * 教授回饋 看來處理了不少問題，是很好的經驗。至於兩次為什麼會有不一樣的結果，有可能是起始條件不同(車的位置或萬向輪一開始的方向)，導致後續的資料時序不同。但從另一方面來說，可以想一下如何讓系統更穩定。

> [name=盧奕璋]

## 第十一週紀錄 - 指定題進度檢視

* CHECKPOINTS
  * 車車
    * [x] 循跡
    * [x] 可以偵測到 node（包含十字路口和死巷）
    * [x] 偵測到 node 之後，穩定直走、轉彎、迴轉（寫死指令）
    * [x] 可以接收來自電腦的藍芽指令

  * python
    * [x] 完成基本的 BFS
    * [x] 完成第一題的設計
    * [x] 可以透過藍芽傳輸指令
  
  * combined
    * [x] 可以讀取 RFID 的值
    * [x] 能走完 3 個點
    * [x] 可以不輔助情況下，完成小型 E 字地圖
    * [x] 可以不輔助的情況下，完成進階地圖
    * [x] 可以正確在死巷讀取 RFID
  
  * Checkpoint新版 (依實際通過狀況填寫)
    * [x] 關卡1：基本駕駛
    * [x] 關卡2：蛇行
    * [x] 關卡3：S型彎道
    * [x] 關卡4：迴轉區
    * [x] 關卡5：直行
    * [x] bonus：倒車入庫

> 給助教檢查[name=呂英弘]

### 5/3

* 組內討論事項 (必填，如問題、構想、分工合作、時間安排...等等)
  * 進化 U turn
    * 原本：**二段式轉彎**，雖然大致上能夠迴轉成功，但是遇到兩個node太靠近時，會發生還沒轉完彎就已經進入下一個node了(轉彎太佔空間了)，導致可能**發生少讀到一個node的情形**。
    * 進化後：**三段式迴轉**，先進行一小部分的右轉，車身大約轉至45度，再進行左轉倒退，最後再右轉前進完成迴轉，自從更改完此迴轉方式後，**除了因紙張車輪打滑外，成功率大於95%**。

  * 進化 B turn
    * 經過不斷的觀察後發現我們的車子在**向前轉彎打滑的機率遠大於倒車轉彎**，又因為倒車入庫最需要的就是轉彎的角度，因此最後更改為**先前進直行一小段距離，過了該node後再進行右轉倒車**，此成功率大約為八成，相較於原本的兩三成進步許多。

  * BFS完成E型地圖並能傳輸指令  
    我們將之前的學過的BFS改寫，多存取了各個Node之間的相對方向與距離。因為在主程式內不能告訴車子絕對的方向(北邊、南邊等)，只能告訴它相對要做的動作(左轉、右轉等)。

    ```python
    class Node:
    ...
    def setNeighbor(self, neighbor, direction, length = 1):
        self.Neighbors.append((neighbor, Direction(direction), int(length)))
        return

    def getDirection(self, nd):
        for neighbor in self.Neighbors:
            if neighbor[0] == nd:
                return Direction(neighbor[1])
        print("No such neighbor exists.")
        return 0
    ```

    而在迷宮內，利用絕對方向之間的關係，得出相對方向，建立一個矩陣以轉換成車子需要獲得的指令。  

    ```python
    class Action(IntEnum):
        GO_FORWARD = 1
        TURN_LEFT = 2
        TURN_RIGHT = 3
        GO_BACKWARD = 4
        U_TURN = 5
        HALT = 6

    #N => 1, S => 2, W => 3, E => 4
    actions =[[Action.GO_FORWARD,Action.U_TURN,Action.TURN_LEFT,Action.TURN_RIGHT],
              [Action.U_TURN,Action.GO_FORWARD,Action.TURN_RIGHT,Action.TURN_LEFT],
              [Action.TURN_RIGHT,Action.TURN_LEFT,Action.GO_FORWARD,Action.U_TURN],
              [Action.TURN_LEFT,Action.TURN_RIGHT,Action.U_TURN,Action.GO_FORWARD] ]
    ```

    接下來利用```getDirection()```將計算出的BFS改成Node之間的絕對方向，再利用```getAction()```改成車子需要判讀的相對方向。最後再將這個相對方向之間的序列改成車子能讀懂的指令```S```、```B```、```L```、```R```、```U```等。

    ```python
    def getDirection(self, nd_from, nd_to):
        direction = []
        path = self.BFS_2(nd_from, nd_to)
        for i in range(len(path)-1):
            direction.append(self.nd_dict[path[i]].getDirection(path[i+1]))
        return direction

    def getAction(self, car_dir, nd_from, nd_to):
        direction = self.getDirection(nd_from, nd_to)
        action = []
        cur_dir = car_dir
        for next_dir in direction:
            action.append(actions[int(cur_dir)-1][int(next_dir)-1])
            cur_dir = next_dir
        return action
    ```

    將上述的程式include到藍芽連接的程式後，藍芽能夠確實地計算出路徑後傳出指令給車子，完成E型地圖。但目前只能計算一段A至B的BFS，無法繼續接續。

### 5/5

* 組內討論事項 (必填，如問題、構想、分工合作、時間安排...等等)
  * algorithm  
    計算出每一種deadend之間的最短距離，並以此距離作為權重，重新產生一張只有deadend的**完全圖(complete graph)**。
    接下來，再計算自起點到各個deadend間的**曼哈頓距離(Manhattan distance)**，以作為分數的依據，將各邊再**除以其兩端deadend獲得的分數**，以使最後在搜尋經過的路徑時，會以此路徑為優先，獲取較多的分數。  
    我們首先使用Floyd-Warshall演算法找出任兩點之間的最短距離，再重新製作成一張新的complete graph。
* 組員分工 (必填)
  * 一人負責改良硬體及TrunLeft、TrunRight等馬達控制，加快車車的行走速度及流暢性。
  * 兩人負責查找適用的尋路演算法並實作。
* 遇到問題之處理狀況、解決方式 (必填)
  * 尋路演算法  
    在網路上進行大量搜尋之後選定利用Floyd-Warshall對地圖進行預處理，將原始地圖轉換為以deadend為點的complete graph，然後再利用旅行推銷員問題的想法找出可以走遍所有deadend的最短路徑。
* 課程建議 (選填)
  * 改良車體過程及轉彎方式的過程中發現，如果是利用馬達"拉"動車車而不是"推"動車車的話，運作較為順暢，建議可以將車車改為前輪驅動的形式。
* 想說的話 (選填)
  * 張哲銘：  
    這禮拜很順利的過了考前checkpoint!雖然說他的再現性還不到100%，但相較於之前已經非常穩定了。這週的演算法寫起來覺得比較困難，但也因此更加熟悉python的寫法。目前演算法跑起來會讓電腦風扇聲音很大，如何讓其更有效率便會是接下來我們需要思考的重點！
  * 徐以帆：  
    雖然說車體及基本的循跡控制早在幾週前就已經完成，但是在最後這一週為了改良車子性能以及提升穩定性仍花費不少時間，我們多約了不少時間才趕上進度，日後再規劃整合及優化的時間上還需要再估計得寬裕一些。
  * 楊珩：  
    雖然在checkpoint拿下了滿分，但是仍有需要加強的部分，像是速度問題，能夠在checkpoint穩穩地跑完，在指定題考試時絕對走不完，若要經過40多個node的話，平均兩個node只能走三秒，還包括左右轉以及迴轉的時間。這樣看來還必須要再調整一些參數來完成。

## 第十一週批閱區 - 指定題進度檢視

* 助教批閱欄
  * 從紀錄可以看到一些修改的內容、方法、結果，對於你們實際上在跑的時候進步的原因可以一目了然，蠻完整的。

> [name=呂英弘]

* 教授批閱欄
  * 評分等第 A+
  * 教授回饋 累積點點滴滴的創意，得到好的綜效。除了嘗試錯誤之外，貴組調整軟硬體的方法、心得是?

> [name=張時中]

## 第十二週紀錄 - 指定題競賽

* 預計完成事項 (必填)
  * 完成尋路演算法
  * 吃完所有分數點
  * 不須用手輔助
* 實際達成事項 (必填)
  * 吃完**所有分數**(共 +2140分)
  * 中間有兩次馬達卡死，需手動輔助
  * **提升轉彎效率**
    * 抵達Node時**不停車**，直接轉彎
    * 行走過程中就**先向python端取得下一步指令**，省去等待時間(正式競賽後完成)
  * 完成**最佳化尋路演算法**
* 組內討論事項 (必填，如問題、構想、分工合作、時間安排...等等)
  * 因為時間很趕(2 min.)，需要尋找**合適的演算法**
    * 任兩deadend間最短路徑
      * Dijstra、Floyd-Warshall等
    * 時限內拿到最多分數
      * TSP、Greedy
  * **加速車車**的動作(尋跡、左右轉、迴轉等)
    * 提升車速
    * 轉彎不停車
      * 可能因為藍牙延遲不一致而不穩定
  * **解決藍牙延遲**問題
    * 預先傳送指令給車車
* 組員分工 (必填)
  * 一人負責改善轉向性能(調整轉向參數)
  * 一人負責撰寫尋路演算法
  * 一人負責優化藍牙通訊
* 遇到問題之處理狀況、解決方式 (必填)
  * 利用[Dijkstra演算法](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm)分析各deadend間最短路徑

    ```python
    for deadend in self.deadends:
        for nd_to in self.nodes:
            self.distance[deadend][nd_to] = [10000, list()]
        self.distance[deadend][deadend][0] = 0
        pi_function = dict()
        pi_function[deadend] = None
        queue = [deadend]

        while len(queue):
            minDis = 1000
            cur_nd = None
            for nd in queue:
                if self.distance[deadend][nd][0] < minDis:
                    cur_nd = nd
                    minDis = self.distance[deadend][nd][0]
            queue.remove(cur_nd)

            for nd_data in self.nd_dict[cur_nd].getNeighbors():
                if minDis + nd_data[2] < self.distance[deadend][nd_data[0]][0]:
                    self.distance[deadend][nd_data[0]][0] = minDis + nd_data[2]
                    pi_function[nd_data[0]] = cur_nd
                    queue.append(nd_data[0])

        for nd_to in self.deadends:
            if nd_to in pi_function:
                nd = nd_to
                while nd:
                    self.distance[deadend][nd_to][1].append(nd)
                    nd = pi_function[nd]
                self.distance[deadend][nd_to][1].reverse()
    ```

  * 由於車車動作加速，預估可以完成遍歷，因此只需利用[Held–Karp演算法](https://en.wikipedia.org/wiki/Held%E2%80%93Karp_algorithm#Pseudocode[5])搜尋最佳遍歷路徑

    ```python
    S = self.deadends * 1
    length = len(S)
    S.remove(nd_from)
    Dis = dict()
    for nd in S:
        Dis[(tuple([nd]), nd)] = [self.distance[nd_from][nd][0], nd_from]

    for l in range(2, length):
        for s in itertools.combinations(S, l):
            s = list(s)
            for nd_to in s:
                ss = [i for i in s if i != nd_to]
                min_dis = 10000
                min_nd = None
                for nd in ss:
                    if Dis[(tuple(ss), nd)][0] + self.distance[nd][nd_to][0] < min_dis:
                        min_dis = Dis[(tuple(ss), nd)][0] + self.distance[nd][nd_to][0]
                        min_nd = nd
                Dis[(tuple(s), nd_to)] = [min_dis, min_nd]

    min_dis = 10000
    nd_to = None
    for nd in S:
        if Dis[(tuple(S), nd)][0] < min_dis:
            min_dis = Dis[(tuple(S), nd)][0]
            nd_to = nd
    if nd_to == None:
        return None

    # construct path with deadends
    dd_path = []
    cur_nd = nd_to
    while cur_nd != nd_from:
        dd_path.append(cur_nd)
        tmp = Dis[(tuple(S), cur_nd)][1]
        S.remove(cur_nd)
        cur_nd = tmp
    dd_path.append(nd_from)
    dd_path.reverse()

    # convert to path with nodes
    path = [nd_from]
    for i in range(len(dd_path)-1):
        path += self.distance[dd_path[i]][dd_path[i+1]][1][1:]
    print(path)
    return path
    ```

  * 在Arduino上暫存下一個指令，有關方向控制的流程圖如下:

    ```mermaid
    graph LR
        AT[[AskPython w/ timeout]]
        IF1{dirCMD is empty}
        IF2{arrive at node}
        IF3{arrive at last node}
        IF4{dirCMD is empty}
        TR[[PathControl]]
        T[[Turn]]
        subgraph "[Wait]"
        A[[AskPython w/o timeout]]
        end
        S((start))-->IF1
        IF1--Yes-->AT-->IF1
        IF1--No-->TR
        TR-->IF2
        IF2--Yes-->IF3
        IF2--No-->TR
        IF3--Yes-->E((end))
        IF3--No-->IF4
        IF4--Yes-->A--clear dirCMD-->T
        IF4--No-->T-->IF1
    ```

* 課程建議 (選填)
  * 待填
* 想說的話 (選填)
  * 待填

## 第十二週批閱區 - 指定題競賽

* 助教批閱欄
  * 你們比賽的結果真的是蠻順的。從你們過去還有這次紀錄的內容看來，有很仔細研究各個問題，可以說是你們的努力有兌現吧(雖然不一定每次都會這樣)。

> [name=呂英弘]

* 教授批閱欄
  * 評分等第 A
  * 教授回饋 恭喜達成驚艷等級的表現。
  * 馬達卡死的原因? 
  * 再提升穩定度的重點是?

> [name=張時中]

## 第十三週紀錄 - 自選題介紹

* 預計完成事項 (必填)
  * 確定自選題題目
  * 決定大致設計方向
* 實際達成事項 (必填)
  * 自選題題目:**自走載物平台**
    * **升降功能**
      * X型升降機構
      * 螺桿+步進馬達
    * **自動導航功能**
      * 基礎紅外線循跡
      * 利用影像(大範圍)或超音波感測器(近距離)避障
    * **身分識別功能**
      * 載物區上鎖
      * 升降高度記憶
    * **警示功能**
      * 在遭遇突發事件或完成指定任務時發出警示音(蜂鳴器)
* 組內討論事項 (必填，如問題、構想、分工合作、時間安排...等等)
  * 討論所需功能(brainstorm)
    * [x] 載物
    * [ ] 取、卸物
    * [x] 升降
    * [x] 自行移動(pi camera or 紅外線循跡)
    * [ ] 偵測高度(上升到桌面(某平台)高度，依據不同的桌面升到不同的高度)
    * [x] 設定目的地
      * 路面循跡
    * [x] 身份辨識
    * [x] 確認抵達目的地
    * [ ] 側邊支架
    * [x] 警示功能(聲音)
    * [x] LED指示狀態
    * [x] 自動避障
      * 用pi-camera辨識路徑上是否有**靠近中**的障礙物(人、動物)，若有的話則發出**警示音**
    * [x] 排除障礙物
      * 若是路徑上有**固定**的障礙物，則減速並用**機械手臂**將其移除。
      * 或者可以繞道(?
    * [x] 自動歸位
  * 討論可能的實作方式
    * 步進馬達
    * 支架  
      ![支架](https://i.imgur.com/pLODDMd.png)
  * 討論如何進行後續製作
* 組員分工 (必填)
  * 三人共同發想
  * 一人則製作簡報
* 遇到問題之處理狀況、解決方式 (必填)
  * 進行後續製作
    * 平時線上討論，完成圖面(機構部分)繪製及程式撰寫，並網購零件
    * 之後視疫情嚴重度找機會取回車車，輪流保管以進行組裝及測試
* 課程建議 (選填)
  * 待填
* 想說的話 (選填)
  * 徐以帆:  
    對於教授提問:**我們是否因為運氣好而成功?**  
    我認為**不是**，但**顧及同儕關係的和諧**不便當下提出。我認為我們的車車沒有大問題的原因包含:

    1. **正確且確實接線**  
       我們在[第五週](#第五週紀錄---組車)就有簡短提過要注意的面向。我們特別注意**將電線纏繞**並**鎖緊接口**以確保接線不要接觸不良，也在可能短路的地方**纏繞絕緣膠帶**，並且**使用完整排線**並**注意接線pin腳**以確保接線位置正確。(有幾組提到接線鬆脫、誤用Arduino預設腳位或短路燒壞等)
    2. **在安全範圍內操作**  
       我相信這應該是**很基本的概念，教授在課堂上也提過**，而且我們的軟體計算結果本來就不會算出需瞬間大幅轉換的情況(教授建議的寫法本身也不會)，因此原本沒有特別注意。(有組別提到馬達問題後來發現是源於頻繁要求馬達急速反轉)
    3. **自行改良sample code**  
       我們在[第十週](#第十週紀錄---指定題進度報告)也遇過藍牙通訊相關的困難(訊息無法傳送、不完整等)，我們選擇在**了解sample code後自行改寫程式**以符合我們的需求。然而有些組別或許組員對程式的熟悉度較低，因此沒有能力或是沒有想到自行修改程式。(有組別提到藍牙傳輸訊息不完整、有亂碼等)
    4. **討論出良好的方法**  
       我們這組組員組成得宜，在討論中能各自發揮所長，也能將各自**以往的經驗及能力用於解決當下的問題**，例如:楊珩提出接線需注意的事項、我在演算法的方向較有研究。而參數調整的方式就只能是試誤法，在**確保系統正常運作並了解各參數作用的情況下**，最終結果取決於**原本的預期(敢不敢想)以及持續調整的耐心**。

    誠如教授所言，**正確操作及養成優先測試的習慣**是日後身為電機畢業生所需具備的能力，努力**加強自身實力**也是學生的責任。然而，**身為同儕而非教師，並且我們競賽成績偏高**，我在當下無法迅速決定是否要公開點出以上其他組別可能的過失，**還請教授見諒**。
  * 張哲銘:  
    這禮拜線上的上課方式雖有許多不習慣，但在疫情的衝擊下也只能這樣上課。這次上課中被問到我們這次能夠成功是否是因為器材剛好選得比較好，這點我必須要否認。跟其他組一樣，我們也花了不少時間在處理這台車子上面，而且我們也一樣有遇到不少問題，但我們有努力去克服並找到問題點而加以改進。
  * 楊珩:  
    :beginner:首先要說的是，線上的教學方式雖然挺不習慣的，尤其對於這門需要實做的課程，不過這種方式確實令人感到新奇。這週應該是因為還不太熟悉流程所以導致時間有點拖延到:arrow_backward:，希望之後流程能夠更加順暢!

## 第十三週批閱區 - 自選題介紹

* 助教批閱欄
  * 提出的idea蠻好的，感覺是在原本的基礎上去增加功能，蠻多部件應該可以用跟之前一樣的材料。結構設計上，不確定各位是否有經驗，但是期待你們的作品！
  * 我覺得可以仔細說明做得好的原因蠻好的，有這些分析才能夠做為大家互相提升能力的材料。

> [name=呂英弘]

* 教授批閱欄
  * 評分等第 A
  * 教授回饋 可以客觀總結成功的原因非常好。我可以理解當時的考量，不過將來你們要是有機會跟不同文化背景的人共事(例如有機會到美國求學/工作的時候)，可以當場說出來的話應該會更好。作為一個小的練習，三位要不要自己試著把成功的原因用英文講一次呢。

> [name=盧奕璋]

## 第十四週紀錄 - 自選題proposal報告

* 預計完成事項 (必填)
  * 確定功能設計
  * 查找合適零件
  * 完成設計草圖
* 實際達成事項 (必填)
  * 確定所需功能
    * 載物
    * 自行移動
    * 升降
    * 設定目的地
    * 確認抵達目的地
    * LCD指示狀態
    * 自動歸位
    * 身份辨識
    * 警示功能(聲音)
    * 自動避障(長、短距離)
    * 排除障礙物
  * 找齊所需零件  
    | 品項  | 單價 | 數量 | 小計 | 連結 | 備註 |
    | ---- | ---- | ---- | ---- | ---- | ---- |
    | *自行訂購* |  |  |  |  |
    | SG90-360 | 55 | 2 | 110 | [link](https://shopee.tw/%E3%80%90UCI%E9%9B%BB%E5%AD%90%E3%80%91-(16-3)-SG90-%E8%88%B5%E6%A9%9F-9%E5%85%8B-360%E5%BA%A6-%E5%9B%BA%E5%AE%9A%E7%BF%BC-%E7%9B%B4%E5%8D%87%E6%A9%9F-i.2305548.2022158637) | |
    | 螺桿(M5\*100 mm) | 20 | 2 | 40 | [link](https://shopee.tw/m3-4-5-6*55~100mm%E5%8A%A0%E9%95%B7-%E7%99%BD%E9%90%B5%E4%B8%8D%E9%8F%BD%E9%8B%BC%E8%9E%BA%E7%B5%B2%E4%B8%B8%E9%A0%AD-%E5%8D%81%E5%AD%97-%E6%A9%9F%E6%A2%B0%E7%89%99%E8%9E%BA%E7%B5%B2-i.752514.48884333) | 6/3已到貨(Y) |
    | M5螺帽 | 10 per 10 | 2 | 10 | [link](https://shopee.tw/m2m2.-5-m2.6-m3-m3.5-m4-m5-m6-m8m10-m12%E4%B8%8D%E9%8F%BD%E9%8B%BC%E8%9E%BA%E5%B8%BD-%E7%99%BD%E9%90%B5%E5%85%AD%E8%A7%92%E8%9E%BA%E5%B8%BD-%E5%A4%96%E5%85%AD%E8%A7%92%E8%9E%BA%E5%B8%BD-%E8%9E%BA%E6%AF%8D-i.752514.60073764) | 6/3已到貨(Y) |
    | 鐵軸(3\*130 mm)(無發票) | 50 per 7 | 12 | 100 | [link](https://shopee.tw/%E2%80%BB%E9%87%91%E8%AA%A0%E4%BA%94%E2%80%BB%E7%9B%B4%E5%BE%913mm%E5%AF%A6%E5%BF%83%E4%B8%8D%E9%8A%B9%E9%8B%BC%E6%A3%92-%E7%99%BD%E9%90%B5%E6%A3%92%EF%BC%88303%E6%9D%90%E8%B3%AA%EF%BC%89-%E6%A8%A1%E5%9E%8B-%E6%94%B9%E9%80%A0-%E6%A4%8D%E6%A8%81-%E8%BB%8A%E8%BB%B8-%E8%BB%B8%E5%BF%83-(%E6%AF%8F%E5%8C%857%E5%85%A5)-i.29107234.6138875043) | 6/1已到貨(Y) |
    | 1602LCD | 65 | 1 | 65 | [link](https://shopee.tw/%E3%80%90%E7%A5%A5%E6%98%8C%E9%9B%BB%E5%AD%90%E3%80%91Arduino%E7%B3%BB%E5%88%97%E5%A5%97%E4%BB%B6-1602-LCD%E6%B6%B2%E6%99%B6%E8%9E%A2%E5%B9%95-M036-IIC-I2C-%E8%BD%89%E6%8E%A5%E6%9D%BF-%E6%A8%A1%E7%B5%84-%E7%B5%84%E5%90%88-%E6%A8%A1%E5%A1%8A-i.27742636.4148112403) | |
    | 5向搖桿 | 25 | 1 | 25 | [link](https://shopee.tw/%E3%80%90%E7%92%B0%E5%B3%B6%E7%A7%91%E6%8A%80%E3%80%91(b2-12)%E4%BA%94%E5%90%91%E5%B0%8E%E8%88%AA%E6%90%96%E6%A1%BF%E6%A8%A1%E7%B5%84-%E4%BA%94%E5%90%91%E5%B0%8E%E8%88%AA%E6%8C%89%E9%8D%B5%E6%A8%A1%E5%A1%8A-5D%E6%90%96%E6%A1%BF-%E7%8D%A8%E7%AB%8B%E9%8D%B5%E7%9B%A4-%E9%96%8B%E9%97%9C%E6%8C%89%E9%88%95-%E5%96%AE%E7%89%87%E6%A9%9F-i.280233910.5445695741) | |
    | 電磁閥 | 65 | 1 | 65 | [link](https://shopee.tw/-%E7%92%B0%E5%B3%B6%E7%A7%91%E6%8A%80-(C15-4)%E9%9B%BB%E7%A3%81%E9%96%A5-%E5%90%B8%E5%85%A5%E5%9E%8B%E9%9B%BB%E7%A3%81%E9%90%B5-%E6%A1%86%E6%9E%B6%E5%BC%8F%E5%BD%88%E7%B0%A7%E5%BE%A9%E4%BD%8D-%E6%AB%83%E9%8E%96%E9%9B%BB%E5%AD%90%E9%8E%96-%E5%BE%AE%E5%9E%8B0420-i.280233910.4252256579) | |
    | 蜂鳴器 | 5 | 1 | 5 | [link](https://shopee.tw/%E3%80%90%E5%82%91%E6%A3%AE%E5%89%B5%E5%B7%A5%E3%80%91%E6%9C%89%E6%BA%90%E8%9C%82%E9%B3%B4%E5%99%A8-5v-%E9%9B%BB%E7%A3%81%E5%BC%8F%E8%9C%82%E9%B3%B4%E5%99%A8-%E9%98%BB%E6%8A%9716%E6%AD%90%E5%A7%86-%E6%8E%A1%E7%94%A8SOT%E5%A1%91%E5%B0%81%E7%AE%A1-Arduino-i.20917936.390863126) | |
    | HC-SR04P | 45 | 1 | 45 | [link](https://shopee.tw/%E3%80%90%E5%82%91%E6%A3%AE%E5%89%B5%E5%B7%A5%E3%80%91HC-SR04P-3.3V-5V-Arduino-%E8%B6%85%E9%9F%B3%E6%B3%A2%E6%84%9F%E6%B8%AC%E5%99%A8-%E8%B6%85%E9%9F%B3%E6%B3%A2%E6%A8%A1%E7%B5%84-%E8%B6%85%E8%81%B2%E6%B3%A2%E6%A8%A1%E7%B5%84-%E9%81%BF%E9%9A%9C-%E6%B8%AC%E8%B7%9D-i.20917936.1483953180) | |
    | SG90 | 35 | 2 | 70 | [link](https://shopee.tw/%E3%80%90%E7%92%B0%E5%B3%B6%E7%A7%91%E6%8A%80%E3%80%91(F3-5)SG90-%E8%88%B5%E6%A9%9F%E2%98%85%E5%85%A8%E8%87%BA%E7%8F%BE%E8%B2%A8%E2%98%85-SG90-%E8%88%B5%E6%A9%9F-Tower-Pro-1.8Kg-%E6%89%AD%E5%8A%9B%E8%88%B5%E6%A9%9F-%E9%87%91%E5%B1%AC%E9%BD%92%E8%BC%AA%E6%9F%B1-i.280233910.6143762756) | |
    | 12Vto5V USB | 60 | 1 | 60 | [link](https://shopee.tw/%E3%80%90%E7%92%B0%E5%B3%B6%E7%A7%91%E6%8A%80%E3%80%91(C4-1)-DC-DC-USB%E7%9B%B4%E6%B5%81%E9%99%8D%E5%A3%93%E6%A8%A1%E5%A1%8A12V24V%E8%BD%895V-QC3.0%E6%89%8B%E6%A9%9F%E5%BF%AB%E5%85%85-i.280233910.7246980817) | |
    | micro USB線 | 35 | 1 | 35 | [link](https://shopee.tw/%E3%80%90%E5%82%91%E6%A3%AE%E5%89%B5%E5%B7%A5%E3%80%91%E9%AB%98%E5%93%81%E8%B3%AAMicro-USB%E5%85%85%E9%9B%BB-%E5%82%B3%E8%BC%B8%E7%B7%9A-Android%E9%80%9A%E7%94%A8-%E5%A4%A7%E9%9B%BB%E6%B5%81-%E5%A4%A7%E5%BB%A0%E4%BB%A3%E5%B7%A5-LG-HTC-Samsung-i.20917936.369015508) | |
    | M2螺帽 | 10 per 10 | 32 | 40 | [link](https://shopee.tw/m2m2.-5-m2.6-m3-m3.5-m4-m5-m6-m8m10-m12%E4%B8%8D%E9%8F%BD%E9%8B%BC%E8%9E%BA%E5%B8%BD-%E7%99%BD%E9%90%B5%E5%85%AD%E8%A7%92%E8%9E%BA%E5%B8%BD-%E5%A4%96%E5%85%AD%E8%A7%92%E8%9E%BA%E5%B8%BD-%E8%9E%BA%E6%AF%8D-i.752514.60073764) | 6/3已到貨(Y) |
    | M2\*9銅柱 | 10 per 10 | 4 | 10 | [link](https://shopee.tw/m2*3~27(10%E6%94%AF)%E7%B3%BB%E5%88%97%E5%90%84%E5%B0%BA%E9%8A%85%E6%9F%B1-%E9%9B%99%E9%80%9A%E6%AF%8D-%E9%9A%94%E9%9B%A2%E6%9F%B1-%E8%95%BE%E7%B5%B2%E9%8A%85%E6%9F%B1-%E7%9B%A3%E6%8E%A7%E9%8A%85%E6%9F%B1-%E6%AD%A1%E8%BF%8E%E6%B4%BD%E8%A9%A2-i.752514.942156066) | 6/3已到貨(Y) |
    | M2螺絲 | 詢價 | 35 | 100 | [link](https://shopee.tw/%E3%80%90%E8%AB%8B%E8%A9%A2%E5%83%B9%E5%BE%8C%E8%B3%BC%E8%B2%B7%E3%80%91%E4%B8%8D%E9%8F%BD%E9%8B%BC%E7%99%BD%E9%90%B5-m1-m1.2-m1.4-m1.6-m2-%E5%90%84%E5%B0%BA%E5%AF%B8%E4%B8%B8%E9%A0%AD%E5%8D%81%E5%AD%97%E8%9E%BA%E7%B5%B2-%E5%BE%AE%E5%9E%8B%E8%9E%BA%E7%B5%B2-i.752514.60074558) | 6/3已到貨(Y)|
    | 雷切支架、排障裝置 |  |  | 1500 |  |
    | 3DP 聯軸器 |  | 2 | 0 | 組員提供 |
    | 麵包板 |  | 1 | 0 | 組員提供 |
    | 220 ohm電阻 |  | 3 | 0 | 組員提供 |
    | ~~28BYJ48 5V/12V~~ | 35/40 | 1 | 35/40 | [link](https://shopee.tw/%E3%80%90UCI%E9%9B%BB%E5%AD%90%E3%80%91(15-2)-28BYJ-48-%E6%AD%A5%E9%80%B2%E9%A6%AC%E9%81%945V-12V-4%E7%9B%B85%E7%B7%9A-%E6%B8%9B%E9%80%9F%E9%9B%BB%E6%A9%9F-i.2305548.73316735) | |
    | ~~ULN2003~~ | 19 | 1 | 19 | [link](https://shopee.tw/%E3%80%90%E8%90%8D%E8%90%8D%E3%80%91ULN2003-%E6%AD%A5%E9%80%B2%E9%A6%AC%E9%81%94%E9%A9%85%E5%8B%95%E6%A8%A1%E7%B5%84-%E4%BA%94%E7%B7%9A%E5%9B%9B%E7%9B%B8-%E6%AD%A5%E9%80%B2%E9%A6%AC%E9%81%94-%E6%B8%9B%E9%80%9F%E9%9B%BB%E6%A9%9F-28BYJ-48-5V-i.10708564.5042676687) |
    | *課程提供* |  |  |  |  |
    | 車車本人 | 0 | 1 | 0 |  |
    | Raspberry Pi 3B | 0 | 1 | 0 |  |
    | Raspberry Pi SD卡 | 0 | 1 | 0 |  |
    | Pi camara | 0 | 1 | 0 |   |
    | MFRC-522 | 0 | 1 | 0 |  |
    | 繼電器 | 0 | 1 | 0 |  |
    | MJE3055T | 0 | 2 | 0 |  |
    | LM2596 | 0 | 1 | 0 |  |
    | M3螺絲 | 0 | 15 | 0 |  |
    | M3螺帽 | 0 | 35 | 0 |  |
    | 單芯線 | 0 | 3+3 m | 0 |  |
    | 杜邦線 公-公 | 0 | 15 | 0 |  |
    | 杜邦線 公-母 | 0 | 40 | 0 |  |
    | 杜邦線 母-母 | 0 | 15 | 0 |  |
* 組內討論事項 (必填，如問題、構想、分工合作、時間安排...等等)
  * 載物
    * 有蓋的盒子(有電磁鎖)
  * 自行移動
    * 紅外線循跡，須預鋪軌道
  * 升降
    * 兩組X型升降機構(避免支撐偏向一側會不穩)
    * 步進馬達
    * 正反牙螺桿 or 分兩組動力
  * 設定目的地
    * 上蓋LCD+搖桿選擇目的地
    * 電腦控制&規劃(或直接紀錄在開發版上)
  * 確認抵達目的地
    * 底部RFID感應走到node或終點
  * LCD指示狀態
    * 裝在盒子上蓋
  * 自動歸位
    * 設定一個「停車區」
  * 身份辨識
    * 刷RFID才能打開
    * 裝在盒子上蓋
    * 盒子需有電磁閥上鎖
  * 警示功能(聲音)
    * 蜂鳴器
    * 時機：迷路(走出軌道)、遇到無法排除的障礙、準備上升、偵測到有障礙物主動接近
  * 自動避障(近距離、固定)
    * 超音波感測器x3
    * 感應到前方有障礙物就推開
  * 排除障礙物
    * 用伺服馬達控制密集板，將障礙物推到兩側
    * 減速並嘗試用**機械手臂**將其移除
    * 無法移除就嘗試繞道
  * 自動避障(長距離、移動)
    * 用pi-camera辨識路徑上是否有**靠近中**的障礙物(人、動物)，若有的話則停車並發出**警示音**
  * system diagram
    ```mermaid
    flowchart TB
        A("Arduino Uno")
        R("Raspberry Pi")
        Sir("Infrared Sensor")
        Srf("RFID Sensor")
        Sult("Ultrasound Sensor x2")
        C("Computer(BFS alg. using Python)")
        M("Motor(L298N)")
        Cam("pi camera")
        J("joystick")
        Servo1("Servo(front)")
        Servo2("Stepper(platform)")
        LCD("LCD")
        B("Buzzer")
        V("Electromagnetic valve")

        A-.node & stop & RFID detail.->C
        C-.direction.->A
        Sir--road information-->A
        A--speed-->M
        A<--conmunication-->R
        Cam--image-->R
        Sult--distance-->R
        Srf--RFID detail-->R
        J-->R
        R-->Servo1
        R-->Servo2
        R-->LCD
        R-->B
        R-->V
    ```
* 組員分工 (必填)
  * 待填
* 遇到問題之處理狀況、解決方式 (必填)
  * 待填
* 課程建議 (選填)
  * 待填
* 想說的話 (選填)
  * 待填

## 第十四週批閱區 - 自選題proposal報告

* 助教批閱欄
  * 零件和流程看起來蠻清楚的，疫情期間的分工應該會是蠻大的挑戰，可以討論一下。

> [name=呂英弘]

* 教授批閱欄
  * 評分等第 A-
  * 教授回饋 記錄簿前半部整理的不錯，但有些必填的部分漏掉了。另外，我們評分是以各位新加入的功能為主，萬一沒有車子，也不用擔心。你們可以多強調各個組件的功能，明確說明這些組件要如何整合進平台，以及評估有了這些組件可以達到什麼功能即可。
> [name=盧奕璋]

## 第十五週紀錄 - 自選題進度報告

* 預計完成事項 (必填)
  * 6/2預設進度
  * 硬體
    * 完成50%硬體組裝，因為有些機構零件需要配合模組來組裝，而我們組測試模組與機構組裝是不同組員負責的，因此進度有限。
    * 完成模組基本測試，確認每一個模組都能夠順利運作。
  * 軟體
    * rpi、pi-camera測試
    * 影像讀取，判定移動測試
* 實際達成事項 (必填)
  * 硬體：
    * **完成機構草圖**設計
    * 開始進行機構草圖的優化
      * 支撐結構優化
      * 線路規劃優化
      * 體積縮小
    * **完成硬體3D模型**
    * 電子元件&模組測試(\*:還未收到，無法測試:cry:)
      * [x] 超音波感測模組
      * [x] 伺服馬達(180、360度)
      * [ ] 電源模組
        * 因為沒有10V以上電壓源，故無法測試
      * [x] 電磁閥
      * [x] LCD顯示器
      * [x] 五向搖桿
      * [x] 蜂鳴器
      * [x] \*繼電器
      * [ ] \*RFID
      * [x] \*電晶體
      * [ ] \*Rpi
      * [ ] \*pi camera
  * 軟體：
  
    **影像辨識部分:**
    * motion detection test  
      在兩張相鄰的影片擷取影像中，若差異太大的點所圍成的區域大於某一特定的闕值，則判定為有物體移動。但問題會出現在背景都被判斷進去。

    * optical flow test  
      <font size=4>
      **[這邊特感謝英弘助教跟我們說可以使用這個來參考]**
      </font>

      利用```ShiTomasi corner detection```擷取特定的點來進行```lucas-kanade method```，以計算各點在螢幕裡的移動情形:
      $$\frac{\partial{I}}{\partial{x}}\frac{dx}{dt}+\frac{\partial{I}}{\partial{y}}\frac{dy}{dt}+\frac{\partial{I}}{\partial{t}}=0$$

      optical flow中所需的$\dfrac{dx}{dt}$、$\dfrac{dy}{dt}$，不能藉由單一的點完成分析，所以都是取附近多個點。

      利用這個，可以擷取foreground物體的移動情形，也能夠改成偵測背景的移動。

      [ref: Moving Object Detection Based on Optical Flow Estimation and a Gaussian Mixture Model for Advanced Driver Assistance Systems](https://www.mdpi.com/1424-8220/19/14/3217)  

    * **Camera Motion Test!!**  
      camera motion是建立在全圖固定座標上的optical flow，透過整體位置移動的情形來做判讀。像這邊試跑的，可以畫出每一個點相對的移動方向，並判定整體是否有移動。
      ![](https://i.imgur.com/z4fgnt0.jpg)

      :::info
      **這邊的話原本是要寫camera的移動性，但經過一些修正之後可以做為正式使用!**
      :::

      1. 當速度緩慢的時候，外界的移動也是緩慢的，因此若將判定```movement```的闕值調高，那在正常移動速度緩慢的情況下電腦會判定移動模式為stable。
      2. 當有物體快速接近攝影機時，依相對速度的觀點，我們站在攝影機上的座標系來看，會認為是自己以快速的速度接近物體，因此會有```movement```的判定(trucking,平移)。
      3. 因此這樣的判斷結果可以作為判定是否有物體快速接近或者是有物體快速的自前方進行移動，而不會因為車子本身在移動而產生如```motion detection test```中的背景判讀錯誤。

      實測結果(目前不是使用裝好的picamera) 會發現當球很靠近攝影機的時候，會判定是有值的速度，意思等同於**有物體在非常靠近鏡頭處進行移動**，可能會需要發出警報!!

    **檔案傳輸部分:**
* 組內討論事項 (必填，如問題、構想、分工合作、時間安排...等等)
  * 討論問題(硬體)
    * 確認車體所需功能以及模組擺放位置
    * **支撐位置改良**，避免部分面積受力過大或重心偏移
    * 考量到R-Pi在處理影像時會過熱，因此討論要如何散熱，到網路上找尋相關資訊，並考慮空間、重量以及成本因素後決定採用散熱片，其效能較風扇高一點。
  * 討論問題(軟體)
    * 叫車及排程路線規劃程式
    * 動態影像識別程式
      目前還不確定要**直接影像辨識**(已完成)還是要透過**訓練object tracking的tensorflow project**來做為主要的處理。

  * 到時候要如何把硬體設備安裝在機構上
* 組員分工 (必填)
  * 一人負責硬體支架及空間規劃
  * 一人負責影像辨識
  * 一人負責模組測試及軟體架構
* 遇到問題之處理狀況、解決方式 (必填)
  * 軟體error  
    執行深度學習的Scikit-Learn 模組時，容易在有限的次數內執行訓練，但結果卻還是差異很大，產生```ConvergenceWarning```。

    * 暫時強制把warning給忽略，反正執行的迴圈次數真的非常多www，目前在影片後段看到的判斷結果也是正常的
        ```python
        # ignore the convergence warning
        from warnings import simplefilter
        from sklearn.exceptions import ConvergenceWarning
        simplefilter("ignore", category=ConvergenceWarning)
        ```
  * 支撐位置
    * 重新分配車體支撐位置，將重量導引至原車車的支撐結構上
  * 模組位置
    * 分配模組位置使拉線跟散熱能力最佳化
  * 叫車及排程
    * 修改R pi的```/etc/rc.local```，使啟動後自動開始執行```server```程式，控制車車排程及路線
    * 一般使用者以```ssh```方式連上R pi，啟動```client```程式，透過```socket```(IPC)向```server```發出叫車請求
* 課程建議 (選填)
  * 待填
* 想說的話 (選填)
  * 楊珩：  
    這幾個禮拜我不斷地在畫2D平面圖，在頭腦中不斷模擬成品組合起來的樣子，並與組員討論車體的結構優化，雖然畫圖與改圖花了很多時間，但也讓我更熟悉如何使用AutoCAD與Fusion 360，我也在平面圖完成後拿到Fusion 360把零件組合成立體模型，看到誠品的樣子真的讓我感到非常有成就感!
  * 張哲銘：  
    從不能到校上課以後，在python的學習上真的都是自己來，跟同學教的，真的不斷學到很多東西。這禮拜也自主學習了很多的module，```argparse```, ```sklearn``` 到最主要的```opencv-python```，真的很累但也學到很多。希望如果可以的話，接下來能夠併入已經訓練好的模組，讓他識別物體的能力更強!
  * 徐以帆：  
    這次在測試模組時不小心接錯VCC及GND導致用來測試的Arduino nano燒壞，之後使用R pi時要更加小心，反覆確認接線再過電。

## 第十五週批閱區 - 自選題進度報告

* 助教批閱欄
  * 看起來你們已經implement了不少演算法和系統流程了，感覺花了不少工夫，讚讚。
  * 如果想用tensorflow，建議可以輸出tensorflow lite然後跑在手機上，然後把手機直接架在車上，不然rpi3可能跑不動。(但寫Android程式也不容易就是了)
  * 有一點點看不太懂client的流程，如果已經開server那應該只要在同一個網域就不用再ssh進去用IPC溝通？(不過你們只要可以demo成功方法都OK)
    * [回應] server是開在local host，所以是ssh進去R pi執行R pi上的client，這樣就不用自己寫使用者的身分驗證(把登入R pi當作權限控管的方式)

> [name=呂英弘]

* 教授批閱欄
  * 評分等第 A+
  * 教授回饋 
  * 1. "闕值" -> 閥值
  * 2. 影像辨識、結構設計、軟體設計都有用心與新進展，紀錄簡明扼要。
  * 3. 與所規劃的Gantt Chart時程，超前還是落後?

> [name=張時中]

## 第十六週紀錄 - 自選題進度報告

* 預計完成事項 (必填)
  * 硬體
    * 測試車車功能是否完好
    * 重壓測試
    * 完成80%硬體組裝(結合原本車體) 
      * 有部分零件需要與模組相結合才方便安裝，因此尚無法完成組裝。
      * 買完剩餘所需材料
        * Rpi專用散熱片(15~20元)
        * M3 15mm螺絲，固定模組用(10~15元)
        * 快乾膠(黏合密集板用)
        * 彈簧(備用，用來幫助X型支架的升降)
    * 使用R pi控制新加的模組
  * 軟體
    * 影像辨識
    * 通訊程式
* 實際達成事項 (必填)
  * 硬體
    * 大部分已組裝完成
    * 完成基本功能測試
    * 完成升降平台初步測試  
      {%youtube UMH_EkVfQDw %}  
      組裝後與設計草圖所模擬的一樣  
      ![](https://i.imgur.com/G6G1kbG.png)
    * 經過重壓測試後(放上相等物重之物)，**車車一樣能穩定行走:grin:**，只是行走速度稍微下降。
    * :::info
      **等重之物**  
      **我們事先估計了密集板總重以及模組螺絲等重量後，再把相等物重之物壓在車頂板上，模擬實際行走時的負重，以確保移動功能依舊完善。**
      :::
    * :::danger
      R pi因不明原因中途故障:cry:，故需暫時延後硬體測試，已請助教幫忙。
      :::
  * 軟體
    * 完成通訊程式，但只能在筆電上的linuxc環境進行測試，等R pi抵達再進行整合
    * 影像實際測試部分，因為沒有RPi的環境，暫時參考網路上使用picamera的code。  
      因為```cv2.videocapture```函式所抓取的攝影機和```picamera``` 是不相容的(直接使用也是可以但會需要驅動軟體)，所以嘗試在沒有實際硬體與library的情況下建立起能讓```cv2.videocapture```access到```picamera```的中間程式，並且用```threading```提高其FPS。

      :::info
      先確定影片能輸出，到時候若FPS高會導致無法使用前面的影像辨別程式的話，再把```threading```移除即可)
      :::

* 組內討論事項 (必填，如問題、構想、分工合作、時間安排...等等)
  * 硬體問題
    * 初步測試發現左馬達**疑似**有問題，一開始狀況是時轉時不轉，過了一段時間後發現壓重物移動時有不正常、週期性的怪聲，初步判定為馬達內齒輪組發生某幾齒斷裂的情形(其他組也有遇過)
    * 仔細思考找到能夠讓支架升降最省力的方法，同時要考慮整體穩定性。
    * :::danger
      由於R pi使用headless設置，故一開始斷線以為是網路不良所致，事後測試發現3V3腳位無法量到電壓才知道R pi故障。

      分析原因:  
      當時是在成功完成基本設置，沒有接任何GPIO，僅使用pi camera成功拍照並成功利用FSTP下載照片後，正在筆電上查詢其他設定方式時斷線，目前無法判斷中途故障的原因。
      :::
* 組員分工 (必填)
  * 一人負責硬體組裝及測試
  * 一人負責影像辨識與輸入處理
  * 一人負責模組測試及程式撰寫
* 遇到問題之處理狀況、解決方式 (必填)
  * 對於左馬達的問題，不排除購買更換新的一顆馬達
  * 支架在位置較低時所需的水平拉力頗大，目前仍不確定伺服馬達是否能夠利用羅感來成功帶動裝置，因此會先買一些彈簧來幫忙分擔拉力。
  * R pi故障，經詢問助教後，助教可以幫忙再寄新的R pi，***在此特別感謝助教大力幫忙!!***
* 課程建議 (選填)
  * 待填
* 想說的話 (選填)
  * 張哲銘：
  * 徐以帆：  
    在最後的階段遇到硬體故障真的很緊張，感謝助教盡力幫忙。希望之後能一切順利。
  * 楊珩：  
    經過了這幾周的磨練大家都成長了不少，希望在最後的這幾周一樣能夠繼續撐下去，完成我們的final project，同時也能兼顧好各科的期末考!:crossed_swords:

## 第十六週批閱區 - 自選題進度報告

* 助教批閱欄
  * 目前看起來是已經把手邊的零件兜在一起了蠻好的，但是rpi故障的問題應該會影響你們進度蠻多的，繼續加油~

> [name=呂英弘]

* 教授批閱欄
  * 評分等第 A+
  * 教授回饋 有量化的工作記錄會更好，例如：密集板的重量、FPS提高前與提高後的數目、水平拉力怎樣算是頗大...等等。錯字：羅感-->螺桿(?)。

> [name=盧奕璋]


## 第十七週紀錄

* 疫情下之調整與心得建議
  * 分工變得較為麻煩，原本希望可以共同討論軟硬體的設置，但由於模組及硬體不方便互相傳遞，因此必須改為明確切割的分工方式，和上半學期相比少了不少團隊合作的部分。
  * 微積分好難，一整週都在讀，今天考完了但還有好多科，希望可以平平安安活過下禮拜:lying_face::dizzy_face::cry:
  * 希望疫情趕快結束，真的拜託！:disappointed::sob::crying_cat_face:
  * ![](https://i.imgur.com/GbUI5DC.png)
教授您好，因為助教說在本週記錄簿新增疫情下之調整與心得建議主題項目，而我們這組三位同學都認為是在第十七週加上此項目就好。  
因為這週本來沒有任何東西，所以助教說的新增是直接copy前一週來再加上疫情，還是只要新增疫情，我們認為是文字解讀問題。
## 第十七週批閱區

* 助教批閱欄
  * 期末考辛苦了，final demo前看起來還有不少要合在一起的部分，可以盡快彼此討論出一個合作模式跟時程，加油~

> [name=呂英弘]

* 教授批閱欄
  * 評分等第 B
  * 教授回饋 1. 本週看來進度很少(或說零?)，所以沒有寫甚麼工作紀錄，可以理解。 你們組原來就是這樣規劃時程嗎? 若有調整，請記得要更新。
  *         2. 期末考後，可否具體舉例分享一兩項分工合作方式的改變，以及你們小組所發展出最有效的遠端合作方式? 謝謝!

> [name=張時中]

###### tags: `電資工程入門設計與實作` `109-2`
