กลับไปหน้ารวมไฟล์
arduino-esp32-crawler-powered-by-can-1d47c9.md

Arduino ESP32 Crawler ที่ขับเคลื่อนด้วย CAN

รถ Crawler/Tank ที่ใช้ Arduino เป็นพื้นฐาน!? เราไม่เคยเห็นสิ่งเหล่านี้มานับไม่ถ้วนแล้วหรือ? อาจจะใช่ แต่ไม่ใช่ในรูปแบบนี้ โฟกัสหลักไม่ได้อยู่ที่ตัว Crawler มากเท่ากับการสื่อสารระหว่าง Electronic Control Units (ECUs) โดยอิงตาม Controller Area Network (CAN) ที่ใช้ในรถยนต์สมัยใหม่

UPDATES:

  • อัปเดต Implementation สำหรับทั้งสอง boards
  • มีการแก้ไขหลายจุดเพื่อเพิ่มความเสถียรสำหรับ I2C และ TOF (ใช้เวลาพอสมควร)
  • ลดความถี่ CPU ของ D-duino32 จาก 240 เป็น 160 MHz (ลดการปล่อยความร้อนและที่สำคัญกว่าคือการใช้พลังงาน เพื่อลดภาระของแหล่งจ่ายไฟ)
  • บทเรียน A: อย่าพยายามอ่านค่าจาก TOF sensor บ่อยกว่าทุก 50ms (แก้ไขปัญหาการค้าง)
  • บทเรียน B: อย่าอ่านค่าจากอุปกรณ์ I2C เร็วเกินไป (แก้ไขปัญหาความไม่เสถียรด้วยการหน่วงเวลา 10ms)
  • รวม ESP32-CAM พร้อมอุปกรณ์พับได้ (เป็นลูกเล่นมากกว่าฟีเจอร์ มันใช้ไฟเลี้ยง 5V ร่วมกับ DC regulator เท่านั้น แต่ไม่ได้เชื่อมต่อกับ CAN)
  • บทเรียน C: หากวิดีโอของ ESP32-CAM มีปัญหา ให้ตรวจสอบว่ามีการจ่ายไฟเพียงพอหรือไม่ (ไฟ 5V บนบอร์ดจาก Wemos D1 R32 ไม่เพียงพอ)
ESP32 Crawler พร้อมกล้องด้านหน้าและ CAN transceivers ใต้ Chassis

แน่นอนว่า ก่อนอื่นเราต้องมีพาหนะ - การยุ่งเกี่ยวกับ CAN ในรถยนต์จริงไม่ใช่ความคิดที่ดี - และอะไหล่บางส่วนจากกล่องเก็บของผม ผมเลือก Chassis แบบมีสายพานพร้อมมอเตอร์ 2 ตัวจาก DOIT (T101 mini), Wemos D1 R32, D-duino32 พร้อม OLED บนบอร์ด, Motor Shield จาก Adafruit, TOF sensor (VL53L0X) สำหรับการวัดระยะทาง, IMU (MPU9250) สำหรับการตรวจจับการเอียง, กล่องแบตเตอรี่, สกรูและน็อต, สายจัมเปอร์ และสุดท้ายแต่ไม่ท้ายสุดคือ CAN transceivers สองตัว (SN65HVD230) หลังจากนั้นไม่นาน ทุกอย่างก็ถูกประกอบเข้าด้วยกัน งั้นมาดูกันว่าผลลัพธ์จากกิจกรรมยามว่างนี้เป็นอย่างไร...

แล้วเรื่องการสื่อสาร CAN ล่ะ? ก่อนที่เราจะเจาะลึก ผมขอให้ภาพรวมเกี่ยวกับการเดินสายที่ใช้สำหรับการสร้างนี้ โฟกัสหลักอยู่ที่การเชื่อมต่อแบบ High-Speed (HS) CAN - โดยที่คำว่า "high-speed" บอกเราเกี่ยวกับพฤติกรรมทางไฟฟ้ามากกว่า Baudrate ตัว ESP32 มี integrated HS CAN controller ดังนั้นเราจึงเพียงแค่ต้องต่อ CAN transceiver ที่เข้ากันบน MCU ทั้งสองตัว เปรียบเทียบได้ที่ นี่.

การเดินสายพร้อมโมดูลกล้องเสริม

SN65HVD230 transceivers ที่ใช้จำเป็นต้องใช้ไฟเลี้ยง 3.3V และใช้ระดับสัญญาณเดียวกัน พวกมันจะถูกเชื่อมต่อจาก CRX และ CTX ไปยัง GPIOs ของ MCUs (ไม่มีการไขว้สาย) หลังจากนั้นทั้งสองตัวจะเชื่อมต่อถึงกันผ่าน CANH และ CANL (ไม่มีการไขว้สาย) Motor Shield, TOF/IMU sensor เชื่อมต่อกับ D1 R32 ด้วย I2C (SDA & SCL) กล่องแบตเตอรี่และมอเตอร์เชื่อมต่อกับ Shield และสุดท้าย D-duino32 ได้รับพลังงานจาก DC regulator (AMS1117-5.0V) ผมลองใช้ V5 & GND จาก D1 R32 แต่ประสบปัญหาพฤติกรรมแปลกๆ มากมาย (โดยเฉพาะเรื่องการสื่อสาร CAN) หลังจากจ่ายไฟแบตเตอรี่โดยตรงให้กับ D-duino32 ด้วยความช่วยเหลือของ Regulator ปัญหาก็หายไป ผมเดาว่า Voltage Regulator ของ D1 R32 ไม่เพียงพอที่จะขับเคลื่อน Shield, Sensors และ D-duino32 พร้อมกัน

การสื่อสารผ่าน CAN ระหว่าง ECUs เกิดขึ้นโดยใช้ Frames ในที่นี้ ผมใช้ Standard Format ซึ่งใช้ Payload สูงสุด 8 Bytes ต่อหนึ่งข้อความ หากคุณสนใจว่า Bus Arbitration ต่อ ECU จัดการอย่างไร และ Frame Format ทั้งหมดมีลักษณะอย่างไร โปรดดูที่ นี่ ข้อความ (หรือ Frames) จะถูกแยกแยะด้วย IDs ที่ไม่ซ้ำกันทั่วทั้งเครือข่าย ID นี้ยังเทียบเท่ากับ Priority (ID ที่มีค่าน้อยกว่าจะมี Priority สูงกว่าในกรณีที่มี Arbitration พร้อมกัน) ดังนั้นการสร้าง Message Catalog จึงต้องพิจารณาถึงลำดับของ IDs ด้วย ไม่ใช่แค่ Payload เท่านั้น

CAN messages ระหว่าง Nodes ทั้งสอง

ในโปรเจกต์นี้ IDs 0x10, 0x11 และ 0x12 ใช้เพื่อถ่ายโอนข้อมูลจาก PS4 controller ที่เชื่อมต่อกับ D-duino32 ผ่าน CAN ไปยัง D1 R32 ซึ่งจะคำนวณการบังคับเลี้ยว/คันเร่ง และสุดท้ายคือความเร็วมอเตอร์ซ้ายและขวาจากข้อมูลดังกล่าว ในทางกลับกัน D1 R32 จะส่งข้อความที่มี ID 0x20 ซึ่งประกอบด้วยสถานะของระบบช่วยด้านหน้า (การเบรกอัตโนมัติโดยอิงจากระยะทางด้านหน้าที่เก็บรวบรวมโดย TOF sensor) สถานะของระบบเตือนการเอียง (Pitch และ/หรือ Roll > 45° ที่รวบรวมโดย IMU) ข้อมูลสถานะจะแสดงบน OLED และใช้เพื่อควบคุม PS4 LED และฟังก์ชันสั่นเพื่อการตอบสนองโดยตรงต่อ "ผู้ขับขี่"

void task_txCAN(void * pvParameters) {
for(;;) {
CAN_frame_t tx_frame;
int d = distance;
tx_frame.FIR.B.FF==CAN_frame_std;
tx_frame.MsgID = 0x20;
tx_frame.FIR.B.DLC = 8;
tx_frame.data.u8[0] = byte(auto_break);
tx_frame.data.u8[1] = byte(break_active);
tx_frame.data.u8[2] = byte(tilt_warn);
tx_frame.data.u8[3] = 0;
tx_frame.data.u8[4] = byte(d>>(3*8));
tx_frame.data.u8[5] = byte(d<<(1*8)>>(3*8));
tx_frame.data.u8[6] = byte(d<<(2*8)>>(3*8));
tx_frame.data.u8[7] = byte(d<<(3*8)>>(3*8));
ESP32Can.CANWriteFrame(&tx_frame);
delay(50);
}
}

บ่อยครั้งที่ข้อมูลจำเป็นต้องถูกแปลงเพื่อถ่ายโอนเป็น Bytes ใน Frame ซึ่งสามารถทำได้โดยการแปลง Bool เป็น Bit (หากไม่มีข้อจำกัด ก็สามารถใช้ Byte ได้) ต้องระมัดระวังมากขึ้นสำหรับ Data Type อื่นๆ และโดยเฉพาะอย่างยิ่งว่า Data Type เหล่านั้นถูกแสดงบน MCU แต่ละชนิดอย่างไร ตัวอย่างเช่น Arduino Uno ใช้ 2 Bytes สำหรับ Integer (16-bit) แต่ ESP32 ใช้ 4 Bytes (32-bit) การดูแลเป็นพิเศษเป็นสิ่งจำเป็นหากมีการผสมผสานสถาปัตยกรรม MCU ที่แตกต่างกันในเครือข่าย และวิธีการแสดง Data Type สำหรับแต่ละตัว ดังนั้นจึงเป็นสิ่งสำคัญที่จะต้องทราบว่า Message Catalog มีลักษณะอย่างไรและควรจัดการกฎการนำเสนอสำหรับ Payload อย่างไร

เชื่อมต่อ Arduino Due สำหรับการ Monitoring

สำหรับการวิเคราะห์/Monitoring Traffic ระหว่าง D1 R32 และ D-Duino32 ผมใช้ Arduino Due ซึ่งมี Integrated CAN controller เช่นกัน Due - แตกต่างจาก ESP32 - รองรับไม่เพียงแค่หนึ่ง แต่สอง Channels ทำให้คุณสามารถเชื่อมต่อ Transceivers สองตัวและเช่น รับฟัง Traffic ของ CAN Network Segments ที่แตกต่างกันสองชุด มีประโยชน์มากหากจำเป็นต้องวิเคราะห์ Gateway แต่ไม่จำเป็นสำหรับโปรเจกต์นี้ ในที่นี้มีเพียง Segment เดียวที่เชื่อมต่อระหว่าง MCUs สองตัวที่เราต้องการ Transceiver ของ Due สามารถเชื่อมต่อกับ CANH และ CANL เข้ากับการเดินสายที่มีอยู่ได้โดยง่าย เนื่องจาก CAN เป็น Bus และไม่ใช่การเชื่อมต่อแบบ Point-to-Point

Log ของ Traffic ระหว่างทั้งสอง

ข้อมูล Frontmatter ดั้งเดิม

title: "Arduino ESP32 Crawler Powered by CAN"
description: "A simple Arduino/ESP32 crawler with PS4 BT remote control, but with 2x MCU and an advanced CAN-based communication (\"drive-by-wire\")."
author: "srolf"
category: "Motors & Robotics"
tags:
  - "rover"
  - "robot"
  - "can"
  - "cars"
  - "esp"
  - "remote control"
views: 14265
likes: 3
price: 2450
difficulty: "Intermediate"
components:
  - "1x SparkFun IMU Breakout - MPU-9250"
  - "1x Multitool, Screwdriver"
  - "1x Solder Wire, Lead Free"
  - "1x DOIT T101 Mini"
  - "2x SN65HVD230"
  - "1x Drill / Driver, Cordless"
  - "1x Wemos D1 R32"
  - "1x SN65HVD230"
  - "1x AMS1117 5.0V"
  - "1x Jumper wires (generic)"
  - "1x ProtoCentral VL53L0X Laser ToF Sensor breakout board"
  - "1x Soldering iron (generic)"
  - "1x Arduino Due"
  - "1x Adafruit Motor Shield v2.3"
  - "1x D-duino32"
  - "5x Female Header 8 Position 1 Row (0.1\")"
  - "1x Male Header 40 Position 1 Row (0.1\")"
tools: []
apps:
  - "1x Arduino IDE"
  - "1x PuTTY"
downloadableFiles:
  - "https://projects.arduinocontent.cc/7c48c265-6235-44f9-b645-3e64aea723e2.ino"
  - "https://projects.arduinocontent.cc/7c48c265-6235-44f9-b645-3e64aea723e2.ino"
  - "https://projects.arduinocontent.cc/0001813d-bc1a-4bb3-b153-d7cf9fc312a3.ino"
documentationLinks: []
passwordHash: "71942b53e8d8a6f7775ce2643d27e2b3eb4eca86d9be82f4c1840be248fb8881"
encryptedPayload: "U2FsdGVkX1+K2Myurj0KYrrkszViSkuFMy46w07ywsipT8HF/+oXLoFT1iePyW4/PqVicAaKC+EOcAObsnrIa9JeRQsAI9W7oJWyxtaIN8I="
seoDescription: "Arduino ESP32 Crawler project featuring PS4 BT control, dual MCU, and advanced CAN-based \\\\\\\"drive-by-wire\\\\\\\" communication system."
videoLinks: []
heroImage: "https://cdn.jsdelivr.net/gh/bigboxthailand/arduino-assets@main/images/projects/arduino-esp32-crawler-powered-by-can-1d47c9_cover.jpg"
lang: "th"