Skip to content

Commit b9eb530

Browse files
committed
Merge branch 'master' of https://github.com/FRC2914/2914FRC2014
2 parents f37cb39 + f7ae346 commit b9eb530

File tree

71 files changed

+2054
-1679
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+2054
-1679
lines changed

.gitignore

+4-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,7 @@
55
/robot drive/2014 Ragnarok/build
66
*.pyc
77
*.log.*
8-
*.log
8+
*.log
9+
/robot drive/Oswald Freedom/build/
10+
/robot drive/Oswald Freedom/nbproject/private/
11+
*.pydevproject

.pydevproject

+3
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,7 @@
22
<?eclipse-pydev version="1.0"?><pydev_project>
33
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
44
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
5+
<pydev_pathproperty name="org.python.pydev.PROJECT_EXTERNAL_SOURCE_PATH">
6+
<path>C:\opencv\build\python\2.7\x86</path>
7+
</pydev_pathproperty>
58
</pydev_project>

LICENSE

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Copyright (c) 2014, Team 2914
2+
All rights reserved.
3+
4+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5+
6+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

README.md

+24-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
2914FRC2014
22
===========
3+
This code is released under the BSD 2-clause license. Check out the file called LICENSE.
4+
35
Robot code and vision tracking code for 2914's 2014 Bot
46

5-
Prerequisites:
7+
===========
8+
###Prerequisites when developing on windows:
9+
610
Eclipse w/git w/pydev
711

812
install python 2.7
@@ -12,3 +16,22 @@ install opencv 2.4.8 to C:\opencv\
1216
install scipy 0.13.2-win32-superpack-python2.7
1317

1418
install numpy-1.8.0-win32-superpack-python2.7
19+
20+
===========
21+
22+
###How does it work and what cool features does it have?
23+
24+
The cRIO and and pandaboard boot on startup. The cRIO runs the project located under `./robot drive`. The pandaboard runs `./python vision stuff/Eye Of Sauron/CODE/eyeofsauron.py`. They then set up a tcp socket. The protocol between the two is documented [here]( https://github.com/FRC2914/2914FRC2014/tree/master/python%20vision%20stuff ).The OS running on the pandaboard can be configured using the instructions [here]( https://github.com/FRC2914/2914FRC2014/wiki/Setting-Up-Arch-Linux).
25+
26+
The cRIO has multiple "modes". Each mode controls rotation. When the user "locks on" to a target, rotation is controlled by that mode. Otherwise rotation is "released" and controlled by rotating the (3d) joystick.
27+
28+
The pandaboard can track different types of objects. It can track game balls, alliance members (by their bumpers), the goal itself (requires calibration to get it right). It can also detect when the goal is lit yellow ("hot"). There is a usb webcam mounted at the front (bumper level) to do this. Tracking balls uses its own webcam, which is mounted about 3 feet off the ground on our intake system.
29+
30+
Log files were supposed to be written to `../LOGS/runtimeXX.log` but the buffers wouldn't flush when the power was cut (after every game). We just `print()`ed everything we wanted to log and we `>>./runtime.log` using bash.
31+
32+
Different cameras need to be calibrated. Is is currently calibrated for a logitech c270 on a properly illuminated FRC competition field. HSV ranges are specified in `/python vision stuff/Eye Of Sauron/CODE/settings.conf.<blue/red>`. Before a match tell it what team you are on by copying the right settings to settings.conf, e.g. w/ red bumpers just
33+
`cp settings.conf.red settings.conf`
34+
35+
36+
37+

python vision stuff/.pydevproject

-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,5 @@
66
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
77
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
88
<pydev_pathproperty name="org.python.pydev.PROJECT_EXTERNAL_SOURCE_PATH">
9-
<path>C:\opencv\build\python\2.7\x86</path>
109
</pydev_pathproperty>
1110
</pydev_project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
#!/usr/bin/env python
2+
3+
'''
4+
This module contais some common routines used by other samples.
5+
'''
6+
7+
import numpy as np
8+
import cv2
9+
import os
10+
from contextlib import contextmanager
11+
import itertools as it
12+
13+
image_extensions = ['.bmp', '.jpg', '.jpeg', '.png', '.tif', '.tiff', '.pbm', '.pgm', '.ppm']
14+
15+
class Bunch(object):
16+
def __init__(self, **kw):
17+
self.__dict__.update(kw)
18+
def __str__(self):
19+
return str(self.__dict__)
20+
21+
def splitfn(fn):
22+
path, fn = os.path.split(fn)
23+
name, ext = os.path.splitext(fn)
24+
return path, name, ext
25+
26+
def anorm2(a):
27+
return (a*a).sum(-1)
28+
def anorm(a):
29+
return np.sqrt( anorm2(a) )
30+
31+
def homotrans(H, x, y):
32+
xs = H[0, 0]*x + H[0, 1]*y + H[0, 2]
33+
ys = H[1, 0]*x + H[1, 1]*y + H[1, 2]
34+
s = H[2, 0]*x + H[2, 1]*y + H[2, 2]
35+
return xs/s, ys/s
36+
37+
def to_rect(a):
38+
a = np.ravel(a)
39+
if len(a) == 2:
40+
a = (0, 0, a[0], a[1])
41+
return np.array(a, np.float64).reshape(2, 2)
42+
43+
def rect2rect_mtx(src, dst):
44+
src, dst = to_rect(src), to_rect(dst)
45+
cx, cy = (dst[1] - dst[0]) / (src[1] - src[0])
46+
tx, ty = dst[0] - src[0] * (cx, cy)
47+
M = np.float64([[ cx, 0, tx],
48+
[ 0, cy, ty],
49+
[ 0, 0, 1]])
50+
return M
51+
52+
53+
def lookat(eye, target, up = (0, 0, 1)):
54+
fwd = np.asarray(target, np.float64) - eye
55+
fwd /= anorm(fwd)
56+
right = np.cross(fwd, up)
57+
right /= anorm(right)
58+
down = np.cross(fwd, right)
59+
R = np.float64([right, down, fwd])
60+
tvec = -np.dot(R, eye)
61+
return R, tvec
62+
63+
def mtx2rvec(R):
64+
w, u, vt = cv2.SVDecomp(R - np.eye(3))
65+
p = vt[0] + u[:,0]*w[0] # same as np.dot(R, vt[0])
66+
c = np.dot(vt[0], p)
67+
s = np.dot(vt[1], p)
68+
axis = np.cross(vt[0], vt[1])
69+
return axis * np.arctan2(s, c)
70+
71+
def draw_str(dst, (x, y), s):
72+
cv2.putText(dst, s, (x+1, y+1), cv2.FONT_HERSHEY_PLAIN, 1.0, (0, 0, 0), thickness = 2, lineType=cv2.CV_AA)
73+
cv2.putText(dst, s, (x, y), cv2.FONT_HERSHEY_PLAIN, 1.0, (255, 255, 255), lineType=cv2.CV_AA)
74+
75+
class Sketcher:
76+
def __init__(self, windowname, dests, colors_func):
77+
self.prev_pt = None
78+
self.windowname = windowname
79+
self.dests = dests
80+
self.colors_func = colors_func
81+
self.dirty = False
82+
self.show()
83+
cv2.setMouseCallback(self.windowname, self.on_mouse)
84+
85+
def show(self):
86+
cv2.imshow(self.windowname, self.dests[0])
87+
88+
def on_mouse(self, event, x, y, flags, param):
89+
pt = (x, y)
90+
if event == cv2.EVENT_LBUTTONDOWN:
91+
self.prev_pt = pt
92+
if self.prev_pt and flags & cv2.EVENT_FLAG_LBUTTON:
93+
for dst, color in zip(self.dests, self.colors_func()):
94+
cv2.line(dst, self.prev_pt, pt, color, 5)
95+
self.dirty = True
96+
self.prev_pt = pt
97+
self.show()
98+
else:
99+
self.prev_pt = None
100+
101+
102+
# palette data from matplotlib/_cm.py
103+
_jet_data = {'red': ((0., 0, 0), (0.35, 0, 0), (0.66, 1, 1), (0.89,1, 1),
104+
(1, 0.5, 0.5)),
105+
'green': ((0., 0, 0), (0.125,0, 0), (0.375,1, 1), (0.64,1, 1),
106+
(0.91,0,0), (1, 0, 0)),
107+
'blue': ((0., 0.5, 0.5), (0.11, 1, 1), (0.34, 1, 1), (0.65,0, 0),
108+
(1, 0, 0))}
109+
110+
cmap_data = { 'jet' : _jet_data }
111+
112+
def make_cmap(name, n=256):
113+
data = cmap_data[name]
114+
xs = np.linspace(0.0, 1.0, n)
115+
channels = []
116+
eps = 1e-6
117+
for ch_name in ['blue', 'green', 'red']:
118+
ch_data = data[ch_name]
119+
xp, yp = [], []
120+
for x, y1, y2 in ch_data:
121+
xp += [x, x+eps]
122+
yp += [y1, y2]
123+
ch = np.interp(xs, xp, yp)
124+
channels.append(ch)
125+
return np.uint8(np.array(channels).T*255)
126+
127+
def nothing(*arg, **kw):
128+
pass
129+
130+
def clock():
131+
return cv2.getTickCount() / cv2.getTickFrequency()
132+
133+
@contextmanager
134+
def Timer(msg):
135+
print msg, '...',
136+
start = clock()
137+
try:
138+
yield
139+
finally:
140+
print "%.2f ms" % ((clock()-start)*1000)
141+
142+
class StatValue:
143+
def __init__(self, smooth_coef = 0.5):
144+
self.value = None
145+
self.smooth_coef = smooth_coef
146+
def update(self, v):
147+
if self.value is None:
148+
self.value = v
149+
else:
150+
c = self.smooth_coef
151+
self.value = c * self.value + (1.0-c) * v
152+
153+
class RectSelector:
154+
def __init__(self, win, callback):
155+
self.win = win
156+
self.callback = callback
157+
cv2.setMouseCallback(win, self.onmouse)
158+
self.drag_start = None
159+
self.drag_rect = None
160+
def onmouse(self, event, x, y, flags, param):
161+
x, y = np.int16([x, y]) # BUG
162+
if event == cv2.EVENT_LBUTTONDOWN:
163+
self.drag_start = (x, y)
164+
if self.drag_start:
165+
if flags & cv2.EVENT_FLAG_LBUTTON:
166+
xo, yo = self.drag_start
167+
x0, y0 = np.minimum([xo, yo], [x, y])
168+
x1, y1 = np.maximum([xo, yo], [x, y])
169+
self.drag_rect = None
170+
if x1-x0 > 0 and y1-y0 > 0:
171+
self.drag_rect = (x0, y0, x1, y1)
172+
else:
173+
rect = self.drag_rect
174+
self.drag_start = None
175+
self.drag_rect = None
176+
if rect:
177+
self.callback(rect)
178+
def draw(self, vis):
179+
if not self.drag_rect:
180+
return False
181+
x0, y0, x1, y1 = self.drag_rect
182+
cv2.rectangle(vis, (x0, y0), (x1, y1), (0, 255, 0), 2)
183+
return True
184+
@property
185+
def dragging(self):
186+
return self.drag_rect is not None
187+
188+
189+
def grouper(n, iterable, fillvalue=None):
190+
'''grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx'''
191+
args = [iter(iterable)] * n
192+
return it.izip_longest(fillvalue=fillvalue, *args)
193+
194+
def mosaic(w, imgs):
195+
'''Make a grid from images.
196+
197+
w -- number of grid columns
198+
imgs -- images (must have same size and format)
199+
'''
200+
imgs = iter(imgs)
201+
img0 = imgs.next()
202+
pad = np.zeros_like(img0)
203+
imgs = it.chain([img0], imgs)
204+
rows = grouper(w, imgs, pad)
205+
return np.vstack(map(np.hstack, rows))
206+
207+
def getsize(img):
208+
h, w = img.shape[:2]
209+
return w, h
210+
211+
def mdot(*args):
212+
return reduce(np.dot, args)
213+
214+
def draw_keypoints(vis, keypoints, color = (0, 255, 255)):
215+
for kp in keypoints:
216+
x, y = kp.pt
217+
cv2.circle(vis, (int(x), int(y)), 2, color)

0 commit comments

Comments
 (0)