Nawal DuaPatrick HeithoffEdward Yeap Wen FongSean Maloney
Published © GPL3+

UW-Makeathon: Darts

We made a device that tracks an object and prepositions itself based on the object's location in real time.

AdvancedShowcase (no instructions)Over 1 day1,219
UW-Makeathon: Darts

Things used in this project

Hardware components

Arduino UNO
Arduino UNO
×1
DC motor (generic)
×2
9V battery (generic)
9V battery (generic)
×4
Relay Module (Generic)
×2
Jumper wires (generic)
Jumper wires (generic)
×14

Software apps and online services

OpenCV
OpenCV
Arduino IDE
Arduino IDE

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)
Drill Taps
OpenBuilds Drill Taps
Band Saw
Laser cutter (generic)
Laser cutter (generic)

Story

Read more

Custom parts and enclosures

Pulley

This is the CAD file for the design of the pulley. The pulley is used to move the rods up, down, left and right on the frame.

Schematics

Schematic Motor Wiring

This is the basic and first schematic we drew for how the motor will be wired. The switches in our diagram actually represent a relay board. There are two switches in the relay board that will be controlled through the microprocessor. One of the batteries is connected in the opposite terminals as the other. This makes it so that when one switch is open and the other is closed, the motor will spin one way, and the other way when the positions of both the switches are reversed.

Schematic sketches of frame

These are rough sketches of different parts of the frame that will hold the whole rig.

Schematic sketches of frame 2

These are rough sketches of different parts of the frame that will hold the whole rig.

Code

Our Code

Python
This is the code to help move the motors.
int relyPinOne = 8;
int relyPinTwo = 12;

int relyPinThree = 13;
int relyPinFour = 11;

int direction_rotate = 0;

void setup() {
  // put your setup code here, to run once:
  pinMode(relyPinOne, OUTPUT);
  pinMode(relyPinTwo, OUTPUT);

  pinMode(relyPinThree, OUTPUT);
  pinMode(relyPinFour, OUTPUT);
  Serial.begin(9600);
  
  digitalWrite(relyPinOne, LOW );
  digitalWrite(relyPinTwo, LOW );
  digitalWrite(relyPinThree, LOW );
  digitalWrite(relyPinFour, LOW );
  
  Serial.println("This is my First Example.");
}

void rotate_motor_one_right(){
   digitalWrite(relyPinTwo, LOW );
   digitalWrite(relyPinOne, LOW );
   digitalWrite(relyPinTwo, HIGH );
}

//Motor One
void rotate_motor_one_left(){
   digitalWrite(relyPinTwo, LOW );
   digitalWrite(relyPinOne, LOW );
   digitalWrite(relyPinOne, HIGH );
}

void rotate_motor_one_stop(){
   digitalWrite(relyPinTwo, LOW );
   digitalWrite(relyPinOne, LOW );
}

//Motor Two
void rotate_motor_two_right(){
   digitalWrite(relyPinThree, LOW );
   digitalWrite(relyPinFour, LOW );
   digitalWrite(relyPinFour, HIGH );
}

void rotate_motor_two_left(){
   digitalWrite(relyPinThree, LOW );
   digitalWrite(relyPinFour, LOW );
   digitalWrite(relyPinThree, HIGH );
}

void rotate_motor_two_stop(){
   digitalWrite(relyPinThree, LOW );
   digitalWrite(relyPinFour, LOW );
}

int delay_b = 40;
void loop() {
  while (Serial.available())
  {
    direction_rotate = Serial.read();
  }

  if (direction_rotate == '1'){
     Serial.println("Right Motor One");
     rotate_motor_one_right();
     delay(delay_b);
     rotate_motor_one_stop();
     direction_rotate = 0;
     
  }

  if (direction_rotate == '2'){
     Serial.println("Left Motor One");
     rotate_motor_one_left();
     delay(delay_b);
     rotate_motor_one_stop();
     direction_rotate = 0;
  }

  if (direction_rotate == '3'){
     Serial.println("Stop Motor One");
     rotate_motor_one_stop();
     direction_rotate = 0;
  }

    if (direction_rotate == '4'){
     Serial.println("Right Motor Two");
     rotate_motor_two_right();
     delay(delay_b);
     rotate_motor_two_stop();
     direction_rotate = 0;
  }

  if (direction_rotate == '5'){
     Serial.println("Left Motor Two");
     rotate_motor_two_left();
     delay(delay_b);
     rotate_motor_two_stop();
     direction_rotate = 0;
  }

  if (direction_rotate == '6'){
     Serial.println("Stop Motor Two");
     rotate_motor_two_stop();
     direction_rotate = 0;
  }
//
//  // put your main code here, to run repeatedly:
//    delay(1000);
//      digitalWrite(relyPinTwo, HIGH );
//      Serial.println("pin two off");
//
//       delay(1000);
//      digitalWrite(relyPinOne, HIGH);
//      Serial.println("Turing off pin one");
//       delay(1000);
//       
//      digitalWrite(relyPinTwo, LOW );
//       delay(1000);
//
//      digitalWrite(relyPinOne, HIGH );
//     Serial.println("pin two off");
//   
//           
//      digitalWrite(relyPinTwo, HIGH );
//       delay(1000);
//
//      digitalWrite(relyPinOne, LOW );

  
      
 
}

Our Code 2

Python
This is the code to help track the object.
#!/usr/bin/env python

'''
Track a green ball using OpenCV.

    Copyright (C) 2015 Conan Zhao and Simon D. Levy

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as 
    published by the Free Software Foundation, either version 3 of the 
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

 You should have received a copy of the GNU Lesser General Public License 
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
'''

import cv2
import numpy as np

# For OpenCV2 image display
WINDOW_NAME = 'GreenBallTracker' 

def track(image):

    '''Accepts BGR image as Numpy array
       Returns: (x,y) coordinates of centroid if found
                (-1,-1) if no centroid was found
                None if user hit ESC
    '''

    # Blur the image to reduce noise
    blur = cv2.GaussianBlur(image, (5,5),0)

    # Convert BGR to HSV
    hsv = cv2.cvtColor(blur, cv2.COLOR_BGR2HSV)

    # Threshold the HSV image for only green colors
    lower_green = np.array([40,70,70])
    upper_green = np.array([80,200,200])

    # Threshold the HSV image to get only green colors
    mask = cv2.inRange(hsv, lower_green, upper_green)
    
    # Blur the mask
    bmask = cv2.GaussianBlur(mask, (5,5),0)

    # Take the moments to get the centroid
    moments = cv2.moments(bmask)
    m00 = moments['m00']
    centroid_x, centroid_y = None, None
    if m00 != 0:
        centroid_x = int(moments['m10']/m00)
        centroid_y = int(moments['m01']/m00)

    # Assume no centroid
    ctr = (-1,-1)

    # Use centroid if it exists
    if centroid_x != None and centroid_y != None:

        ctr = (centroid_x, centroid_y)

        # Put black circle in at centroid in image
        total_y_center = round(image.shape[0]/2)
        total_x_center = round(image.shape[1]/2)
        print(total_y_center, total_x_center)



        cv2.circle(image, ctr, 30, (0,0,0))
        cv2.line(image,(total_x_center,total_y_center),(centroid_x,centroid_y),(0,0,0),5)

    # Display full-color image
    cv2.imshow(WINDOW_NAME, image)

    # Force image display, setting centroid to None on ESC key input
    if cv2.waitKey(1) & 0xFF == 27:
        ctr = None
    
    # Return coordinates of centroid
    print(ctr)
    return ctr

# Test with input from camera
if __name__ == '__main__':

    capture = cv2.VideoCapture(0)

    while True:

        okay, image = capture.read()

        if okay:

            if not track(image):
                break
          
            if cv2.waitKey(1) & 0xFF == 27:
                break

        else:

           print('Capture failed')
           break

Our Code 2 cont.

Python
This is the code to help track the object.
#############

## Modified and used as open source


#!/usr/bin/env python

'''
Track a green ball using OpenCV.

    Copyright (C) 2015 Conan Zhao and Simon D. Levy

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as 
    published by the Free Software Foundation, either version 3 of the 
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

 You should have received a copy of the GNU Lesser General Public License 
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
'''

import cv2
import numpy as np
from time import sleep
import serial


# For OpenCV2 image display
WINDOW_NAME = 'GreenBallTracker' 

def track(image, on_target, count=0):

    # Assume no centroid
    ctr = (-1,-1)
    total_y_center = int(round(image.shape[0]/2))
    total_x_center = int(round(image.shape[1]/2))

    if not count % 10 == 0:
        return ((ctr), (total_x_center,total_y_center))

    '''Accepts BGR image as Numpy array
       Returns: (x,y) coordinates of centroid if found
                (-1,-1) if no centroid was found
                None if user hit ESC
    '''

    # Blur the image to reduce noise
    blur = cv2.GaussianBlur(image, (5,5),0)
    #image = image[200:800, 400:1500]

    # Convert BGR to HSV
    hsv = cv2.cvtColor(blur, cv2.COLOR_BGR2HSV)

    # Threshold the HSV image for only green colors
    lower_green = np.array([40,70,70])
    upper_green = np.array([80,200,200])

    # Threshold the HSV image to get only green colors
    mask = cv2.inRange(hsv, lower_green, upper_green)
    
    # Blur the mask
    bmask = cv2.GaussianBlur(mask, (5,5),0)

    # Take the moments to get the centroid
    moments = cv2.moments(bmask)
    m00 = moments['m00']
    centroid_x, centroid_y = None, None
    if m00 != 0:
        centroid_x = int(moments['m10']/m00)
        centroid_y = int(moments['m01']/m00)



    print(image.shape)
    if on_target:
        cv2.circle(image, (total_x_center,total_y_center), 50, (0,255,0))
    else:
        cv2.circle(image, (total_x_center,total_y_center), 50, (0,0,255))

    # Use centroid if it exists
    if centroid_x != None and centroid_y != None:

        ctr = (centroid_x, centroid_y)

        cv2.circle(image, ctr, 50, (0,0,0))
        print(round(total_x_center),int(round(total_y_center))),(int(round(centroid_x)),int(round(centroid_y)))
        cv2.line(image,(int(round(total_x_center)),int(round(total_y_center))),(int(round(centroid_x)),int(round(centroid_y))),(0,0,0),5)

    # Display full-color image
    cv2.imshow(WINDOW_NAME, image)

    # Force image display, setting centroid to None on ESC key input
    if cv2.waitKey(1) & 0xFF == 27:
        ctr = None
    
    # Return coordinates of centroid
   # print(ctr)
    return (ctr, (total_x_center,total_y_center))
###########



def motor_1_right():
    ser.write('1')
    print ("motor one right")

def motor_1_left():
    ser.write('2')
    print ("motor one left")

def motor_1_off():
    ser.write('3') #send 0
    print ("Motor one OFF")

def motor_2_right():
    ser.write('4')
    print ("motor two right")

def motor_2_left():
    ser.write('5')
    print ("motor two left")

def motor_2_off():
    ser.write('6') #send 0
    print ("Motor two OFF")


ser = serial.Serial('/dev/cu.usbmodem1441', 9600) # Establish the connection on a specific port
sleep(2) 

LIMIT = 5
CENTER = 75
 
# Test with input from camera
if __name__ == '__main__':

    motor_one_left = 0
    motor_one_right = 0
    motor_two_left = 0
    motor_two_right = 0

    capture = cv2.VideoCapture(1)
    on_target = False

    while True:

        okay, image = capture.read()

        if okay:
            corr, center = track(image, on_target)

            if cv2.waitKey(1) & 0xFF == 27:
                break

            print(corr[0], corr[1])

            ##Reset
            motor_1_off()
            motor_2_off()
            if (corr[0] == -1 and corr[1] == -1):
                continue

            ## Within 100px stay still
            if abs(corr[0] - center[0]) < CENTER:
                motor_1_off()
            elif (corr[0] - center[0]) > 0 and motor_1_right <= LIMIT:
                motor_1_right()
                motor_one_right+=1
                motor_one_left-=1
            elif motor_one_left <= LIMIT:
                motor_1_left()
                motor_one_left+=1
                motor_one_right-=1


            if abs(corr[1] - center[1]) < CENTER:
                motor_2_off()
            elif (corr[1] - center[1]) > 0 and motor_two_right <= LIMIT:
                motor_2_right()
                motor_two_right+=1
                motor_two_left-=1
            elif motor_two_left <= LIMIT: 
                motor_2_left()
                motor_two_left+=1
                motor_two_right-=1


            if abs(corr[0] - center[0]) < CENTER and abs(corr[1] - center[1]) < CENTER:
                 on_target = True
            else:
                on_target = False



        else:

           print('Capture failed')
           break

Our Code 2 Cont.2

Python
This is the code to help track the object.
from time import sleep
import serial
ser = serial.Serial('/dev/cu.usbmodem1441', 9600) # Establish the connection on a specific port
sleep(2) 

 
while 1:      #Do this in loop

    var = raw_input() #get input from user
   
    
    if (var == '1'):
        ser.write('1')
        print ("Right motor one right")
    
    if (var == '2'):
        ser.write('2')
        print ("Right motor one left")

    if (var == '3'):
        ser.write('3') #send 0
        print ("Motor one OFF")

     if (var == '4'):
        ser.write('4')
        print ("Right motor two right")
    
    if (var == '5'):
        ser.write('2')
        print ("Right motor two left")

    if (var == '6'):
        ser.write('6') #send 0
        print ("Motor two OFF")

Credits

Nawal Dua
1 project • 0 followers
Patrick Heithoff
0 projects • 0 followers
Edward Yeap Wen Fong
0 projects • 0 followers
Sean Maloney
0 projects • 0 followers
Thanks to Adrian Rosebrock.

Comments