2025年11月26日 星期三

DYNAMIXEL Protocol 2.0 (py uart demo)

 Python 透過 pyserial 函式庫向 /dev/ttyUSB0 埠發送您指定的 DYNAMIXEL Protocol 2.0 數據包的程式碼範例。

🚨 前置作業

您需要先安裝 pyserial 函式庫:

Bash
pip install pyserial

💻 Python 程式碼

這個程式碼會設定串列埠,並以二進位 (byte) 格式發送您提供的數據。

Python
import serial
import time
import binascii

# --- 串列埠設定 ---
SERIAL_PORT = '/dev/ttyUSB0'  # Linux 系統下通常是 ttyUSB0
BAUDRATE = 57600
TIMEOUT = 0.1  # 讀取逾時時間 (秒)

# --- 要發送的數據包 (Protocol 2.0 協定) ---
# FF FF FD 00 01 07 00 03 74 00 55 09 00 00 D5 27
# Header  ID Len(L/H) Instr Addr(L/H) Data(4 bytes) CRC(L/H)
# 數據包說明:
# ID: 01
# Instruction: 03 (WRITE)
# Address: 0x0074 (Goal Position)
# Data: 0x00000955 (2389, 這是 0x55 0x09 0x00 0x00 的 little-endian 轉換)
# CRC: 0xD5 0x27
HEX_STRING = "FFFFFD0001070003740055090000D527"

# 將十六進制字串轉換為 bytes
try:
    # binascii.unhexlify 將十六進制字串轉換為 bytes
    PACKET_TO_SEND = binascii.unhexlify(HEX_STRING)
except TypeError as e:
    print(f"錯誤:十六進制字串轉換失敗 - {e}")
    print("請檢查您的十六進制字串是否有效且長度為偶數。")
    exit(1)


def send_dynamixel_packet():
    """
    配置串列埠並發送 DYNAMIXEL 數據包。
    """
    print(f"嘗試開啟串列埠:{SERIAL_PORT},波特率:{BAUDRATE}")

    # 配置串列埠:57600 波特率,無奇偶校驗 (N),8 個數據位 (8),1 個停止位 (1)
    # pySerial 預設是 N, 8, 1
    try:
        ser = serial.Serial(
            port=SERIAL_PORT,
            baudrate=BAUDRATE,
            parity=serial.PARITY_NONE,
            stopbits=serial.STOPBITS_ONE,
            bytesize=serial.EIGHTBITS,
            timeout=TIMEOUT
        )
        
        # 確保連接是開啟的
        if not ser.isOpen():
            ser.open()

        print("串列埠開啟成功。")
        print(f"準備發送數據包 ({len(PACKET_TO_SEND)} bytes):")
        print(f"十六進制:{PACKET_TO_SEND.hex().upper()}")
        
        # --- 發送數據 ---
        bytes_written = ser.write(PACKET_TO_SEND)
        ser.flush() # 確保數據立即發送

        print(f"成功寫入 {bytes_written} 個位元組。")

        # --- 嘗試讀取回覆 (Status Packet) ---
        # 由於 DYNAMIXEL 會回覆一個狀態包 (Status Packet),我們嘗試讀取它。
        # Status Packet 的長度不固定,但通常約為 14-16 bytes 左右。
        print("\n等待 DYNAMIXEL 回覆 (Status Packet)...")
        time.sleep(0.01) # 短暫延遲,等待馬達處理和回覆
        
        response = ser.read(30) # 嘗試讀取最多 30 個位元組的回覆
        
        if response:
            print(f"收到回覆 ({len(response)} bytes):")
            print(f"十六進制:{response.hex().upper()}")
        else:
            print("未收到任何回覆 (逾時)。")
            
        # --- 關閉串列埠 ---
        ser.close()
        print("\n串列埠已關閉。")

    except serial.SerialException as e:
        print(f"\n錯誤:無法存取或配置串列埠 {SERIAL_PORT}。")
        print("請確認以下事項:")
        print(f"* 1. 串列轉接器已連接到 {SERIAL_PORT}。")
        print(f"* 2. 您有足夠的權限 (可能需要 'sudo' 或將使用者加入 'dialout' 群組)。")
        print(f"* 3. 埠號 ({SERIAL_PORT}) 是否正確。")
        print(f"詳細錯誤訊息: {e}")
    except Exception as e:
        print(f"發生一般錯誤: {e}")

# 執行函式
if __name__ == "__main__":
    send_dynamixel_packet()

📋 執行注意事項

  1. 使用者權限: 在 Linux 系統中,存取 /dev/ttyUSB0 通常需要特定的權限。如果遇到 Permission denied 錯誤,您可能需要使用 sudo 執行腳本,或者將您的使用者帳號添加到 dialout 群組:

    Bash
    sudo usermod -a -G dialout $USER
    # 之後需要登出並重新登入才能生效
    
  2. 埠號: 確保您的 USB-to-UART 轉接器或 U2D2 連接到電腦時確實被識別為 /dev/ttyUSB0。如果不是,請修改程式碼中的 SERIAL_PORT 變數。

  3. DYNAMIXEL 連接: DYNAMIXEL 馬達必須正確連接到 UART 轉接器上,且電源開啟,才能收到回覆。

沒有留言:

張貼留言