Files
This commit is contained in:
commit
25bc1ebd44
158
client.py
Normal file
158
client.py
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
# On Ubuntu gstreamer interface is missing on OpenCV
|
||||||
|
# On Fedora enable RPM fusion repo and install packages
|
||||||
|
# dnf install python3-opencv gstreamer-plugins-bad-free gstreamer-plugins-ugly gstreamer1-plugins-bad-freeworld gstreamer1-plugins-good gstreamer1-libav python3-evdev
|
||||||
|
|
||||||
|
from time import sleep
|
||||||
|
import sys
|
||||||
|
import socket
|
||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
import time
|
||||||
|
from threading import Thread
|
||||||
|
|
||||||
|
_, hostname = sys.argv
|
||||||
|
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
sock.settimeout(0)
|
||||||
|
sock.bind(("", 37021))
|
||||||
|
|
||||||
|
#WIDTH, HEIGHT = 1920, 1080
|
||||||
|
WIDTH, HEIGHT = 1280, 720
|
||||||
|
WIDTH, HEIGHT = 640, 480
|
||||||
|
#WIDTH, HEIGHT = 320, 240
|
||||||
|
|
||||||
|
CROSSHAIR_THICKNESS = 3
|
||||||
|
CROSSHAIR_SIZE = 50
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
from glob import glob
|
||||||
|
from evdev import InputDevice, categorize, ecodes
|
||||||
|
state = dict()
|
||||||
|
shoot = False
|
||||||
|
robot_shoot_timestamp = 0
|
||||||
|
|
||||||
|
|
||||||
|
class GamepadReader(Thread):
|
||||||
|
def run(self):
|
||||||
|
global shoot
|
||||||
|
global robot_shoot_timestamp
|
||||||
|
gamepad = InputDevice(glob("/dev/input/by-id/usb-Microsoft_Controller*event*")[0])
|
||||||
|
print("Opening:", gamepad)
|
||||||
|
|
||||||
|
for event in gamepad.read_loop():
|
||||||
|
if not event:
|
||||||
|
continue
|
||||||
|
if event.type == 3:
|
||||||
|
state["axis%d" % event.code] = event.value
|
||||||
|
elif event.type == 1:
|
||||||
|
state["button%d" % event.code] = event.value
|
||||||
|
elif event.type == 0:
|
||||||
|
pass # dno?
|
||||||
|
else:
|
||||||
|
print(event.type, event.value, event.code)
|
||||||
|
|
||||||
|
if state.get("button310", 0) or state.get("button311", 0):
|
||||||
|
shoot = True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
t = GamepadReader(daemon=True)
|
||||||
|
|
||||||
|
t.start()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
print("Resolving hostname:", hostname)
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
sockaddr = socket.getaddrinfo(hostname, 37020)[0][-1]
|
||||||
|
except OSError:
|
||||||
|
sleep(0.5)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
print("Sending let's play packet to", sockaddr)
|
||||||
|
msg = "play:%d:%d" % (WIDTH, HEIGHT)
|
||||||
|
sock.sendto(msg.encode("ascii"), sockaddr)
|
||||||
|
|
||||||
|
|
||||||
|
pipeline = 'udpsrc port=5000 caps = "application/x-rtp, encoding-name=(string)H264" ! rtpjitterbuffer mode=3 ! rtph264depay ! decodebin ! videoconvert ! appsink'
|
||||||
|
|
||||||
|
print("gst-launch-1.0 -v", pipeline.replace("appsink", "autovideosink"))
|
||||||
|
sleep(5)
|
||||||
|
cap = cv2.VideoCapture(pipeline)
|
||||||
|
|
||||||
|
if not cap.isOpened():
|
||||||
|
print("Didn't receive video feed")
|
||||||
|
quit()
|
||||||
|
|
||||||
|
|
||||||
|
red = np.zeros((HEIGHT,WIDTH,3), np.uint8)
|
||||||
|
cv2.rectangle(red, (0, 0), (WIDTH, HEIGHT), (0, 0, 255), thickness=-1)
|
||||||
|
cv2.namedWindow("window", cv2.WND_PROP_FULLSCREEN)
|
||||||
|
cv2.setWindowProperty("window",cv2.WND_PROP_FULLSCREEN,cv2.WINDOW_FULLSCREEN)
|
||||||
|
|
||||||
|
blood = 1.0
|
||||||
|
shoot_box_width = 0
|
||||||
|
|
||||||
|
|
||||||
|
while True:
|
||||||
|
ret, frame = cap.read()
|
||||||
|
if ret == False:
|
||||||
|
break
|
||||||
|
|
||||||
|
# cv2.putText(frame, "yoyo",
|
||||||
|
# (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 3)
|
||||||
|
|
||||||
|
cv2.rectangle(frame, (WIDTH//2-CROSSHAIR_THICKNESS//2, HEIGHT//2-CROSSHAIR_SIZE//2), (WIDTH//2+CROSSHAIR_THICKNESS//2, HEIGHT//2+CROSSHAIR_SIZE//2), (0, 255, 0), thickness=-1)
|
||||||
|
cv2.rectangle(frame, (WIDTH//2-CROSSHAIR_SIZE//2, HEIGHT//2-CROSSHAIR_THICKNESS//2), (WIDTH//2+CROSSHAIR_SIZE//2, HEIGHT//2+CROSSHAIR_THICKNESS//2), (0, 255, 0), thickness=-1)
|
||||||
|
cv2.rectangle(frame, (10, HEIGHT-20), (int(WIDTH*0.30), HEIGHT-10),(0, 0, 0),thickness=-1)
|
||||||
|
|
||||||
|
if blood > 0:
|
||||||
|
blood -= 0.02
|
||||||
|
frame = cv2.addWeighted( red, blood, frame, (1-blood), 0.0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
msg = "speed:%d:%d" % (state.get("axis1", 0), state.get("axis3", 0))
|
||||||
|
sock.sendto(msg.encode("ascii"), sockaddr)
|
||||||
|
|
||||||
|
if shoot and time.time() - robot_shoot_timestamp >=1:
|
||||||
|
msg = "shoot"
|
||||||
|
robot_shoot_timestamp = time.time()
|
||||||
|
shoot_box_width = 0
|
||||||
|
#cv2.rectangle(frame, (WIDTH-10, HEIGHT-10), (40, 100),(0, 0, 0),thickness=-1)
|
||||||
|
sock.sendto(msg.encode("ascii"), sockaddr)
|
||||||
|
shoot = False
|
||||||
|
else:
|
||||||
|
shoot = False
|
||||||
|
|
||||||
|
if time.time() - robot_shoot_timestamp <=1:
|
||||||
|
shoot_box_width += int((WIDTH*0.30)/22)
|
||||||
|
else:
|
||||||
|
shoot_box_width = int(WIDTH*0.30)
|
||||||
|
cv2.rectangle(frame, (10, HEIGHT-20), (shoot_box_width, HEIGHT-10),(0, 255, 0),thickness=-1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cv2.imshow("window",frame)
|
||||||
|
if cv2.waitKey(1) & 0xFF == ord('q'):
|
||||||
|
break
|
||||||
|
try:
|
||||||
|
#print("got:", sock.recv(100))
|
||||||
|
data = sock.recv(100)
|
||||||
|
cmd = data.decode("ascii")
|
||||||
|
#print(cmd)
|
||||||
|
if cmd == "hit":
|
||||||
|
robot_hit_timestamp = time.time()
|
||||||
|
blood = 2.2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
except BlockingIOError:
|
||||||
|
pass
|
||||||
|
#print("nuffing")
|
4
config.ini
Normal file
4
config.ini
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[tank]
|
||||||
|
hit_delay = 5
|
||||||
|
robot_id = 2
|
||||||
|
enemy_bytes = 0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x20df4eb1
|
191
robot.py
Normal file
191
robot.py
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
from glob import glob
|
||||||
|
import os
|
||||||
|
from threading import Thread
|
||||||
|
from time import sleep
|
||||||
|
from smbus import SMBus
|
||||||
|
from time import sleep
|
||||||
|
import sys
|
||||||
|
import socket
|
||||||
|
import time
|
||||||
|
from configparser import ConfigParser
|
||||||
|
"""
|
||||||
|
scp tank.py root@tank-465ce7: && ssh root@tank-465ce7 "python3 tank.py"
|
||||||
|
"""
|
||||||
|
|
||||||
|
os.chdir("/root/")
|
||||||
|
|
||||||
|
config = ConfigParser()
|
||||||
|
config.read("config.ini")
|
||||||
|
enemy_bytes = config.get('tank','enemy_bytes').split(",")
|
||||||
|
robot_id = hex(int(config.get('tank','robot_id'),10))
|
||||||
|
hit_delay = int(config.get('tank','hit_delay'),10)
|
||||||
|
hit_delay = int(config.get('tank','hit_delay'),10)
|
||||||
|
|
||||||
|
#robot_id = socket.gethostname().split("-")[-1]
|
||||||
|
robot_shot_time = 0
|
||||||
|
robot_hit_timer = 0
|
||||||
|
|
||||||
|
bus = SMBus(0)
|
||||||
|
hit = False
|
||||||
|
|
||||||
|
|
||||||
|
#os.system("ifconfig wlan0 mtu 2304")
|
||||||
|
|
||||||
|
GSTREAM = """gst-launch-1.0 -v v4l2src device=%(cam)s ! capsfilter caps="video/x-h264, width=%(width)d, height=%(height)s, framerate=20/1" ! rtph264pay config-interval=10 pt=96 ! udpsink host=%(remote)s port=5000 &"""
|
||||||
|
|
||||||
|
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
|
||||||
|
sock.settimeout(0.2)
|
||||||
|
sock.bind(("", 37020))
|
||||||
|
print("Receiver started")
|
||||||
|
|
||||||
|
#sockaddr = "192.168.2.255", 55555
|
||||||
|
#sock.sendto(b"hello", sockaddr)
|
||||||
|
|
||||||
|
def filter_scale(axis):
|
||||||
|
tresh = 3000
|
||||||
|
if abs(axis) < tresh:
|
||||||
|
return 0
|
||||||
|
if axis > 0:
|
||||||
|
return (axis-tresh) * 255 / (32768-tresh)
|
||||||
|
else:
|
||||||
|
return (axis+tresh) * 255 / (32768-tresh)
|
||||||
|
|
||||||
|
class MotorDriver(object):
|
||||||
|
|
||||||
|
MotorSpeedSet = 0x82
|
||||||
|
PWMFrequenceSet = 0x84
|
||||||
|
DirectionSet = 0xaa
|
||||||
|
MotorSetA = 0xa1
|
||||||
|
MotorSetB = 0xa5
|
||||||
|
Nothing = 0x01
|
||||||
|
EnableStepper = 0x1a
|
||||||
|
UnenableStepper = 0x1b
|
||||||
|
Stepernu = 0x1c
|
||||||
|
I2CMotorDriverAdd = 0x0f #Set the address of the I2CMotorDriver
|
||||||
|
|
||||||
|
def __init__(self, bus, address=0x0f):
|
||||||
|
self.I2CMotorDriverAdd=address
|
||||||
|
|
||||||
|
#Maps speed from 0-100 to 0-255
|
||||||
|
def map_vals(self,value, leftMin, leftMax, rightMin, rightMax):
|
||||||
|
#http://stackoverflow.com/questions/1969240/mapping-a-range-of-values-to-another
|
||||||
|
# Figure out how 'wide' each range is
|
||||||
|
leftSpan = leftMax - leftMin
|
||||||
|
rightSpan = rightMax - rightMin
|
||||||
|
|
||||||
|
# Convert the left range into a 0-1 range (float)
|
||||||
|
valueScaled = float(value - leftMin) / float(leftSpan)
|
||||||
|
|
||||||
|
# Convert the 0-1 range into a value in the right range.
|
||||||
|
return int(rightMin + (valueScaled * rightSpan))
|
||||||
|
|
||||||
|
#Set motor speed
|
||||||
|
def MotorSpeedSetAB(self,MotorSpeedA,MotorSpeedB):
|
||||||
|
#MotorSpeedA=self.map_vals(MotorSpeedA,0,32767,0,255)
|
||||||
|
#MotorSpeedB=self.map_vals(MotorSpeedB,0,32767,0,255)
|
||||||
|
bus.write_i2c_block_data(self.I2CMotorDriverAdd, self.MotorSpeedSet, [MotorSpeedA,MotorSpeedB])
|
||||||
|
sleep(.02)
|
||||||
|
|
||||||
|
#Set motor direction
|
||||||
|
def MotorDirectionSet(self,Direction):
|
||||||
|
bus.write_i2c_block_data(self.I2CMotorDriverAdd, self.DirectionSet, [Direction,0])
|
||||||
|
sleep(.02)
|
||||||
|
|
||||||
|
bus = SMBus(0)
|
||||||
|
m = MotorDriver(bus)
|
||||||
|
oldDirection = None
|
||||||
|
old_speed = 0, 0
|
||||||
|
addr = None
|
||||||
|
|
||||||
|
class irReciver(Thread):
|
||||||
|
def run(self):
|
||||||
|
global hit, addr
|
||||||
|
global robot_hit_timer
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
bytes=bus.read_i2c_block_data(0x10,0x02,5)
|
||||||
|
byte = hex(bytes[1] << 24 | bytes[2] << 16 | bytes[3] << 8 | bytes[4])
|
||||||
|
if byte != "0x0":
|
||||||
|
print(byte)
|
||||||
|
#print(byte)
|
||||||
|
# if code belong to enemy then hit
|
||||||
|
if byte in enemy_bytes and byte !=robot_id and not hit:
|
||||||
|
print("Cabuum")
|
||||||
|
hit = True
|
||||||
|
robot_hit_timer = time.time()
|
||||||
|
bus.write_byte_data(0x10,0x06,0x02)
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
sleep(0.2)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
t = irReciver(daemon=True)
|
||||||
|
t.start()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
data, addr = sock.recvfrom(100)
|
||||||
|
except OSError:
|
||||||
|
m.MotorSpeedSetAB(0,0)
|
||||||
|
continue
|
||||||
|
buf = data.decode("ascii").split(":")
|
||||||
|
|
||||||
|
cmd = buf[0]
|
||||||
|
|
||||||
|
if hit:
|
||||||
|
sock.sendto("hit".encode("ascii"),addr)
|
||||||
|
m.MotorDirectionSet(0b0110)
|
||||||
|
hit = False
|
||||||
|
|
||||||
|
if time.time() - robot_hit_timer < 5:
|
||||||
|
m.MotorDirectionSet(0b0110)
|
||||||
|
m.MotorSpeedSetAB(250,250)
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
#end led flashing
|
||||||
|
bus.write_byte_data(0x10,0x06,0x01)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if cmd == "play":
|
||||||
|
remote, port = addr
|
||||||
|
width, height = int(buf[1]), int(buf[2])
|
||||||
|
|
||||||
|
|
||||||
|
os.system("killall gst-launch-1.0")
|
||||||
|
cam = sorted(glob("/dev/video*"))[-1]
|
||||||
|
cmd = GSTREAM % locals()
|
||||||
|
print("Launching:", cmd)
|
||||||
|
os.system(cmd)
|
||||||
|
elif cmd == "shoot":
|
||||||
|
if time.time() - robot_shot_time > 1:
|
||||||
|
#bus.write_byte_data(0x20,0x01,socket.gethostname().split("-")[-1])
|
||||||
|
bus.write_byte_data(0x20,0x01,int(robot_id,16))
|
||||||
|
robot_shot_time = time.time()
|
||||||
|
elif cmd == "speed":
|
||||||
|
forward_backward, left_right = int(buf[1]), int(buf[2])
|
||||||
|
axis1 = -filter_scale(forward_backward)
|
||||||
|
axis2 = filter_scale(left_right)
|
||||||
|
m1 = axis1 - axis2
|
||||||
|
m2 = axis1 + axis2
|
||||||
|
|
||||||
|
mx = max(abs(m1), abs(m2))
|
||||||
|
if mx > 255:
|
||||||
|
m1, m2 = m1 * 255 / mx , m2 * 255 / mx
|
||||||
|
|
||||||
|
d = (0b1000 if m2 < 0 else 0b0100) | (0b10 if m1 < 0 else 0b01)
|
||||||
|
#print("axis1 %03d axis2 %03d m1 %03d m2 %03d d %s" % ( axis1, axis2, m1, m2, bin(d)))
|
||||||
|
|
||||||
|
if d != oldDirection:
|
||||||
|
oldDirection = d
|
||||||
|
m.MotorSpeedSetAB(0,0)
|
||||||
|
m.MotorDirectionSet(d)
|
||||||
|
|
||||||
|
m1 = abs(m1)
|
||||||
|
m2 = abs(m2)
|
||||||
|
|
||||||
|
if (m1, m2) != old_speed:
|
||||||
|
old_speed = m1, m2
|
||||||
|
m.MotorSpeedSetAB(int(m1),int(m2))
|
16
tank
Normal file
16
tank
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/sh /etc/rc.common
|
||||||
|
# Copyright (C) 2015 CZ.NIC z.s.p.o. (http://www.nic.cz/)
|
||||||
|
|
||||||
|
START=81
|
||||||
|
STOP=0
|
||||||
|
|
||||||
|
USE_PROCD=1
|
||||||
|
SCRIPT="/root/robot.py"
|
||||||
|
|
||||||
|
start_service() {
|
||||||
|
procd_open_instance
|
||||||
|
procd_set_param command python3 "$SCRIPT"
|
||||||
|
#procd_set_param stdout 1
|
||||||
|
#procd_set_param stderr 1
|
||||||
|
procd_close_instance
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user