เดโม & ตัวอย่างใช้งานจริง
เดโม Pick & Place แบบเต็มขั้นตอน 2 รูปแบบ (Gripper และ Vacuum Pump) ที่ผู้ใช้สามารถ copy-paste ไปรันได้ทันที พร้อมคำอธิบายแต่ละบรรทัด อ้างอิงจาก "Successful Cases" ของ Elephant Robotics
13.1 ภาพรวมเดโม
ในบทนี้มีเดโม 2 แบบ:
Demo 1: Gripper ขนบล็อก
ใช้ Adaptive Gripper หยิบบล็อกไม้จากจุด A ไปวางที่จุด B
Demo 2: Vacuum Pump ขนบล็อก
ใช้ปั๊มสุญญากาศดูดบล็อกไม้จากจุด A ไปวางที่จุด B
ทั้ง 2 เดโมใช้พิกัดเดียวกัน เปลี่ยนแค่วิธีจับ ทำให้เปรียบเทียบได้ง่าย
Flow ของ Pick & Place โครงสร้างเหมือนกันทั้ง 2 demos
การเข้าจุดจับ 2 step (เหนือก่อน ลงตรงๆ) ปลอดภัยกว่าเข้าตรง:
- ถ้ามีของกีดขวาง แขนชนน้อย
- การลงตรงๆ คุม linear motion ง่ายกว่าโค้งเข้า
- ใช้แนวคิดเดียวกับ industrial robot ของจริง
ต้องการเรียนรู้ฉบับเต็ม บท 8.3 motion control + Cheatsheet Motion
13.2 การเตรียม
อุปกรณ์ที่ต้องใช้
- myCobot 280 JN พร้อมเปิดเครื่องและทดสอบ Login แล้ว (ดู บทที่ 4)
- End-Effector Gripper สำหรับ Demo 1, Vacuum Pump สำหรับ Demo 2
- บล็อกไม้/พลาสติก ขนาดประมาณ 2×2 ซม. น้ำหนัก <150 กรัม
- โต๊ะทำงานที่มีพื้นที่ราบ ไม่มีสิ่งกีดขวาง
การสอนตำแหน่ง (Teach Points) ด้วย myBlockly
ก่อนรันสคริปต์ ต้องรู้พิกัดของ จุดหยิบ และ จุดวาง ในโลกจริง วิธีหา:
- เปิด myBlockly และ Connect กับหุ่นยนต์
- คลิก Free Mode (จะปลด servo เพื่อขยับด้วยมือ)
- ขยับแขนด้วยมือไปที่ จุดหยิบ (Grab Point)
- คลิก Get Coords จะเห็นค่า [X, Y, Z, Rx, Ry, Rz]
- บันทึกค่าเหล่านี้ลงในตัวแปร
grab_pointในสคริปต์ - ทำซ้ำสำหรับ จุดวาง (Place Point) บันทึกใน
place_point - ปิด myBlockly ก่อนรัน Python ไม่งั้นพอร์ตจะชน
หลัง Free Mode อย่าลืม Focus Servo กลับ ไม่งั้นแขนจะตกลงเมื่อปล่อยมือ และ ต้องปิด myBlockly ก่อนรัน Python ใช้พอร์ตเดียวกันไม่ได้
13.3 Demo 1: Gripper ขนบล็อก
13.3.1 ทดสอบ Gripper ก่อน
ก่อนรันโปรแกรมเต็ม ทดสอบเปิด/ปิด Gripper ก่อน:
python test_gripper.pyfrom pymycobot import MyCobot280
import time
arm = MyCobot280("/dev/ttyTHS1", 1000000)
for i in range(2):
arm.set_gripper_state(1, 100) # ปิด
time.sleep(1)
arm.set_gripper_state(0, 100) # เปิด
time.sleep(1)
หาก Gripper เปิด-ปิดได้ปกติ ผ่าน ไปขั้นถัดไป
13.3.2 โปรแกรม Pick & Place เต็ม
python gripper_pick_place.pyfrom pymycobot import MyCobot280
import time
# ----------- ตัวแปร (ปรับค่าตามจุดที่สอน) -----------
init_angles = [18.36, 6.5, -124.45, 26.54, -1.84, -110.47]
# พิกัด [X, Y, Z, Rx, Ry, Rz]
grab_point = [158.4, -66.9, 77.9, 179.01, 0.88, 52.41]
place_point = [158.4, 36.9, 77.9, 179.01, 0.88, 52.41]
# ความสูงปลอดภัยที่ลอยเหนือวัตถุ
SAFE_HEIGHT = 70 # มิลลิเมตร
# ----------- เริ่มต้น -----------
arm = MyCobot280("/dev/ttyTHS1", 1000000)
def lift_above(point):
"""ลอยเหนือ point เป็นระยะ SAFE_HEIGHT"""
return [point[0], point[1], point[2] + SAFE_HEIGHT,
point[3], point[4], point[5]]
if __name__ == "__main__":
# 1) เปิด Gripper เตรียมพร้อม
arm.set_gripper_state(0, 100)
time.sleep(1)
# 2) ไป Home
arm.send_angles(init_angles, 100)
time.sleep(2)
# 3) ลอยเหนือจุดหยิบ
arm.send_coords(lift_above(grab_point), 100, 1)
time.sleep(2)
# 4) ลงไปที่จุดหยิบ
arm.send_coords(grab_point, 100, 1)
time.sleep(2)
# 5) ปิด Gripper หยิบของ
arm.set_gripper_state(1, 100)
time.sleep(1)
# 6) ยกขึ้น
arm.send_coords(lift_above(grab_point), 100, 1)
time.sleep(2)
# 7) ย้ายไปลอยเหนือจุดวาง
arm.send_coords(lift_above(place_point), 100, 1)
time.sleep(2)
# 8) ลงไปที่จุดวาง
arm.send_coords(place_point, 100, 1)
time.sleep(2)
# 9) เปิด Gripper ปล่อยของ
arm.set_gripper_state(0, 100)
time.sleep(1)
# 10) ยกขึ้นกลับเป็นท่าจบ
arm.send_coords(lift_above(place_point), 100, 1)
time.sleep(2)
print("✓ Demo completed.")
คำอธิบายขั้นตอน
- เปิด Gripper เผื่อยังคาของไว้จากครั้งก่อน
- กลับท่า Home เพื่อเริ่มต้นจากตำแหน่งที่รู้
- เคลื่อนไปลอย เหนือ จุดหยิบ 70 มม. เพื่อให้ลงตรงตำแหน่ง ไม่ชนของ
- ลงตรงไปที่จุดหยิบ (Z ลด 70 มม.)
- ปิด Gripper หยิบ
- ยกขึ้น (ลอยเหนือ)
- เลื่อนไปเหนือจุดวาง
- ลงตรงไปที่จุดวาง
- เปิด Gripper ปล่อย
- ยกขึ้นกลับ เพื่อพร้อมทำรอบถัดไป
ถ้าหุ่นยนต์หยิบ "เฉียดไป" หรือ "ลึกไป" ปรับ SAFE_HEIGHT หรือ ค่าพิกัด Z ของ grab_point
ทีละ 5 มม. หากเฉียงข้าง ต้องสอนตำแหน่ง (Teach) ใหม่ด้วย myBlockly
13.4 Demo 2: Vacuum Pump ขนบล็อก
13.4.1 การต่อสายปั๊ม
ก่อนรันโค้ด ต้องต่อสายปั๊ม 4 เส้น (GND / 5V / G2 / G5) เข้ากับ GPIO ของ Jetson Nano ตามตาราง หากยังไม่ได้ต่อ ดูภาพประกอบและขั้นตอนเต็ม ๆ ใน บทที่ 3.4.1 การติดตั้งปั๊มสุญญากาศ
| สีสาย | ปั๊ม Pin | Jetson Nano | หน้าที่ |
|---|---|---|---|
| ⚫ ดำ | GND | GND | กราวด์ |
| 🔴 แดง | 5V | 5V | ไฟเลี้ยง |
| 🟡 เหลือง | G2 | BCM 21 (Pin 40) | ปล่อยอากาศ |
| ⚪ ขาว | G5 | BCM 20 (Pin 38) | ดูดอากาศ |
13.4.2 ทดสอบปั๊มก่อน
python test_pump.pyfrom pymycobot import MyCobot280
import time
import Jetson.GPIO as GPIO
arm = MyCobot280("/dev/ttyTHS1", 1000000)
GPIO.setmode(GPIO.BCM)
GPIO.setup(20, GPIO.OUT)
GPIO.setup(21, GPIO.OUT)
def pump_on():
GPIO.output(20, 0) # Logic invert: 0 = ON
time.sleep(0.05)
def pump_off():
GPIO.output(20, 1) # 1 = OFF
time.sleep(0.05)
GPIO.output(21, 0) # เปิดวาล์วปล่อยลม
time.sleep(1)
GPIO.output(21, 1) # ปิดวาล์ว
time.sleep(0.05)
for i in range(2):
pump_on()
time.sleep(2)
pump_off()
time.sleep(2)
GPIO.cleanup()
13.4.3 โปรแกรม Pick & Place เต็ม (ปั๊ม)
python pump_pick_place.pyfrom pymycobot import MyCobot280
import time
import Jetson.GPIO as GPIO
# ----------- ตัวแปร -----------
init_angles = [18.36, 6.5, -124.45, 26.54, -1.84, -110.47]
grab_point = [158.4, -66.9, 77.9, 179.01, 0.88, 52.41]
place_point = [158.4, 36.9, 77.9, 179.01, 0.88, 52.41]
SAFE_HEIGHT = 70
# ----------- Setup -----------
arm = MyCobot280("/dev/ttyTHS1", 1000000)
GPIO.setmode(GPIO.BCM)
GPIO.setup(20, GPIO.OUT)
GPIO.setup(21, GPIO.OUT)
def pump_on():
GPIO.output(20, 0)
time.sleep(0.05)
def pump_off():
GPIO.output(20, 1)
time.sleep(0.05)
GPIO.output(21, 0)
time.sleep(1)
GPIO.output(21, 1)
time.sleep(0.05)
def lift_above(p):
return [p[0], p[1], p[2] + SAFE_HEIGHT, p[3], p[4], p[5]]
# ----------- Main -----------
if __name__ == "__main__":
try:
pump_off() # เริ่มต้นปั๊มปิด
time.sleep(1)
arm.send_angles(init_angles, 100)
time.sleep(2)
arm.send_coords(lift_above(grab_point), 100, 1)
time.sleep(2)
arm.send_coords(grab_point, 100, 1)
time.sleep(2)
pump_on() # ดูดวัตถุ
time.sleep(1)
arm.send_coords(lift_above(grab_point), 100, 1)
time.sleep(2)
arm.send_coords(lift_above(place_point), 100, 1)
time.sleep(2)
arm.send_coords(place_point, 100, 1)
time.sleep(2)
pump_off() # ปล่อยวัตถุ
time.sleep(1)
arm.send_coords(lift_above(place_point), 100, 1)
time.sleep(2)
print("✓ Demo completed.")
finally:
GPIO.cleanup()
สังเกตว่า GPIO.output(20, 0) = ON และ 1 = OFF
เป็น Logic Invert ที่ใช้กับวงจรของปั๊มรุ่นนี้
ถ้าใช้กับวงจรอื่นต้องตรวจสอบเสมอ
13.5 ปรับให้เข้ากับงานของคุณ
เดโมนี้เป็นตัวอย่างพื้นฐานที่สุด ขั้นต่อไปคือเอาไปต่อกับ Vision:
- ใช้ AIKit + Color Detection แทนการระบุพิกัด
grab_pointตายตัว ใช้กล้อง 3D หาวัตถุสีแดง/น้ำเงิน แล้วคำนวณพิกัดส่งให้แขน ดู บทที่ 5 - ใช้ YOLOv8 ตรวจจับวัตถุในชีวิตประจำวัน (แก้ว, ขวด) แล้วสั่งหยิบแบบเลือก class
- ลูปทำซ้ำ เพิ่ม
for i in range(10):รอบโค้ดหลัก ทำให้เป็นสายการผลิตจำลอง - หลายจุด กำหนด
grab_pointsและplace_pointsเป็น list หลายจุด สลับหยิบไป-มาเป็นแพทเทิร์น
13.6 เคล็ดลับการดีบัก
- หุ่นยนต์เคลื่อนไม่ตรง เช็คว่ารัน Calibrate แล้วหรือยัง
- เคลื่อนช้าเกินไป เปลี่ยน speed จาก 100 เป็น 80 ลดจังหวะ sleep
- เคลื่อนเร็วเกิน ของล้ม ลด speed ลงเป็น 30-50
- ปั๊ม/Gripper ไม่จับ ตรวจสายไฟ + พื้นผิว ดู A.3
- เกิน Joint Limit แสดง Error 1-6 ปรับ Home angles ใหม่
เพิ่ม mc.set_color(R, G, B) ในแต่ละขั้น
ทำให้เห็นว่าโค้ดถึงจุดไหน เช่น เขียว=กำลังเคลื่อน, แดง=หยิบเสร็จ, น้ำเงิน=วางเสร็จ
13.7 เดโมขั้นสูง: เชื่อม PLC ผ่าน IO
สำหรับ Industrial use case สามารถให้ PLC ส่งสัญญาณมาให้หุ่นยนต์ทำงาน ได้ผ่าน IO ของฐาน เช่น สัญญาณ trigger จาก sensor บนสายการผลิต แล้วหุ่นยนต์รับและตอบสนอง
PLC มาตรฐานอุตสาหกรรมใช้ 24V logic แต่ GPIO ของ Jetson Nano ใช้ 3.3V ต้องใช้ relay circuit หรือ optocoupler ระหว่างกลาง ห้ามต่อตรง เพราะ 24V จะทำลาย GPIO ทันที
Flow ทั่วไป
- PLC ส่งสัญญาณ 24V relay ลด level เป็น 3.3V เข้า GPIO input ของ Jetson
- Python อ่าน GPIO ใน loop, รอ rising edge
- เมื่อตรวจจับ สั่งหุ่นยนต์ทำงาน (เช่น กลับ Home, หยิบของ, ฯลฯ)
- เมื่อเสร็จ ส่งสัญญาณกลับ PLC ผ่าน GPIO output relay 24V output
from pymycobot import MyCobot280
import Jetson.GPIO as GPIO
import time
mc = MyCobot280('/dev/ttyTHS1', 1000000)
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.IN) # input จาก PLC (ผ่าน relay)
GPIO.setup(18, GPIO.OUT) # output ไป PLC (ผ่าน relay)
print("รอสัญญาณจาก PLC...")
while True:
if GPIO.input(17) == GPIO.HIGH:
print("→ PLC trigger! เริ่ม sequence")
mc.send_angles([0, 0, 0, 0, 0, 0], 50)
time.sleep(3)
GPIO.output(18, GPIO.HIGH) # บอก PLC ว่าทำเสร็จ
time.sleep(0.5)
GPIO.output(18, GPIO.LOW)
time.sleep(0.05) # debounce
ดูรายละเอียดเพิ่มเติม + วงจร relay ที่ Successful Cases PLC IO Interactive Control
13.8 เดโมเพิ่มเติม
เดโมอื่น ๆ ที่ Elephant Robotics จัดเตรียมไว้: