ควบคุมเซอร์โวมอเตอร์ ด้วย OpenCV Python
เซอร์โวมอเตอร์ (Servo Motor) เป็นการรวมมอเตอร์ไฟฟ้ากระแสตรง (DC Motor) เข้ากับวงจรควบคุม โดยความแตกต่างที่สำคัญของเซอร์โวมอเตอร์กับมอเตอร์แบบอื่น ๆ คือเซอร์โวมอเตอร์จะรู้ตำแหน่งที่ตัวเองอยู่ และสั่งเปลี่ยนตำแหน่งโดยการเปลี่ยนองศาได้ นิยมใช้งานในเครื่องบินบังคับ เรือบังคับ โดยใช้กำหนดทิศทางของหางเสือเป็นองศา
การทํางานเพียงตัว เซอร์โวมอเตอร์ เพียงอย่างเดียวนั้นไม่สามารถทํางานได้ การที่จะให้ เซอร์โวมอเตอร์ จะควบคุมลักษณะที่กล่าวมาข้างต้นนั้นต้องมี ไมโครคอนโทรลเลอร์ มีหน้าที่รับคําสั่งจากผู้ใช้งานว่าต้องการให้ เซอร์โวมอเตอร์ นั้นเคลื่อนที่ด้วยความเร็วเท่าไหร่และระยะทาง ใกล้หรือไกลแค่ไหน หน้าที่ตรงจุดนี้จะเป็น ไมโครคอนโทรลเลอร์ Ardoino จะเป็นตัวกําหนดให้กับตัว เซอร์โวมอเตอร์
แต่ในบทความนี้ จะควบคุม เซอร์โวมอเตอร์ ด้วยวัตถุ ในที่นี้คือ ลูกเทนนิส สีเขียว ผ่านทาง OpenCV ภาษา Python โดยเมื่อ วัตถุ เคลื่อนที่ผ่านหน้ากล้อง Webcam ขนาดภาพ 640×480 โดยจะส่งค่าแกน x ไปยัง Ardoino UNO เพื่อไปควมคุม เซอร์โวมอเตอร์ ให้หมุน 0-180 องศา
ในบทความนี้เลือกใช้ MG996R ซึ่งเป็นเซอร์โวมอเตอร์ เฟืองทดเป็นแบบโลหะ หมุนได้ 0-180 องศา ให้แรงบิดสูงถึง 15 kg ใช้ไฟเลี้ยง 4.8V – 7.2V

MG996R มี 3 สาย คือ 1. สายสีแดง ต่อเข้ากับไฟเลี้ยง 4.8V – 7.2V 2. สายสีน้ำตาลต่อเข้า กับ GND 3. สายสีส้ม ต่อเข้ากับ สัญญาณควบคุม DC ในตัวอย่างจะเป็นขา 9 ของ Arduino UNO
รายการอุปกรณ์
ขั้นตอนการทํางาน
1 : เขียน Python ควบคุม Arduino ด้วย pySerial
Python มีการใช้กันอย่างแพร่หลายในด้านการศึกษาและการเรียนรู้ Machine Learning และความสามารถ หลายๆอย่าง เช่น คุณสามารถใช้ควบคุมบอร์ด Arduino. ใช่แน่นอนคุณสามารถใช้ภาษาการเขียนโปรแกรม Python เพื่อสร้างโปรแกรมของคุณเพื่อควบคุม Arduino ได้โดยไม่มีปัญหาและด้วยวิธีง่ายๆ เราจะมาอธิบายวิธีการทำทีละขั้นตอน
2 : เชื่อมต่อ เซอร์โวมอเตอร์ กับ Arduino Keyestudio


3 : อัพโหลดโค้ด เพื่อรอคำสั่งจาก Python
อัพโหลดโค้ด ด้านล่างไปยังบอร์ด Arduino UNO R3 รุ่น Keyestudio PLUS
#include <Servo.h>
Servo myservo;
int val;
void setup() {
Serial.begin(9600);
myservo.attach(9);
}
void loop() {
String readString;
String Q;
while (Serial.available()) {
delay(1);
if (Serial.available() > 0) {
char c = Serial.read();
if (isControl(c)) {
break;
}
readString += c;
}
Q = readString;
int X = Q.toInt();
val = map(X, 0, 640, 0, 180);
myservo.write(val);
}
}

4 : เขียนโค้ด ควบคุมเซอร์โวมอเตอร์ ด้วย OpenCV Python
ไปที่โปรแกรม PyCharm สร้างไฟล์ Python โดยคลิกขวาที่โฟลเดอร์ venv -> New -> Python File

ตั้งชื่อไฟล์ ในตัวอย่างเป็น servo-opencv -> Enter

เขียนโค้ดดังนี้
import cv2
import imutils
import time
import serial
ser = serial.Serial("COM3", 9600)
greenLower = (29, 86, 6)
greenUpper = (64, 255, 255)
vs = cv2.VideoCapture(0)
time.sleep(2.0)
while True:
_, frame = vs.read()
if frame is None:
break
blurred = cv2.GaussianBlur(frame, (11, 11), 0)
width, height = frame.shape[:2]
hsv = cv2.cvtColor(blurred, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, greenLower, greenUpper)
mask = cv2.erode(mask, None, iterations=2)
mask = cv2.dilate(mask, None, iterations=2)
cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
center = None
if len(cnts) > 0:
c = max(cnts, key=cv2.contourArea)
((x, y), radius) = cv2.minEnclosingCircle(c)
M = cv2.moments(c)
center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))
# To see the centroid clearly
if radius > 10:
cv2.circle(frame, (int(x), int(y)), int(radius), (0, 255, 255), 5)
input_value = str(int(x))
print(input_value)
ser.write(input_value.encode())
cv2.imwrite("circled_frame.png", cv2.resize(frame, (int(height / 2), int(width / 2))))
cv2.circle(frame, center, 5, (0, 0, 255), -1)
cv2.imshow("Frame", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
vs.release()
cv2.destroyAllWindows()
ทดสอบการทำงานโดย คลิกขวา ในพื้นที่การเขียนโค้ด -> Run ‘ servo-opencv ’

เคยใช้delphi3.0เขียนเมื่อ 23ปีที่แล้ว ทำให้หุ่นยนต์ ไปเตะลูกปิงปองเข้าโกล์ เขียนเป็นหมื่นบรรทัดเลยคับ ใช้ timage.canvas.pixel[] มาอ่านค่าสีทีละblockเล็กๆ แล้วไปเข้าสูตร สถิติ ถ้าใกล้เคียงกับตัวอย่างที่เคยเก็บสี ก็จะให้มันจำ แล้วไปค้นหาในภาพจากกล้อง ตอนนั้น สนุกมากๆ กล้องยังใช้webcam กากๆอยู่เลย ภาพได้แค่ 480*320