Привет Хабр.
Люблю стрелковое оружие и стрельбу. Однако в домашних условий это плохое хобби. Нет, ну можно конечно купить травмат и изрешетить квартиру, но, думаю, домашние этого не оценят. Не желая мирится с этим, решил реализовать свой, в меру безопасный домашний тир. Если заинтересовал — добро пожаловать под кат.
Идеи, как это можно реализовать, витали в голове давно. Вот несколько забракованных:
— пистолет с фототранзистором + экран монитора. Подсвечивая половину/четверть/одну восьмую/и т.д. экрана, проверяем ответ от фототранзистора и итеративно уточняем часть экрана, в которую направлен пистолет. Идею забраковал из-за низкой частоты обновления мониторов и их инерционности.
— пистолет с фототранзистором + экран из светодиодных матриц. Уже лучше, можно обновлять изображение на диодной матрице с достаточной частотой. Даже начал спаивать диодные матрицы, но вовремя одумался.
— пистолет с камерой, несколько лазерных светодиодов, образующих метки на стене, по которым камера определяет свое положение. В принципе идея была не плоха. Однако прикинув, как будет смотреться пистолет с прикрученной к нему вебкамерой, так же от нее отказался.
Ну и финальная идея — статическая камера, смотрящая на стену и пистолет с лазером. Идея есть, дело за реализацией.
Купил первый попавшийся детский пистолет(Desert Eagle калибра 50). Выкинул внутренности, обработал напильником и установил в него лазерный диод, кнопку на спусковой крючок и ардуинину nano. Нет, можно конечно поставить туда в место ардуинины конденсатор, так что бы он кнопкой переключался с источника питания на диод и обратно, но это не достаточно гибкий подход. Лазерный диод приклеил на холодную сварку. Пока она застывала, аккуратно корректировал включенный диод, совмещая с прицельной планкой.
Написал простейший скетч:
Пистолет «стреляет» короткими импульсами по 4мс (подобрал в процессе настройки) с максимальной скорострельностью 2 выстрела в секунду.
Далее дело за приемной стороной. Купил простейшую вебкамеру. Малинка уже была в закромах. Подключил камеру, направил на стену.
Далее нужно поставить на малинку необходимые пакеты
Осталось написать питоновский скрипт. Это был мой первый скрипт на питоне, по этому пришлось убить на него почти день.
Немного пояснений. Скрипт делает снимки с камеры и преобразует их в черно-белые. Далее отсекает все что темнее 245. Как показала практика пятно лазерного диода детектируется очень уверенно даже при длине импульса всего пару миллисекунд. Далее находим контур пятна и минимальную окружность, его описывающую. Рисуем попадания на мишени, проигрываем звук. После семи «выстрелов» подсчитываем очки (коих можно набить максимум 100).
Перед стрельбой нужно откалибровать положение мишени в камере.
Кстати «мишень»:
У меня камера стоит в трех метрах от мишени. Раскомментируем строку #print (center, dist), стреляем, пока не попадем точно в центр. Смотрим в логе позицию попадания и прописываем в начало скрипта (CenterX, CenterY). Так же там правим Radius под свой размер мишени.
Разрешающая способность камеры с трех метров порядка двух миллиметров. Если этого покажется мало, можно просто придвинуть камеру.
Все,впадаем в детство приступаем к занятиям по огневой подготовке.
Процесс выглядит так (сори за обшарпанные обои — живу на съемной квартире):
Исходники к проекту: github.com/DIMOSUS/Laser-shoting
Не забываем про безопасность — на лазер, как и в телескоп на солнце, можно посмотреть только два раза…
В будущем хотелось бы установить в пистолет сервомашинку, которая будет дергать груз для симуляции отдачи. Ну и распечатать нормальную мишень.
Люблю стрелковое оружие и стрельбу. Однако в домашних условий это плохое хобби. Нет, ну можно конечно купить травмат и изрешетить квартиру, но, думаю, домашние этого не оценят. Не желая мирится с этим, решил реализовать свой, в меру безопасный домашний тир. Если заинтересовал — добро пожаловать под кат.
Идеи, как это можно реализовать, витали в голове давно. Вот несколько забракованных:
— пистолет с фототранзистором + экран монитора. Подсвечивая половину/четверть/одну восьмую/и т.д. экрана, проверяем ответ от фототранзистора и итеративно уточняем часть экрана, в которую направлен пистолет. Идею забраковал из-за низкой частоты обновления мониторов и их инерционности.
— пистолет с фототранзистором + экран из светодиодных матриц. Уже лучше, можно обновлять изображение на диодной матрице с достаточной частотой. Даже начал спаивать диодные матрицы, но вовремя одумался.
— пистолет с камерой, несколько лазерных светодиодов, образующих метки на стене, по которым камера определяет свое положение. В принципе идея была не плоха. Однако прикинув, как будет смотреться пистолет с прикрученной к нему вебкамерой, так же от нее отказался.
Ну и финальная идея — статическая камера, смотрящая на стену и пистолет с лазером. Идея есть, дело за реализацией.
Купил первый попавшийся детский пистолет(Desert Eagle калибра 50). Выкинул внутренности, обработал напильником и установил в него лазерный диод, кнопку на спусковой крючок и ардуинину nano. Нет, можно конечно поставить туда в место ардуинины конденсатор, так что бы он кнопкой переключался с источника питания на диод и обратно, но это не достаточно гибкий подход. Лазерный диод приклеил на холодную сварку. Пока она застывала, аккуратно корректировал включенный диод, совмещая с прицельной планкой.
Скрытый текст
Скрытый текст
Написал простейший скетч:
Скрытый текст
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;
delay(1);
}
Пистолет «стреляет» короткими импульсами по 4мс (подобрал в процессе настройки) с максимальной скорострельностью 2 выстрела в секунду.
Далее дело за приемной стороной. Купил простейшую вебкамеру. Малинка уже была в закромах. Подключил камеру, направил на стену.
Скрытый текст
Далее нужно поставить на малинку необходимые пакеты
sudo apt-get install libv4l-0 libopencv-dev python-opencv
Осталось написать питоновский скрипт. Это был мой первый скрипт на питоне, по этому пришлось убить на него почти день.
Скрытый текст
#!/usr/bin/python
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:
break
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)
#calibrate
#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()
cv2.waitKey(300)
subprocess.Popen('aplay 924.wav', shell = True)
cv2.waitKey(1000)
cv2.waitKey(50)
cv2.destroyAllWindows()
Немного пояснений. Скрипт делает снимки с камеры и преобразует их в черно-белые. Далее отсекает все что темнее 245. Как показала практика пятно лазерного диода детектируется очень уверенно даже при длине импульса всего пару миллисекунд. Далее находим контур пятна и минимальную окружность, его описывающую. Рисуем попадания на мишени, проигрываем звук. После семи «выстрелов» подсчитываем очки (коих можно набить максимум 100).
Перед стрельбой нужно откалибровать положение мишени в камере.
Кстати «мишень»:
Скрытый текст
У меня камера стоит в трех метрах от мишени. Раскомментируем строку #print (center, dist), стреляем, пока не попадем точно в центр. Смотрим в логе позицию попадания и прописываем в начало скрипта (CenterX, CenterY). Так же там правим Radius под свой размер мишени.
Разрешающая способность камеры с трех метров порядка двух миллиметров. Если этого покажется мало, можно просто придвинуть камеру.
Все,
Процесс выглядит так (сори за обшарпанные обои — живу на съемной квартире):
Исходники к проекту: github.com/DIMOSUS/Laser-shoting
Не забываем про безопасность — на лазер, как и в телескоп на солнце, можно посмотреть только два раза…
В будущем хотелось бы установить в пистолет сервомашинку, которая будет дергать груз для симуляции отдачи. Ну и распечатать нормальную мишень.