Home Shooting Range at Raspberry

    Hi Habr.
    I love small arms and shooting. However, at home this is a bad hobby. No, well, you can certainly buy a trauma and riddle the apartment, but, I think, the home will not appreciate it. Not wanting to put up with this, I decided to implement my own, moderately safe home shooting range. If interested - welcome to cat.

    Ideas how this can be realized have been in my head for a long time. Here are a few rejected ones:
    - a gun with a phototransistor + a monitor screen. Highlighting half / quarter / one-eighth / etc. screen, check the response from the phototransistor and iteratively specify the part of the screen into which the gun is directed. I rejected the idea because of the low refresh rate of monitors and their inertia.
    - a gun with a phototransistor + a screen of LED matrices. Already better, you can update the image on the diode array with sufficient frequency. I even started soldering diode arrays, but changed my mind in time.
    - a gun with a camera, several laser LEDs forming marks on the wall, by which the camera determines its position. In principle, the idea was not bad. However, having estimated how the pistol with the webcam screwed to it would look, he also refused it.
    Well, the final idea is a static camera looking at the wall and a laser gun. There is an idea, it's up to implementation.
    I bought the first child gun (Desert Eagle caliber 50). I threw out the insides, processed it with a file and installed a laser diode, a trigger button and nano arduinine in it. No, of course you can put a capacitor in place of the arduinine, so that he would switch the button from the power source to the diode and back, but this is not a flexible enough approach. The laser diode glued to cold welding. While it froze, he carefully adjusted the diode on, combining it with the aiming bar.
    Hidden text
    Hidden text

    Wrote the simplest sketch:
    Hidden text
    void setup() {
        pinMode(3, OUTPUT);//LED
        pinMode(2, INPUT);//Button to ground
        digitalWrite(2, true);
    int t = 10000;
    bool PreButton = false;
    void loop() {
        bool Button = !digitalRead(2);
        if (PreButton == false && Button == true && t > 500) t = 0;
        if (t<5) digitalWrite(3, true);
        else digitalWrite(3, false);
        if (t<10000) t++;
        PreButton = Button;

    The gun “shoots” with short pulses of 4ms (picked up during the setup) with a maximum rate of 2 shots per second.
    Next, it is up to the receiver. I bought the simplest webcam. Malinka was already in the bins. I connected the camera, directed it to the wall.
    Hidden text

    Next, you need to put the necessary packages on the raspberry
    sudo apt-get install libv4l-0 libopencv-dev python-opencv

    It remains to write a Python script. This was my first python script, so I had to kill him for almost a day.
    Hidden text
    import sys
    import cv2
    import math
    import subprocess
    if __name__ == '__main__':
        #target in camera
        CenterX = 426.5
        CenterY = 190.5
        Radius = 40.0
        width = 800
        height = 640
        capture = cv2.VideoCapture(0)
        capture.set(3, width);
        capture.set(4, height);
        image = cv2.imread("target.jpg", cv2.CV_LOAD_IMAGE_COLOR)
        target_x = float(image.shape[0])*0.5
        target_y = float(image.shape[1])*0.5
        target_Radius = min(target_x,target_y)
        target = image.copy()
        cv2.namedWindow("Result", 1)
        cv2.imshow("Result", target)
        ShotCount = int();
        Scoore = 0;
        while 1:
            if cv2.waitKey(1) >= 0:
            ret,frame = capture.read()
            grey_image = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
            ret,grey_image = cv2.threshold(grey_image, 245, 255, cv2.THRESH_BINARY)
    #        grey_image = cv2.erode(grey_image, None, iterations = 1)
    #        grey_image = cv2.dilate(grey_image, None, iterations = 1)
            (contour, _) = cv2.findContours(grey_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
            if contour:
                subprocess.Popen('aplay Shot.wav', shell = True)
                cntr = sorted(contour, key = cv2.contourArea, reverse = True)[0]
                (x,y), radius = cv2.minEnclosingCircle(cntr)
                center = (x, y)
                shot_x = (float(x) - CenterX)/Radius
                shot_y = (float(y) - CenterY)/Radius
                dist = math.sqrt(shot_x*shot_x+shot_y*shot_y)
                shot_x = target_x + shot_x*target_Radius
                shot_y = target_y + shot_y*target_Radius
                Shot = (int(shot_x), int(shot_y))
                cv2.circle(target, Shot, 5, (60,60,255),10)
                cv2.circle(target, Shot, 10, (120,120,120),1)
                cv2.imshow("Result", target)
                #print (center, dist)
                print ("Shots", ShotCount+1)
                if dist < 1.0:
                    Scoore += 1 - dist
                ShotCount += 1
                if ShotCount > 6:
                    ShotCount = 0;
                    Scoore = Scoore/7.0*100.0
                    print("You Scoore: ", Scoore)
                    Scoore = 0
                    target = image.copy()
                    subprocess.Popen('aplay 924.wav', shell = True)

    A little explanation. The script takes pictures from the camera and converts them to black and white. Then it cuts off everything that is darker than 245. As practice has shown, the spot of the laser diode is detected very confidently even with a pulse length of only a couple of milliseconds. Next, we find the contour of the spot and the minimum circle that describes it. Draw target hits, play sound. After seven “shots” we count points (of which you can get a maximum of 100).
    Before shooting, you need to calibrate the position of the target in the camera.
    By the way, the "target":
    Hidden text

    My camera is three meters from the target. Uncomment the line #print (center, dist), shoot until we hit exactly the center. We look at the hit position in the log and write to the beginning of the script (CenterX, CenterY). There we also rule Radius to fit our target size.
    The resolution of the camera from three meters is about two millimeters. If this doesn’t seem enough, you can simply slide the camera.
    That's it, we fall into childhood, we start classes on fire training.

    The process looks like this (litter for ragged wallpapers - I live in a rented apartment):

    Sources for the project: github.com/DIMOSUS/Laser-shoting

    Do not forget about security - you can look at the laser, like with a telescope in the sun, only two times ...
    In the future, I would like to install a servo in the gun that will pull the load to simulate recoil . Well, print a normal target.

    Also popular now: