2026年8月17日 星期一

顏色分類程序模擬

顏色分類程序模擬 



  • 為了讓 EasyBuilder Pro 中的動畫能按照預期的流程運行,請新增 Macro(巨集)程式。若要設定初始條件,請建立一個僅在開機初始時執行一次的 Macro 程式;若要讓所有物件都能符合預期的流程,請建立一個每 100 毫秒週期性持續執行的 Macro 程式。這兩個 Macro 程式皆可透過此連結下載:https://drive.google.com/file/d/1c7v9q-HqcTzzmn3DMime8PQ8LGhC4O-0/view?usp=sharing



  • macro_command main()
    short lw[3]={0,0,0}
    GetDataEx(lw[0], "Local HMI", LW, 2, 3)
    lw[0]=5 //kode warna
    lw[1]=100 //posisi x
    lw[2]=210 //posisi y
    SetDataEx(lw[0], "Local HMI", LW, 2, 3)
    end macro_command


    short
    lw[3]={0,0,0}
    • 說明:宣告一個含有 3 個元素的短整數(Short Integer,16-bit 有符號整數)陣列 lw,並初始化數值皆為 0

      • lw[0]:預計存放顏色代碼

      • lw[1]:預計存放 X 座標

      • lw[2]:預計存放 Y 座標


    GetDataEx(lw[0], "Local HMI", LW, 2, 3)
    
    • 說明:從本地觸控螢幕(Local HMI)的位址 LW-2 開始,連續讀取 3 個 Words(即 LW-2, LW-3, LW-4)的數值,並寫入陣列 lw[0]lw[1]lw[2] 中。

    • 參數解析

      • lw[0]:接收資料的起始目標變數

      • "Local HMI":資料來源設備

      • LW:記憶體區塊類型(Local Word)

      • 2:起始位址(LW-2)

      • 3:連續讀取的筆數(長度)

    • (註:在此範例中,這行讀取動作會被隨後的給值覆蓋,主要作用為確保陣列與 HMI 記憶體位址對齊或同步)


    lw[0]=5 //kode warna
    lw[1]=100 //posisi x
    lw[2]=210 //posisi y
    
    • 說明:在巨集內部給予物件屬性設定值:

      • lw[0] = 5:將顏色代碼(Kode Warna)設定為 5

      • lw[1] = 100:將 X 軸位置(Posisi X)設定為 100

      • lw[2] = 210:將 Y 軸位置(Posisi Y)設定為 210


    SetDataEx(lw[0], "Local HMI", LW, 2, 3)
    
    • 說明:將陣列 lw 中的最新數值,一次性寫回本地觸控螢幕(Local HMI)的 LW-2 開始連續 3 個位址。

    • 對應寫入結果

      • LW-2 = 5 (顏色代碼)

      • LW-3 = 100 (X 座標)

      • LW-4 = 210 (Y 座標)


    macro_command main()
    short lw[7] = {0,0,0,0,0,0,0} //target, sorter, warna, posx, posy, rand, konv 
    bool lb[7]={false,false,false,false,false,false,false} //tb1, tb2, konv, div, sort, wk1, wk2 
    GetDataEx(lw[0], "Local HMI", LW, 0, 7)
    GetDataEx(lb[0], "Local HMI", LB, 0, 7)
    if(lb[0] or lb[5]) then
        RAND(lw[5])
        lw[2]=lw[5]%5
    end if
    if(lb[1] or lb[6]) then
        lb[2]=true
    end if
    if(lb[2]) then
        if(lw[3]>460) then
        lb[4]=true
        lb[2]=false
        else
        lw[3]=lw[3]+5
        lw[6]=lw[3]%2    
        end if
    end if
    if(lw[3]>250) then
        lb[3]=true
    end if
    if(lb[3]) then
        lw[0]=lw[2]*5
        if(lw[1]>lw[0]) then
            lw[1]=lw[1]-1
        else if(lw[1]<lw[0]) then
            lw[1]=lw[1]+1
        else
            lb[3]=false
        end if
    end if
    if(lb[4]) then
        if(lw[2]==0) then
            if(lw[4]<55) then
                lw[2]=5        
                lw[3]=100    
                lw[4]=210     
                lb[4]=false    
            else
            lw[4]=lw[4]-5         
            end if
        end if
        if(lw[2]==1) then
            if(lw[4]<105) then
                lw[2]=5
                lw[3]=100
                lw[4]=210
                lb[4]=false
            else
                lw[3]=lw[3]+5
                lw[4]=lw[4]-5
            end if
        end if
        if(lw[2]==2) then
            if(lw[3]>610) then
                lw[2]=5
                lw[3]=100
                lw[4]=210
                lb[4]=false
            else
                lw[3]=lw[3]+5
            end if
        end if
        if(lw[2]==3) then
            if(lw[4]>315) then
                lw[2]=5
                lw[3]=100
                lw[4]=210
                lb[4]=false
            else
                lw[3]=lw[3]+5
                lw[4]=lw[4]+5
            end if
        end if
        if(lw[2]==4) then
            if(lw[4]>355) then
                lw[2]=5
                lw[3]=100
                lw[4]=210
                lb[4]=false
            else
                lw[4]=lw[4]+5
            end if
        end if
    end if
    SetDataEx(lw[0], "Local HMI", LW, 0, 7)
    SetDataEx(lb[0], "Local HMI", LB, 0, 7)
    end macro_command

  • 這段 EasyBuilder Pro 巨集程式碼是整個 「自動化分揀傳送帶系統」的核心動畫邏輯控制(配合每 100ms 週期執行的巨集)。

    它負責處理隨機生成物品顏色啟動傳送帶推進動態調整分揀導軌角度/位置,以及將不同顏色的物品分流推入對應的收集箱

    一、 變數與暫存器對照表

    在解析邏輯前,我們先整理程式碼中定義的 14 個核心暫存器:

    1. 數值暫存器 LW[0..6] (16-bit Integer)

    變數對應暫存器原文註解功能說明
    lw[0]LW-0target分揀導軌/機構目標角度(依顏色計算出:lw[2] * 5
    lw[1]LW-1sorter分揀導軌/機構當前實際角度(逐漸向 lw[0] 靠近)
    lw[2]LW-2warna物品顏色代碼(0~4 代表 5 種顏色,5 為無物品/預設)
    lw[3]LW-3posx物品的 X 軸座標
    lw[4]LW-4posy物品的 Y 軸座標
    lw[5]LW-5rand亂數暫存器
    lw[6]LW-6konv傳送帶運轉狀態動畫切換(01 閃爍效果)

    2. 開關/狀態暫存器 LB[0..6] (1-bit Boolean)

    變數對應暫存器原文註解功能說明
    lb[0]LB-0tb1HMI 按鈕 S1(產生新物品)
    lb[1]LB-1tb2HMI 按鈕 S2(啟動傳送帶)
    lb[2]LB-2konv傳送帶運轉中狀態旗標
    lb[3]LB-3div導軌轉動/調整角度旗標
    lb[4]LB-4sort物品進入分流/推入箱子動作旗標
    lb[5]LB-5wk1Wokwi MQTT 傳入的 S1 按鈕觸發訊號
    lb[6]LB-6wk2Wokwi MQTT 傳入的 S2 按鈕觸發訊號

    二、 核心程式邏輯區段說明

    1. 資料讀取 (GetDataEx)


    GetDataEx(lw[0], "Local HMI", LW, 0, 7)
    GetDataEx(lb[0], "Local HMI", LB, 0, 7)
    
    • 說明:一次性從 HMI 讀取 LW-0 ~ LW-6LB-0 ~ LB-6 當前的最新數值。

    2. 生成隨機顏色物品 (S1 按鈕觸發)


    if(lb[0] or lb[5]) then
        RAND(lw[5])
        lw[2]=lw[5]%5
    end if
    
    • 說明:當按下 HMI 的 S1 (lb[0]) 或 Wokwi 的 S1 (lb[5]) 時:

      • 產生隨機數寫入 lw[5]

      • 取餘數 lw[5] % 5,隨機決定目前物品的顏色代碼 lw[2](結果為 $0, 1, 2, 3, 4$ 其中一種)。

    3. 啟動傳送帶 (S2 按鈕觸發)


    if(lb[1] or lb[6]) then
        lb[2]=true
    end if
    
    • 說明:當按下 HMI 的 S2 (lb[1]) 或 Wokwi 的 S2 (lb[6]) 時,將傳送帶運送旗標 lb[2] 設定為 true

    4. 傳送帶運送邏輯


    if(lb[2]) then
        if(lw[3]>460) then
            lb[4]=true
            lb[2]=false
        else
            lw[3]=lw[3]+5
            lw[6]=lw[3]%2    
        end if
    end if
    
    • 說明:當傳送帶運轉中 (lb[2] == true):

      • 推進物品:X 座標 lw[3] 每次增加 5 個像素。

      • 動態動畫lw[6] = lw[3] % 2 產生 01 交替變化,可用於傳送帶的滾輪滾動效果。

      • 到達終點:當 X 座標超過 460 (lw[3] > 460) 時,代表物品已抵達分揀點。此時停止傳送帶 (lb[2]=false),並啟動分流推入動作 (lb[4]=true)。

    5. 導軌/分揀機構預先轉動切換


    if(lw[3]>250) then
        lb[3]=true
    end if
    
    if(lb[3]) then
        lw[0]=lw[2]*5
        if(lw[1]>lw[0]) then
            lw[1]=lw[1]-1
        else if(lw[1]<lw[0]) then
            lw[1]=lw[1]+1
        else
            lb[3]=false
        end if
    end if
    
    • 說明

      • 當物品在傳送帶上通過 X > 250 位置時,觸發導軌調整旗標 lb[3] = true

      • 依據物品顏色計算目標角度 lw[0] = lw[2] * 5

      • lw[1](當前導軌角度)會以每次 1 度的速度微調,逐漸靠近 lw[0],達到平滑轉動的動畫效果。達成目標後清除旗標 lb[3] = false

    6. 依顏色分流至對應容器 (Sort & Reset)

    lb[4] == true 時,依據顏色代碼 lw[2] ($0 \sim 4$) 執行不同的軌跡移動(改變 X, Y 座標),將物品推進對應箱子;完成後重置狀態(顏色設為 5,座標歸位至初始點 $(100, 210)$):

    C
    if(lb[4]) then
        // 顏色 0:往上方直推 (Y 遞減至 < 55)
        if(lw[2]==0) then
            if(lw[4]<55) then
                lw[2]=5; lw[3]=100; lw[4]=210; lb[4]=false    
            else
                lw[4]=lw[4]-5         
            end if
        end if
    
        // 顏色 1:往左上斜推 (X 遞增, Y 遞減至 < 105)
        if(lw[2]==1) then
            if(lw[4]<105) then
                lw[2]=5; lw[3]=100; lw[4]=210; lb[4]=false
            else
                lw[3]=lw[3]+5; lw[4]=lw[4]-5
            end if
        end if
    
        // 顏色 2:往右平推 (X 遞增至 > 610)
        if(lw[2]==2) then
            if(lw[3]>610) then
                lw[2]=5; lw[3]=100; lw[4]=210; lb[4]=false
            else
                lw[3]=lw[3]+5
            end if
        end if
    
        // 顏色 3:往右下斜推 (X 遞增, Y 遞增至 > 315)
        if(lw[2]==3) then
            if(lw[4]>315) then
                lw[2]=5; lw[3]=100; lw[4]=210; lb[4]=false
            else
                lw[3]=lw[3]+5; lw[4]=lw[4]+5
            end if
        end if
    
        // 顏色 4:往下方直推 (Y 遞增至 > 355)
        if(lw[2]==4) then
            if(lw[4]>355) then
                lw[2]=5; lw[3]=100; lw[4]=210; lb[4]=false
            else
                lw[4]=lw[4]+5
            end if
        end if
    end if
    

    7. 資料寫回 (SetDataEx)


    SetDataEx(lw[0], "Local HMI", LW, 0, 7)
    SetDataEx(lb[0], "Local HMI", LB, 0, 7)
    
    • 說明:將巨集計算後的最新座標、角度、狀態一次性寫回 HMI 的暫存器中,使畫面上的動態物件即時更新位置。

    三、 運作流程總結

    1. 按下 S1 $\rightarrow$ 隨機產生顏色代碼 ($0\sim4$),生成物品於 $(100, 210)$

    2. 按下 S2 $\rightarrow$ 傳送帶開始運轉,物品向右移動 ($X+5$)。

    3. 過半程 ($X > 250$) $\rightarrow$ 分揀機構依據顏色自動轉動到指定角度。

    4. 到達終點 ($X > 460$) $\rightarrow$ 傳送帶停止,開啟分流模式。

    5. 分流動作 $\rightarrow$ 依據 $0 \sim 4$ 不同的顏色,將物件分別推向 上、右上、右、右下、下 等 5 個方向的集料箱。

    6. 歸位 $\rightarrow$ 物件入箱後重置座標至 $(100,210)$,準備下一次操作。


  • 接下來,為了讓上述 EasyBuilder Pro 應用程式能夠與 ESP32 進行連線,請啟用 MQTT 功能。Broker 伺服器請使用:mqtt-dashboard.com。建立 Publisher Topic(發布主題):ebpro/wokwi/output,並包含 11 個 Tag,名稱分別為:lb0lb1lb2lb3lb4lb5lb6lw1lw2lw3lw4

  • 建立第一個 Subscriber Topic(訂閱主題):wokwi/ebpro/input1,Tag 名稱設定為:lb5。建立第二個 Subscriber Topic:wokwi/ebpro/input2,Tag 名稱設定為:lb6

  • 執行 EBPro 模擬:選擇「專案 (Project)」選單,點擊「離線模擬 (Offline Simulation)」。按下 S1 按鈕,傳送帶上方應會出現一個物件;按下 S2 按鈕,該物件應會由傳送帶運送,並透過引導軌導入對應顏色的容器中。

  • 點擊上述連結運行 Wokwi 電路模擬,等待直到顯示「MQTT Connected」字樣。在 Wokwi 中按下 S1 按鈕,EasyBuilder Pro 的傳送帶上方應會出現物件;在 Wokwi 中按下 S2 按鈕,物件應會由傳送帶運送,並透過引導軌導入對應顏色的容器中。


  • 顏色分類程序模擬 (Sorting Warna)
    以下為操作步驟:
    1. 開啟 Wokwi 專案:請點擊此連結開啟:Wokwi 專案連結
      (圖 8.1 ESP32 結合 I2C 16x2 LCD、繼電器、伺服馬達、5 個 LED 與 2 個按鈕的電路圖)
    2. 新建 EBPro 專案:在 EasyBuilder Pro 中建立一個新專案,並根據下表 8.1 的清單添加相對應的物件:
      (表 8.1 顏色分類模擬所使用的物件清單)
      • 導軌圖片(共 21 張圖)點此下載導軌圖片
      • 傳送帶圖片(共 2 張圖)點此下載傳送帶圖片
    3. 建立動畫與移動物件
      • 使用 字組點燈 (Word Lamp) 物件來製作「導軌 (Guide Rail)」與「傳送帶 (Conveyor)」的動畫。
      • 使用 移動圖形 (Moving Shape) 物件來製作可以「改變顏色」且「移動」的物體。
      • 詳細的操作流程,請觀看下方的製作教學影片:
        (顏色分類模擬製作教學影片)
    4. 編寫巨集程序 (Macro):為了讓 EasyBuilder Pro 的動畫能按照預期的流程運行,需要加入巨集程序:
      • 初始狀態巨集:建立一個「僅在啟動時執行一次」的巨集,用於設定物件的初始狀態。
      • 循環控制巨集:建立一個「每 100 毫秒定期連續執行」的巨集,讓所有物件能跟隨預定的流程變動。
      • 上述兩個巨集程式碼可在此下載:巨集檔案下載連結
    5. 配置 MQTT 通訊(發送端):為了讓 EasyBuilder Pro 能夠與 ESP32 進行連線,請啟用 MQTT 功能:
      • 伺服器代理(Broker)mqtt-dashboard.com
      • 發佈主題(Topic Publisher)ebpro/wokwi/output
      • 標籤(Tags):共 11 個標籤,名稱分別為 lb0, lb1, lb2, lb3, lb4, lb5, lb6, lw1, lw2, lw3, lw4
    6. 配置 MQTT 通訊(接收端)
      • 訂閱主題一(Topic Subscriber 1)wokwi/ebpro/input1,標籤名稱為 lb5
      • 訂閱主題二(Topic Subscriber 2)wokwi/ebpro/input2,標籤名稱為 lb6
    7. 執行 EBPro 離線模擬
      • 在功能選單中選擇「專案 (Project)」,然後點擊「離線模擬 (Offline Simulation)」。
      • 按下 S1 按鈕,此時傳送帶上方應該會出現一個物品。
      • 按下 S2 按鈕,該物品應會隨傳送帶移動,並由導軌將其分類推入對應顏色的容器中。
    8. 連動 Wokwi 硬體模擬
      • 運行上述步驟 1 的 Wokwi 電路,等待螢幕顯示 MQTT Connected(MQTT 已連線)。
      • Wokwi 中按下 S1 按鈕,此時 EasyBuilder Pro 的傳送帶上方應會同步出現物品。
      • Wokwi 中按下 S2 按鈕,物品應會隨傳送帶移動,並由導軌分類推入相對應顏色的容器中。



    8. 顏色分類程序模擬 (Sorting Warna)
    以下為操作步驟:
    1. 開啟 Wokwi 專案:請點擊此連結開啟:Wokwi 專案連結
      (圖 8.1 ESP32 結合 I2C 16x2 LCD、繼電器、伺服馬達、5 個 LED 與 2 個按鈕的電路圖)
    2. 新建 EBPro 專案:在 EasyBuilder Pro 中建立一個新專案,並根據下表 8.1 的清單添加相對應的物件:
      (表 8.1 顏色分類模擬所使用的物件清單)
      • 導軌圖片(共 21 張圖)點此下載導軌圖片
      • 傳送帶圖片(共 2 張圖)點此下載傳送帶圖片
    3. 建立動畫與移動物件
      • 使用 字組點燈 (Word Lamp) 物件來製作「導軌 (Guide Rail)」與「傳送帶 (Conveyor)」的動畫。
      • 使用 移動圖形 (Moving Shape) 物件來製作可以「改變顏色」且「移動」的物體。
      • 詳細的操作流程,請觀看下方的製作教學影片:
        (顏色分類模擬製作教學影片)
    4. 編寫巨集程序 (Macro):為了讓 EasyBuilder Pro 的動畫能按照預期的流程運行,需要加入巨集程序:
      • 初始狀態巨集:建立一個「僅在啟動時執行一次」的巨集,用於設定物件的初始狀態。
      • 循環控制巨集:建立一個「每 100 毫秒定期連續執行」的巨集,讓所有物件能跟隨預定的流程變動。
      • 上述兩個巨集程式碼可在此下載:巨集檔案下載連結
    5. 配置 MQTT 通訊(發送端):為了讓 EasyBuilder Pro 能夠與 ESP32 進行連線,請啟用 MQTT 功能:
      • 伺服器代理(Broker)mqtt-dashboard.com
      • 發佈主題(Topic Publisher)ebpro/wokwi/output
      • 標籤(Tags):共 11 個標籤,名稱分別為 lb0, lb1, lb2, lb3, lb4, lb5, lb6, lw1, lw2, lw3, lw4
    6. 配置 MQTT 通訊(接收端)
      • 訂閱主題一(Topic Subscriber 1)wokwi/ebpro/input1,標籤名稱為 lb5
      • 訂閱主題二(Topic Subscriber 2)wokwi/ebpro/input2,標籤名稱為 lb6
    7. 執行 EBPro 離線模擬
      • 在功能選單中選擇「專案 (Project)」,然後點擊「離線模擬 (Offline Simulation)」。
      • 按下 S1 按鈕,此時傳送帶上方應該會出現一個物品。
      • 按下 S2 按鈕,該物品應會隨傳送帶移動,並由導軌將其分類推入對應顏色的容器中。
    8. 連動 Wokwi 硬體模擬
      • 運行上述步驟 1 的 Wokwi 電路,等待螢幕顯示 MQTT Connected(MQTT 已連線)。
      • Wokwi 中按下 S1 按鈕,此時 EasyBuilder Pro 的傳送帶上方應會同步出現物品。
      • Wokwi 中按下 S2 按鈕,物品應會隨傳送帶移動,並由導軌分類推入相對應顏色的容器中。
    • 本節所製作的完整 EasyBuilder Pro 專案檔(.emtp/.cmtp)可在此下載:EBPro 專案下載連結*
    您是否需要我協助將下載的**巨集程式碼(Macro)**進行細部解釋,或是協助確認 MQTT 的 Tag(標籤)型態要如何設定?
    下載的**巨集程式碼(Macro)**進行細部解釋
    在這個自動化顏色分類專案中,下載的兩支巨集(Macro)分別扮演初始化工作動態循環控制的角色。
    雖然我無法直接打開您的雲端硬碟檔案,但根據 Weintek EasyBuilder Pro 的標準邏輯與 Wokwi 模擬的硬體架構,這兩支巨集的細部運作原理與代碼邏輯如下:

    1. 初始狀態巨集 (僅在啟動時執行一次)
    設定目的:確保 HMI 畫面剛開機時,所有元件都處於「正確的起點」,防止因為上次關機留下的殘留數據導致動畫錯亂。
    虛擬代碼與邏輯解析:
    pascal
    macro_command main()
        // 1. 將傳送帶(Word Lamp)與導軌(Word Lamp)的圖片索引歸零
        short resetValue = 0
        SetData(resetValue, "Local HMI", LW, 1, 1) // 假設 LW1 控制傳送帶動畫
        SetData(resetValue, "Local HMI", LW, 2, 1) // 假設 LW2 控制導軌動畫
    
        // 2. 將移動物體(Moving Shape)的坐標重設回起點
        short startX = 0 
        short startY = 100 // 範例起點坐標
        SetData(startX, "Local HMI", LW, 3, 1) // 物體 X 軸位置
        SetData(startY, "Local HMI", LW, 4, 1) // 物體 Y 軸位置
    
        // 3. 關閉所有開關與計數器
        bool offState = false
        SetData(offState, "Local HMI", LB, 0, 1) // 清除 S1 觸發狀態
        SetData(offState, "Local HMI", LB, 1, 1) // 清除 S2 運行狀態
    end macro_command
    
    請謹慎使用程式碼。
    • 關鍵指令 SetData:負責將數值寫入 HMI 的內部暫存器。
    • 執行時機:在 EBPro 巨集管理中,此巨集會被勾選為 「欲在 HMI 啟動時執行」

    2. 循環控制巨集 (每 100ms 連續執行)
    設定目的:這支巨集是整台分類機的「大腦」,負責計算物體的移動位置、何時播放傳送帶動畫,以及何時觸發導軌。
    動態核心邏輯解析:
    A. 傳送帶與物體移動邏輯 (當 S2 被按下,即 LB1 = ON 時)
    當 Wokwi 或 HMI 按下 S2 開始輸送時,巨集會執行遞增計算:
    pascal
    short posX, conveyorFrame
    GetData(posX, "Local HMI", LW, 3, 1) // 讀取當前物體 X 軸位置
    GetData(conveyorFrame, "Local HMI", LW, 1, 1) // 讀取傳送帶當前圖片幀
    
    if (posX < 200) then // 假設 200 是終點或導軌位置
        posX = posX + 5  // 每 100 毫秒向右移動 5 個像素
        SetData(posX, "Local HMI", LW, 3, 1)
        
        // 傳送帶動畫滾動 (在狀態 0 與 1 之間切換,形成走動錯覺)
        if conveyorFrame == 0 then conveyorFrame = 1 else conveyorFrame = 0
        SetData(conveyorFrame, "Local HMI", LW, 1, 1)
    end if
    
    請謹慎使用程式碼。
    B. 導軌推動分類動畫邏輯
    當物體移動到導軌前(例如 X 軸到達指定範圍),巨集會觸發導軌的 Word Lamp,開始播放那 21 張導軌圖片:
    pascal
    short railFrame
    GetData(railFrame, "Local HMI", LW, 2, 1)
    
    // 如果物體走到了分類點,啟動導軌退條動畫
    if (posX >= 150 and railFrame < 21) then
        railFrame = railFrame + 1 // 圖片格數逐一遞增 (0, 1, 2...20)
        SetData(railFrame, "Local HMI", LW, 2, 1)
        
        // 同步改變移動物體的 Y 軸坐標,將物體往推入箱子
        short posY
        GetData(posY, "Local HMI", LW, 4, 1)
        posY = posY + 3 // 往箱子方向移動
        SetData(posY, "Local HMI", LW, 4, 1)
    end if
    
    請謹慎使用程式碼。
    C. 物件顏色變更 (Moving Shape 狀態)
    巨集會讀取來自 Wokwi (ESP32 顏色感測器) 或模擬產生的顏色代號(例如:1=紅色、2=綠色、3=藍色),並將這個數值寫入控制 Moving Shape 的狀態暫存器,讓畫面上掉落的方塊瞬間變成對應的顏色。

    3. MQTT 標籤(Tag)在巨集中的對應
    步驟 5 提到的 11 個 Tag 扮演了 HMI 與巨集之間的橋樑:
    • lb0 ~ lb4 (位元):通常對應 HMI 畫面上的 LED 燈號狀態,巨集會根據 Wokwi 傳來的訊號,利用 SetData 控制這些燈的亮滅。
    • lw1 ~ lw4 (字組):傳遞物體坐標及計數。當巨集在 HMI 內部把 LW3 (物體位置) 算好後,MQTT 會即時把這個位置發佈(Publish)出去,Wokwi 的伺服馬達就能依據這個位置同步轉動角度!

    在這個自動化顏色分類專案中,下載的兩支巨集(Macro)分別扮演初始化工作動態循環控制的角色。

     Wokwi 模擬的硬體架構,這兩支巨集的細部運作原理與代碼邏輯如下:

    1. 初始狀態巨集 (僅在啟動時執行一次)
    設定目的:確保 HMI 畫面剛開機時,所有元件都處於「正確的起點」,防止因為上次關機留下的殘留數據導致動畫錯亂。
    虛擬代碼與邏輯解析:
    pascal
    macro_command main()
        // 1. 將傳送帶(Word Lamp)與導軌(Word Lamp)的圖片索引歸零
        short resetValue = 0
        SetData(resetValue, "Local HMI", LW, 1, 1) // 假設 LW1 控制傳送帶動畫
        SetData(resetValue, "Local HMI", LW, 2, 1) // 假設 LW2 控制導軌動畫
    
        // 2. 將移動物體(Moving Shape)的坐標重設回起點
        short startX = 0 
        short startY = 100 // 範例起點坐標
        SetData(startX, "Local HMI", LW, 3, 1) // 物體 X 軸位置
        SetData(startY, "Local HMI", LW, 4, 1) // 物體 Y 軸位置
    
        // 3. 關閉所有開關與計數器
        bool offState = false
        SetData(offState, "Local HMI", LB, 0, 1) // 清除 S1 觸發狀態
        SetData(offState, "Local HMI", LB, 1, 1) // 清除 S2 運行狀態
    end macro_command
    

    • 關鍵指令 SetData:負責將數值寫入 HMI 的內部暫存器。
    • 執行時機:在 EBPro 巨集管理中,此巨集會被勾選為 「欲在 HMI 啟動時執行」

    2. 循環控制巨集 (每 100ms 連續執行)
    設定目的:這支巨集是整台分類機的「大腦」,負責計算物體的移動位置、何時播放傳送帶動畫,以及何時觸發導軌。
    動態核心邏輯解析:
    A. 傳送帶與物體移動邏輯 (當 S2 被按下,即 LB1 = ON 時)
    當 Wokwi 或 HMI 按下 S2 開始輸送時,巨集會執行遞增計算:
    pascal
    short posX, conveyorFrame
    GetData(posX, "Local HMI", LW, 3, 1) // 讀取當前物體 X 軸位置
    GetData(conveyorFrame, "Local HMI", LW, 1, 1) // 讀取傳送帶當前圖片幀
    
    if (posX < 200) then // 假設 200 是終點或導軌位置
        posX = posX + 5  // 每 100 毫秒向右移動 5 個像素
        SetData(posX, "Local HMI", LW, 3, 1)
        
        // 傳送帶動畫滾動 (在狀態 0 與 1 之間切換,形成走動錯覺)
        if conveyorFrame == 0 then conveyorFrame = 1 else conveyorFrame = 0
        SetData(conveyorFrame, "Local HMI", LW, 1, 1)
    end if
    
    請謹慎使用程式碼。
    B. 導軌推動分類動畫邏輯
    當物體移動到導軌前(例如 X 軸到達指定範圍),巨集會觸發導軌的 Word Lamp,開始播放那 21 張導軌圖片:
    pascal
    short railFrame
    GetData(railFrame, "Local HMI", LW, 2, 1)
    
    // 如果物體走到了分類點,啟動導軌退條動畫
    if (posX >= 150 and railFrame < 21) then
        railFrame = railFrame + 1 // 圖片格數逐一遞增 (0, 1, 2...20)
        SetData(railFrame, "Local HMI", LW, 2, 1)
        
        // 同步改變移動物體的 Y 軸坐標,將物體往推入箱子
        short posY
        GetData(posY, "Local HMI", LW, 4, 1)
        posY = posY + 3 // 往箱子方向移動
        SetData(posY, "Local HMI", LW, 4, 1)
    end if
    

    C. 物件顏色變更 (Moving Shape 狀態)
    巨集會讀取來自 Wokwi (ESP32 顏色感測器) 或模擬產生的顏色代號(例如:1=紅色、2=綠色、3=藍色),並將這個數值寫入控制 Moving Shape 的狀態暫存器,讓畫面上掉落的方塊瞬間變成對應的顏色。

    3. MQTT 標籤(Tag)在巨集中的對應
    步驟 5 提到的 11 個 Tag 扮演了 HMI 與巨集之間的橋樑:
    • lb0 ~ lb4 (位元):通常對應 HMI 畫面上的 LED 燈號狀態,巨集會根據 Wokwi 傳來的訊號,利用 SetData 控制這些燈的亮滅。
    • lw1 ~ lw4 (字組):傳遞物體坐標及計數。當巨集在 HMI 內部把 LW3 (物體位置) 算好後,MQTT 會即時把這個位置發佈(Publish)出去,Wokwi 的伺服馬達就能依據這個位置同步轉動角度!
    您可以打開這兩支巨集檔案,看看裡面的 SetDataGetData 後面接的是哪些 LW 或 LB 暫存器編號 嗎?我可以針對您看到的特定變數名稱為您做更精準的對照說明。

    顏色排序過程模擬」或「色彩分選過程模擬

  • 工業自動化:指光電色彩分選機(Color Sorter)在產線上自動依據顏色分選農產品(如稻米、豆類)或工業原料的運作模擬。
  • 電腦科學:指色彩排序演算法(例如將不同顏色或數字代表的顏色進行排序,如 LeetCode 的 Sort Colors 題型)的程式執行模擬。


  • 為了讓 EasyBuilder Pro 中的動畫能依照所需的流程順暢運行,請加入巨集(Macro)程式。若要設定初始狀態,請建立一個僅在啟動時執行一次的初始巨集程式;若要讓所有物件都能遵循所需的工藝流程運行,請建立一個每 100 毫秒週期性持續執行的循環巨集程式。上述這兩個巨集程式皆可在此連結下載:
    https://drive.google.com/file/d/1c7v9q-HqcTzzmn3DMime8PQ8LGhC4O-0/view?usp=sharing




    #include <WiFi.h>
    #include <PubSubClient.h>
    #include <LiquidCrystal_I2C.h>
    #include <ESP32Servo.h>
    #include <ArduinoJson.h>
    #define ssid "Wokwi-GUEST"
    #define pass ""
    #define server "mqtt-dashboard.com"
    #define port 1883
    WiFiClient espClient;
    PubSubClient client(espClient);
    LiquidCrystal_I2C lcd(0x27, 16, 2);
    Servo servo;
    int sa = 0;
    int sb = 0;
    int counter = 0;
    void callback(char* topic, byte* payload, unsigned int length) {
      JsonDocument doc;
      deserializeJson(doc, payload);
      bool lb0 = doc["lb0"];
      if (lb0) digitalWrite(4, HIGH);
      else digitalWrite(4, LOW);
      bool lb1 = doc["lb1"];
      if (lb1) digitalWrite(16, HIGH);
      else digitalWrite(16, LOW);
      bool lb2 = doc["lb2"];
      if (lb2) {
        digitalWrite(17, HIGH);
        digitalWrite(23, HIGH);
      }
      else {
        digitalWrite(17, LOW);
        digitalWrite(23, LOW);
      }
      bool lb3 = doc["lb3"];
      if (lb3) digitalWrite(5, HIGH);
      else digitalWrite(5, LOW);
      bool lb4 = doc["lb4"];
      if (lb4) digitalWrite(18, HIGH);
      else digitalWrite(18, LOW);
      int lw1 = doc["lw1"];
      servo.write(lw1 * 9);
      delay(10);
      lcd.setCursor(4, 0);
      if (lw1 < 10) lcd.print(" ");
      if (lw1 < 100) lcd.print(" ");
      lcd.print(lw1);
      int lw2 = doc["lw2"];
      lcd.setCursor(12, 0);
      lcd.print(lw2);
      int lw3 = doc["lw3"];
      lcd.setCursor(4, 1);
      if (lw3 < 10) lcd.print(" ");
      if (lw3 < 100) lcd.print(" ");
      lcd.print(lw3);
      int lw4 = doc["lw4"];
      lcd.setCursor(12, 1);
      if (lw4 < 10) lcd.print(" ");
      if (lw4 < 100) lcd.print(" ");
      lcd.print(lw4);
    }
    void reconnect() {
      while (!client.connected()) {
        Serial.print("Attempting MQTT connection...");
        // Create a random client ID
        String clientId = "ESP8266Client-";
        clientId += String(random(0xffff), HEX);
        // Attempt to connect
        if (client.connect(clientId.c_str())) {
          Serial.println("MQTT Connected");
          // Once connected, publish an announcement...
          client.publish("wokwi/ebpro/input1", "{\"lb5\":false}");
          client.publish("wokwi/ebpro/input2", "{\"lb6\":false}");
          client.subscribe("ebpro/wokwi/output");
        } else {
          Serial.print("failed, rc=");
          Serial.print(client.state());
          Serial.println(" try again in 5 seconds");
          // Wait 5 seconds before retrying
          delay(5000);
        }
      }
    }
    void setup() {
      Serial.begin(115200);
      Serial.print("Connecting to ");
      Serial.println(ssid);
      WiFi.begin(ssid, pass);
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
        if (counter > 10) {
          ESP.restart();
        }
        counter++;
      }
      Serial.println("WiFi connected");
      Serial.println("IP address: ");
      Serial.println(WiFi.localIP());
      servo.attach(19);
      lcd.init();
      lcd.backlight();
      lcd.setCursor(0, 0);
      lcd.print("an1:    an2:    ");
      lcd.setCursor(0, 1);
      lcd.print("an3:    an4:    ");
      pinMode(15, INPUT_PULLUP); //S1
      pinMode(2, INPUT_PULLUP); //S2
      pinMode(4, OUTPUT); //LED1
      pinMode(16, OUTPUT); //LED2
      pinMode(17, OUTPUT); //LED3
      pinMode(5, OUTPUT); //LED4
      pinMode(18, OUTPUT); //LED5
      pinMode(13, OUTPUT); //LED6
      pinMode(14, OUTPUT); //LED7
      pinMode(23, OUTPUT);//konveyor
      client.setServer(server, 1883);
      client.setCallback(callback);
      delay(1000);
    }
    void loop() {
      if (!client.connected()) {
        reconnect();
      }
      client.loop();
      int s1 = !digitalRead(15);
      int s2 = !digitalRead(2);
      if (s1 != sa) {
        Serial.println(s1);
        if (s1) {
          client.publish("wokwi/ebpro/input1", "{\"lb5\":true}");
          digitalWrite(13, HIGH);
        } else {
          client.publish("wokwi/ebpro/input1", "{\"lb5\":false}");
          digitalWrite(13, LOW);
        }
      } sa = s1;
      if (s2 != sb) {
        Serial.println(s2);
        if (s2) {
          client.publish("wokwi/ebpro/input2", "{\"lb6\":true}");
          digitalWrite(14, HIGH);
        } else {
          client.publish("wokwi/ebpro/input2", "{\"lb6\":false}");
          digitalWrite(14, LOW);
        }
      } sb = s2;
    }

    沒有留言:

    張貼留言

    Cargo Transfer Process Simulation 「貨物轉移過程模擬」

    Cargo Transfer Process Simulation「貨物轉移過程模擬」 https://www.youtube.com/watch?v=Ic9PpPG-_NU   以下是操作步驟: 打開 EasyBuilder Pro,選擇「新建專案」(New Project),...