ควบคุมเซอร์โวมอเตอร์ ด้วย 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 เซอร์โวมอเตอร์


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



ควบคุมเซอร์โวมอเตอร์ ด้วย OpenCV Python


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 ’


5 : ผลลัพธ์การทำงาน