├── CODE_OF_CONDUCT.md
├── Hardware
├── LED light setup
│ ├── 3D printing
│ │ ├── COPYRIGHT NOTICE
│ │ ├── led and lens holder.STL
│ │ ├── light slider.STL
│ │ └── slider mounting bracket.STL
│ ├── LED PCB designs
│ │ ├── COPYRIGHT NOTICE
│ │ ├── Design1 - Board Outline.gbr
│ │ ├── Design1 - Copper Bottom.gbr
│ │ ├── Design1 - Copper Top-Copper Bottom.drl
│ │ ├── Design1 - Copper Top.gbr
│ │ ├── Design1 - Silkscreen Bottom.gbr
│ │ ├── Design1 - Silkscreen Top.gbr
│ │ ├── Design1 - Solder Mask Bottom.gbr
│ │ └── Design1 - Solder Mask Top.gbr
│ └── laser cutter
│ │ ├── COPYRIGHT NOTICE
│ │ └── LED diffuser.svg
├── LICENSE
├── Original PiSpy
│ ├── COPYRIGHT NOTICE
│ ├── Camera extension.STL
│ ├── Camera mount.stl
│ ├── Laser Cut Wooden Stand.svg
│ └── RPi mount.STL
└── alternative designs
│ ├── antbox from above
│ ├── COPYRIGHT NOTICE
│ ├── antbox camera mount.STL
│ └── antbox wooden stand 6mm.svg
│ └── lid integration with aerial camera and light
│ ├── COPYRIGHT NOTICE
│ └── camera and LED board mount_laser cut.svg
├── LICENSE
├── PiSpy User Manual v1.1.pdf
├── PiSpy desktop.png
├── README.md
├── Software
├── PiSpy disk image.md
└── PiSpy
│ ├── Day_Night_Mode.py
│ ├── Image.py
│ ├── Import_Trigger.py
│ ├── PiSpy.py
│ ├── Record.py
│ └── Time_Lists.py
└── okh-PiSpy.yml
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, religion, or sexual identity
10 | and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | * Demonstrating empathy and kindness toward other people
21 | * Being respectful of differing opinions, viewpoints, and experiences
22 | * Giving and gracefully accepting constructive feedback
23 | * Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | * Focusing on what is best not just for us as individuals, but for the
26 | overall community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | * The use of sexualized language or imagery, and sexual attention or
31 | advances of any kind
32 | * Trolling, insulting or derogatory comments, and personal or political attacks
33 | * Public or private harassment
34 | * Publishing others' private information, such as a physical or email
35 | address, without their explicit permission
36 | * Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | gpask@middlebury.edu.
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series
86 | of actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or
93 | permanent ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within
113 | the community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120 |
121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
122 | enforcement ladder](https://github.com/mozilla/diversity).
123 |
124 | [homepage]: https://www.contributor-covenant.org
125 |
126 | For answers to common questions about this code of conduct, see the FAQ at
127 | https://www.contributor-covenant.org/faq. Translations are available at
128 | https://www.contributor-covenant.org/translations.
129 |
--------------------------------------------------------------------------------
/Hardware/LED light setup/3D printing/COPYRIGHT NOTICE:
--------------------------------------------------------------------------------
1 | Copyright Gregory Pask, Marcy Kittredge, and Thomas Thul 2022.
2 |
3 | This source describes Open Hardware and is licensed under the CERNOHL-S v2.
4 |
5 | You may redistribute and modify this source and make products using it
6 | under the terms of the CERN-OHL-S v2
7 | (https://ohwr.org/cern ohl s v2.txt ).
8 |
9 | This source is distributed WITHOUT ANY EXPRESS OR IMPLIED
10 | WARRANTY, INCLUDING OF MERCHANTABILITY, SATISFACTORY
11 | QUALITY AND FITNESS FOR A PARTICULAR PURPOSE. Please see
12 | the CERN-OHL-S v2 for applicable conditions.
13 |
14 | Source location: https://github.com/gpask/PiSpy
15 |
16 | As per CERN-OHL-S v2 section 4, should You produce hardware based
17 | on this source, You must where practicable maintain the Source Location
18 | visible on the external case of the PiSpy or other products you make using
19 | this source.
20 |
--------------------------------------------------------------------------------
/Hardware/LED light setup/3D printing/led and lens holder.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gpask/PiSpy/4395658d6053857533d4da31a2e011c20931ea8d/Hardware/LED light setup/3D printing/led and lens holder.STL
--------------------------------------------------------------------------------
/Hardware/LED light setup/3D printing/light slider.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gpask/PiSpy/4395658d6053857533d4da31a2e011c20931ea8d/Hardware/LED light setup/3D printing/light slider.STL
--------------------------------------------------------------------------------
/Hardware/LED light setup/3D printing/slider mounting bracket.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gpask/PiSpy/4395658d6053857533d4da31a2e011c20931ea8d/Hardware/LED light setup/3D printing/slider mounting bracket.STL
--------------------------------------------------------------------------------
/Hardware/LED light setup/LED PCB designs/COPYRIGHT NOTICE:
--------------------------------------------------------------------------------
1 | Copyright Gregory Pask, Marcy Kittredge, Owen Meng, and Matt Lamparter 2022.
2 |
3 | This source describes Open Hardware and is licensed under the CERNOHL-S v2.
4 |
5 | You may redistribute and modify this source and make products using it
6 | under the terms of the CERN-OHL-S v2
7 | (https://ohwr.org/cern ohl s v2.txt ).
8 |
9 | This source is distributed WITHOUT ANY EXPRESS OR IMPLIED
10 | WARRANTY, INCLUDING OF MERCHANTABILITY, SATISFACTORY
11 | QUALITY AND FITNESS FOR A PARTICULAR PURPOSE. Please see
12 | the CERN-OHL-S v2 for applicable conditions.
13 |
14 | Source location: https://github.com/gpask/PiSpy
15 |
16 | As per CERN-OHL-S v2 section 4, should You produce hardware based
17 | on this source, You must where practicable maintain the Source Location
18 | visible on the external case of the PiSpy or other products you make using
19 | this source.
20 |
--------------------------------------------------------------------------------
/Hardware/LED light setup/LED PCB designs/Design1 - Board Outline.gbr:
--------------------------------------------------------------------------------
1 | G04 Generated by Ultiboard 14.0 *
2 | %FSLAX33Y33*%
3 | %MOMM*%
4 |
5 | %ADD10C,0.001*%
6 | %ADD11C,0.001*%
7 |
8 |
9 | G04 ColorRGB 00FFFF for the following layer *
10 | %LNBoard Outline*%
11 | %LPD*%
12 | G54D10*
13 | G54D11*
14 | X0Y0D02*
15 | X55880Y0D01*
16 | X55880Y30480D01*
17 | X0Y30480D01*
18 | X0Y0D01*
19 |
20 | M02*
21 |
--------------------------------------------------------------------------------
/Hardware/LED light setup/LED PCB designs/Design1 - Copper Bottom.gbr:
--------------------------------------------------------------------------------
1 | G04 Generated by Ultiboard 14.0 *
2 | %FSLAX33Y33*%
3 | %MOMM*%
4 |
5 | %ADD10C,0.001*%
6 | %ADD11C,0.254*%
7 | %ADD12C,0.635*%
8 | %ADD13C,1.600*%
9 |
10 |
11 | G04 ColorRGB 00FF00 for the following layer *
12 | %LNCopper Bottom*%
13 | %LPD*%
14 | G54D10*
15 | G36*
16 | X55497Y30097D02*
17 | X55497Y30097D01*
18 | X383Y30097D01*
19 | X383Y383D01*
20 | X55497Y383D01*
21 | X55497Y30097D01*
22 | D02*
23 | G37*
24 | %LPC*%
25 | G36*
26 | X8129Y5080D02*
27 | G75*
28 | D01*
29 | G02X8129Y5080I2031J0*
30 | G01*
31 | D02*
32 | G37*
33 | G36*
34 | X43689Y5080D02*
35 | G75*
36 | D01*
37 | G02X43689Y5080I2031J0*
38 | G01*
39 | D02*
40 | G37*
41 | G36*
42 | X3976Y14389D02*
43 | G74*
44 | D01*
45 | G02X4661Y15074I1103J418*
46 | G01*
47 | X4661Y15074D01*
48 | X4661Y14389D01*
49 | X3976Y14389D01*
50 | D02*
51 | G37*
52 | G36*
53 | X5499Y15074D02*
54 | G74*
55 | D01*
56 | G02X6184Y14389I418J1103*
57 | G01*
58 | X6184Y14389D01*
59 | X5499Y14389D01*
60 | X5499Y15074D01*
61 | D02*
62 | G37*
63 | G36*
64 | X6184Y13551D02*
65 | G74*
66 | D01*
67 | G02X5499Y12866I1103J418*
68 | G01*
69 | X5499Y12866D01*
70 | X5499Y13551D01*
71 | X6184Y13551D01*
72 | D02*
73 | G37*
74 | G36*
75 | X4661Y12866D02*
76 | G74*
77 | D01*
78 | G02X3976Y13551I418J1103*
79 | G01*
80 | X3976Y13551D01*
81 | X4661Y13551D01*
82 | X4661Y12866D01*
83 | D02*
84 | G37*
85 | G36*
86 | X4580Y13970D02*
87 | G75*
88 | D01*
89 | G02X4580Y13970I500J0*
90 | G01*
91 | D02*
92 | G37*
93 | G36*
94 | X3899Y19050D02*
95 | G75*
96 | D01*
97 | G02X3899Y19050I1181J0*
98 | G01*
99 | D02*
100 | G37*
101 | G36*
102 | X49619Y11430D02*
103 | G75*
104 | D01*
105 | G02X49619Y11430I1181J0*
106 | G01*
107 | D02*
108 | G37*
109 | G36*
110 | X49696Y16929D02*
111 | G74*
112 | D01*
113 | G02X50381Y17614I1103J418*
114 | G01*
115 | X50381Y17614D01*
116 | X50381Y16929D01*
117 | X49696Y16929D01*
118 | D02*
119 | G37*
120 | G36*
121 | X51219Y17614D02*
122 | G74*
123 | D01*
124 | G02X51904Y16929I418J1103*
125 | G01*
126 | X51904Y16929D01*
127 | X51219Y16929D01*
128 | X51219Y17614D01*
129 | D02*
130 | G37*
131 | G36*
132 | X51904Y16091D02*
133 | G74*
134 | D01*
135 | G02X51219Y15406I1103J418*
136 | G01*
137 | X51219Y15406D01*
138 | X51219Y16091D01*
139 | X51904Y16091D01*
140 | D02*
141 | G37*
142 | G36*
143 | X50381Y15406D02*
144 | G74*
145 | D01*
146 | G02X49696Y16091I418J1103*
147 | G01*
148 | X49696Y16091D01*
149 | X50381Y16091D01*
150 | X50381Y15406D01*
151 | D02*
152 | G37*
153 | G36*
154 | X50300Y16510D02*
155 | G75*
156 | D01*
157 | G02X50300Y16510I500J0*
158 | G01*
159 | D02*
160 | G37*
161 | G36*
162 | X27167Y17006D02*
163 | X27167Y17006D01*
164 | X29501Y14672D01*
165 | X49850Y14672D01*
166 | G75*
167 | D01*
168 | G02X49850Y13268I950J-702*
169 | G01*
170 | X49850Y13268D01*
171 | X29211Y13268D01*
172 | G75*
173 | D01*
174 | G02X28714Y13474I0J702*
175 | G01*
176 | X28714Y13474D01*
177 | X26379Y15808D01*
178 | X6030Y15808D01*
179 | G75*
180 | D01*
181 | G02X6030Y17212I-950J702*
182 | G01*
183 | X6030Y17212D01*
184 | X26670Y17212D01*
185 | G74*
186 | D01*
187 | G02X27167Y17006I0J702*
188 | G01*
189 | D02*
190 | G37*
191 | G36*
192 | X50027Y22086D02*
193 | X50027Y22086D01*
194 | X51296Y20817D01*
195 | G74*
196 | D01*
197 | G02X51502Y20320I496J497*
198 | G01*
199 | X51502Y20320D01*
200 | X51502Y20000D01*
201 | G75*
202 | D01*
203 | G02X50098Y20000I-702J-950*
204 | G01*
205 | X50098Y20000D01*
206 | X50098Y20029D01*
207 | X49239Y20888D01*
208 | X4101Y20888D01*
209 | X3242Y20029D01*
210 | X3242Y12991D01*
211 | X4101Y12132D01*
212 | X4130Y12132D01*
213 | G75*
214 | D01*
215 | G02X4130Y10728I950J-702*
216 | G01*
217 | X4130Y10728D01*
218 | X3810Y10728D01*
219 | G75*
220 | D01*
221 | G02X3607Y10758I0J702*
222 | G01*
223 | G74*
224 | D01*
225 | G02X3314Y10934I204J671*
226 | G01*
227 | X3314Y10934D01*
228 | X2044Y12204D01*
229 | G75*
230 | D01*
231 | G02X1838Y12701I495J496*
232 | G01*
233 | X1838Y12701D01*
234 | X1838Y20319D01*
235 | G75*
236 | D01*
237 | G02X2044Y20816I702J0*
238 | G01*
239 | X2044Y20816D01*
240 | X3314Y22086D01*
241 | G75*
242 | D01*
243 | G02X3811Y22292I496J-495*
244 | G01*
245 | X3811Y22292D01*
246 | X49529Y22292D01*
247 | G75*
248 | D01*
249 | G02X49678Y22276I0J-702*
250 | G01*
251 | G74*
252 | D01*
253 | G02X50027Y22086I147J685*
254 | G01*
255 | D02*
256 | G37*
257 | G36*
258 | X8129Y25400D02*
259 | G75*
260 | D01*
261 | G02X8129Y25400I2031J0*
262 | G01*
263 | D02*
264 | G37*
265 | G36*
266 | X43689Y25400D02*
267 | G75*
268 | D01*
269 | G02X43689Y25400I2031J0*
270 | G01*
271 | D02*
272 | G37*
273 | %LPD*%
274 | G54D11*
275 | X8129Y5080D02*
276 | G75*
277 | D01*
278 | G02X8129Y5080I2031J0*
279 | G01*
280 | X43689Y5080D02*
281 | G75*
282 | D01*
283 | G02X43689Y5080I2031J0*
284 | G01*
285 | X3976Y14389D02*
286 | G74*
287 | D01*
288 | G02X4661Y15074I1103J418*
289 | G01*
290 | X4661Y14389D01*
291 | X3976Y14389D01*
292 | X5499Y15074D02*
293 | G74*
294 | D01*
295 | G02X6184Y14389I418J1103*
296 | G01*
297 | X5499Y14389D01*
298 | X5499Y15074D01*
299 | X6184Y13551D02*
300 | G74*
301 | D01*
302 | G02X5499Y12866I1103J418*
303 | G01*
304 | X5499Y13551D01*
305 | X6184Y13551D01*
306 | X4661Y12866D02*
307 | G74*
308 | D01*
309 | G02X3976Y13551I418J1103*
310 | G01*
311 | X4661Y13551D01*
312 | X4661Y12866D01*
313 | X4580Y13970D02*
314 | G75*
315 | D01*
316 | G02X4580Y13970I500J0*
317 | G01*
318 | X3899Y19050D02*
319 | G75*
320 | D01*
321 | G02X3899Y19050I1181J0*
322 | G01*
323 | X49619Y11430D02*
324 | G75*
325 | D01*
326 | G02X49619Y11430I1181J0*
327 | G01*
328 | X49696Y16929D02*
329 | G74*
330 | D01*
331 | G02X50381Y17614I1103J418*
332 | G01*
333 | X50381Y16929D01*
334 | X49696Y16929D01*
335 | X51219Y17614D02*
336 | G74*
337 | D01*
338 | G02X51904Y16929I418J1103*
339 | G01*
340 | X51219Y16929D01*
341 | X51219Y17614D01*
342 | X51904Y16091D02*
343 | G74*
344 | D01*
345 | G02X51219Y15406I1103J418*
346 | G01*
347 | X51219Y16091D01*
348 | X51904Y16091D01*
349 | X50381Y15406D02*
350 | G74*
351 | D01*
352 | G02X49696Y16091I418J1103*
353 | G01*
354 | X50381Y16091D01*
355 | X50381Y15406D01*
356 | X50300Y16510D02*
357 | G75*
358 | D01*
359 | G02X50300Y16510I500J0*
360 | G01*
361 | X27167Y17006D02*
362 | X29501Y14672D01*
363 | X49850Y14672D01*
364 | G75*
365 | D01*
366 | G02X49850Y13268I950J-702*
367 | G01*
368 | X29211Y13268D01*
369 | G75*
370 | D01*
371 | G02X28714Y13474I0J702*
372 | G01*
373 | X26379Y15808D01*
374 | X6030Y15808D01*
375 | G75*
376 | D01*
377 | G02X6030Y17212I-950J702*
378 | G01*
379 | X26670Y17212D01*
380 | G74*
381 | D01*
382 | G02X27167Y17006I0J702*
383 | G01*
384 | X50027Y22086D02*
385 | X51296Y20817D01*
386 | G74*
387 | D01*
388 | G02X51502Y20320I496J497*
389 | G01*
390 | X51502Y20000D01*
391 | G75*
392 | D01*
393 | G02X50098Y20000I-702J-950*
394 | G01*
395 | X50098Y20029D01*
396 | X49239Y20888D01*
397 | X4101Y20888D01*
398 | X3242Y20029D01*
399 | X3242Y12991D01*
400 | X4101Y12132D01*
401 | X4130Y12132D01*
402 | G75*
403 | D01*
404 | G02X4130Y10728I950J-702*
405 | G01*
406 | X3810Y10728D01*
407 | G75*
408 | D01*
409 | G02X3607Y10758I0J702*
410 | G01*
411 | G74*
412 | D01*
413 | G02X3314Y10934I204J671*
414 | G01*
415 | X2044Y12204D01*
416 | G75*
417 | D01*
418 | G02X1838Y12701I495J496*
419 | G01*
420 | X1838Y20319D01*
421 | G75*
422 | D01*
423 | G02X2044Y20816I702J0*
424 | G01*
425 | X3314Y22086D01*
426 | G75*
427 | D01*
428 | G02X3811Y22292I496J-495*
429 | G01*
430 | X49529Y22292D01*
431 | G75*
432 | D01*
433 | G02X49678Y22276I0J-702*
434 | G01*
435 | G74*
436 | D01*
437 | G02X50027Y22086I147J685*
438 | G01*
439 | X8129Y25400D02*
440 | G75*
441 | D01*
442 | G02X8129Y25400I2031J0*
443 | G01*
444 | X43689Y25400D02*
445 | G75*
446 | D01*
447 | G02X43689Y25400I2031J0*
448 | G01*
449 | X55497Y30097D02*
450 | X383Y30097D01*
451 | X383Y383D01*
452 | X55497Y383D01*
453 | X55497Y30097D01*
454 | G54D12*
455 | X5080Y16510D02*
456 | X26670Y16510D01*
457 | X29210Y13970D01*
458 | X50800Y13970D01*
459 | X50800Y19050D02*
460 | X50800Y20320D01*
461 | X49530Y21590D01*
462 | X5080Y11430D02*
463 | X3810Y11430D01*
464 | X3810Y21590D02*
465 | X49530Y21590D01*
466 | X2540Y12700D02*
467 | X2540Y20320D01*
468 | X3810Y11430D02*
469 | X2540Y12700D01*
470 | X2540Y20320D02*
471 | X3810Y21590D01*
472 | G54D13*
473 | X5080Y19050D03*
474 | X5080Y13970D03*
475 | X5080Y16510D03*
476 | X5080Y11430D03*
477 | X50800Y16510D03*
478 | X50800Y11430D03*
479 | X50800Y19050D03*
480 | X50800Y13970D03*
481 |
482 | M02*
483 |
--------------------------------------------------------------------------------
/Hardware/LED light setup/LED PCB designs/Design1 - Copper Top-Copper Bottom.drl:
--------------------------------------------------------------------------------
1 | M48
2 | METRIC,TZ
3 | VER,1
4 | FMAT,2
5 | DETECT,ON
6 | ATC,ON
7 | T1C3.300
8 | T2C1.000
9 | %
10 | T1
11 | X10160Y25400
12 | Y5080
13 | X45720Y25400
14 | Y5080
15 | T2
16 | X5080Y19050
17 | Y13970
18 | Y16510
19 | Y11430
20 | X50800Y16510
21 | Y11430
22 | Y19050
23 | Y13970
24 | M30
25 |
--------------------------------------------------------------------------------
/Hardware/LED light setup/LED PCB designs/Design1 - Silkscreen Bottom.gbr:
--------------------------------------------------------------------------------
1 | G04 Generated by Ultiboard 14.0 *
2 | %FSLAX33Y33*%
3 | %MOMM*%
4 |
5 | %ADD10C,0.001*%
6 | %ADD11C,0.156*%
7 | %ADD12C,0.200*%
8 |
9 |
10 | G04 ColorRGB FF14FF for the following layer *
11 | %LNSilkscreen Bottom*%
12 | %LPD*%
13 | G54D10*
14 | G54D11*
15 | X4880Y21429D02*
16 | X4680Y21628D01*
17 | X4680Y21827D01*
18 | X4880Y22026D01*
19 | X5680Y22026D01*
20 | X5480Y22424D02*
21 | X5680Y22623D01*
22 | X4680Y22623D01*
23 | X4680Y22325D02*
24 | X4680Y22922D01*
25 | X50600Y21429D02*
26 | X50400Y21628D01*
27 | X50400Y21827D01*
28 | X50600Y22026D01*
29 | X51400Y22026D01*
30 | X51200Y22325D02*
31 | X51400Y22524D01*
32 | X51400Y22723D01*
33 | X51200Y22922D01*
34 | X51100Y22922D01*
35 | X50400Y22325D01*
36 | X50400Y22922D01*
37 | X50500Y22922D01*
38 | X8925Y19249D02*
39 | X8925Y19846D01*
40 | X9325Y19846D01*
41 | X9325Y19448D01*
42 | X9525Y19249D01*
43 | X9725Y19249D01*
44 | X9925Y19448D01*
45 | X9925Y19846D01*
46 | X8925Y18950D02*
47 | X9925Y18652D01*
48 | X8925Y18353D01*
49 | X9925Y17306D02*
50 | X8925Y17306D01*
51 | X8925Y16908D01*
52 | X9125Y16709D01*
53 | X9225Y16709D01*
54 | X9425Y16908D01*
55 | X9425Y17306D01*
56 | X9425Y17207D02*
57 | X9925Y16709D01*
58 | X9425Y13920D02*
59 | X9425Y13721D01*
60 | X9725Y13721D01*
61 | X9925Y13920D01*
62 | X9925Y14119D01*
63 | X9725Y14318D01*
64 | X9125Y14318D01*
65 | X8925Y14119D01*
66 | X8925Y13721D01*
67 | X8925Y11778D02*
68 | X9925Y11679D01*
69 | X9525Y11480D01*
70 | X9925Y11281D01*
71 | X8925Y11181D01*
72 | X46320Y11231D02*
73 | X46320Y10634D01*
74 | X45920Y10634D01*
75 | X45920Y11032D01*
76 | X45720Y11231D01*
77 | X45520Y11231D01*
78 | X45320Y11032D01*
79 | X45320Y10634D01*
80 | X46320Y11530D02*
81 | X45320Y11828D01*
82 | X46320Y12127D01*
83 | X45320Y13174D02*
84 | X46320Y13174D01*
85 | X46320Y13572D01*
86 | X46120Y13771D01*
87 | X46020Y13771D01*
88 | X45820Y13572D01*
89 | X45820Y13174D01*
90 | X45820Y13273D02*
91 | X45320Y13771D01*
92 | X45820Y16560D02*
93 | X45820Y16759D01*
94 | X45520Y16759D01*
95 | X45320Y16560D01*
96 | X45320Y16361D01*
97 | X45520Y16162D01*
98 | X46120Y16162D01*
99 | X46320Y16361D01*
100 | X46320Y16759D01*
101 | X46320Y18702D02*
102 | X45320Y18801D01*
103 | X45720Y19000D01*
104 | X45320Y19199D01*
105 | X46320Y19299D01*
106 | G54D12*
107 | X1680Y20675D02*
108 | X8480Y20675D01*
109 | X8480Y9805D01*
110 | X1680Y9805D01*
111 | X1680Y20675D01*
112 | X54200Y9805D02*
113 | X47400Y9805D01*
114 | X47400Y20675D01*
115 | X54200Y20675D01*
116 | X54200Y9805D01*
117 |
118 | M02*
119 |
--------------------------------------------------------------------------------
/Hardware/LED light setup/LED PCB designs/Design1 - Silkscreen Top.gbr:
--------------------------------------------------------------------------------
1 | G04 Generated by Ultiboard 14.0 *
2 | %FSLAX33Y33*%
3 | %MOMM*%
4 |
5 | %ADD10C,0.001*%
6 | %ADD11C,0.156*%
7 | %ADD12C,0.203*%
8 | %ADD13C,0.305*%
9 | %ADD14C,0.200*%
10 | %ADD15C,0.250*%
11 |
12 |
13 | G04 ColorRGB FFFF00 for the following layer *
14 | %LNSilkscreen Top*%
15 | %LPD*%
16 | G54D10*
17 | G54D11*
18 | X19085Y16462D02*
19 | X20085Y16561D01*
20 | X19685Y16760D01*
21 | X20085Y16959D01*
22 | X19085Y17059D01*
23 | X20085Y17358D02*
24 | X19085Y17358D01*
25 | X20085Y17955D02*
26 | X19085Y17955D01*
27 | X19585Y17358D02*
28 | X19585Y17955D01*
29 | X20085Y18453D02*
30 | X20085Y18652D01*
31 | X19085Y18453D02*
32 | X19085Y18652D01*
33 | X20085Y18552D02*
34 | X19085Y18552D01*
35 | X20085Y19448D02*
36 | X19085Y19448D01*
37 | X19085Y19150D02*
38 | X19085Y19747D01*
39 | X20085Y20643D02*
40 | X20085Y20046D01*
41 | X19585Y20046D01*
42 | X19085Y20046D01*
43 | X19085Y20643D01*
44 | X19585Y20046D02*
45 | X19585Y20444D01*
46 | X19285Y21041D02*
47 | X19085Y21240D01*
48 | X20085Y21240D01*
49 | X20085Y20942D02*
50 | X20085Y21539D01*
51 | X24165Y16462D02*
52 | X25165Y16561D01*
53 | X24765Y16760D01*
54 | X25165Y16959D01*
55 | X24165Y17059D01*
56 | X25165Y17358D02*
57 | X24165Y17358D01*
58 | X25165Y17955D02*
59 | X24165Y17955D01*
60 | X24665Y17358D02*
61 | X24665Y17955D01*
62 | X25165Y18453D02*
63 | X25165Y18652D01*
64 | X24165Y18453D02*
65 | X24165Y18652D01*
66 | X25165Y18552D02*
67 | X24165Y18552D01*
68 | X25165Y19448D02*
69 | X24165Y19448D01*
70 | X24165Y19150D02*
71 | X24165Y19747D01*
72 | X25165Y20643D02*
73 | X25165Y20046D01*
74 | X24665Y20046D01*
75 | X24165Y20046D01*
76 | X24165Y20643D01*
77 | X24665Y20046D02*
78 | X24665Y20444D01*
79 | X24365Y20942D02*
80 | X24165Y21141D01*
81 | X24165Y21340D01*
82 | X24365Y21539D01*
83 | X24465Y21539D01*
84 | X25165Y20942D01*
85 | X25165Y21539D01*
86 | X25065Y21539D01*
87 | X29245Y16462D02*
88 | X30245Y16561D01*
89 | X29845Y16760D01*
90 | X30245Y16959D01*
91 | X29245Y17059D01*
92 | X30245Y17358D02*
93 | X29245Y17358D01*
94 | X30245Y17955D02*
95 | X29245Y17955D01*
96 | X29745Y17358D02*
97 | X29745Y17955D01*
98 | X30245Y18453D02*
99 | X30245Y18652D01*
100 | X29245Y18453D02*
101 | X29245Y18652D01*
102 | X30245Y18552D02*
103 | X29245Y18552D01*
104 | X30245Y19448D02*
105 | X29245Y19448D01*
106 | X29245Y19150D02*
107 | X29245Y19747D01*
108 | X30245Y20643D02*
109 | X30245Y20046D01*
110 | X29745Y20046D01*
111 | X29245Y20046D01*
112 | X29245Y20643D01*
113 | X29745Y20046D02*
114 | X29745Y20444D01*
115 | X29345Y21041D02*
116 | X29245Y21141D01*
117 | X29245Y21340D01*
118 | X29445Y21539D01*
119 | X29645Y21539D01*
120 | X29745Y21439D01*
121 | X29845Y21539D01*
122 | X30045Y21539D01*
123 | X30245Y21340D01*
124 | X30245Y21141D01*
125 | X30145Y21041D01*
126 | X29745Y21141D02*
127 | X29745Y21439D01*
128 | X34325Y16462D02*
129 | X35325Y16561D01*
130 | X34925Y16760D01*
131 | X35325Y16959D01*
132 | X34325Y17059D01*
133 | X35325Y17358D02*
134 | X34325Y17358D01*
135 | X35325Y17955D02*
136 | X34325Y17955D01*
137 | X34825Y17358D02*
138 | X34825Y17955D01*
139 | X35325Y18453D02*
140 | X35325Y18652D01*
141 | X34325Y18453D02*
142 | X34325Y18652D01*
143 | X35325Y18552D02*
144 | X34325Y18552D01*
145 | X35325Y19448D02*
146 | X34325Y19448D01*
147 | X34325Y19150D02*
148 | X34325Y19747D01*
149 | X35325Y20643D02*
150 | X35325Y20046D01*
151 | X34825Y20046D01*
152 | X34325Y20046D01*
153 | X34325Y20643D01*
154 | X34825Y20046D02*
155 | X34825Y20444D01*
156 | X34925Y21539D02*
157 | X34925Y20942D01*
158 | X34325Y21439D01*
159 | X35325Y21439D01*
160 | X35325Y21340D02*
161 | X35325Y21539D01*
162 | X39405Y16462D02*
163 | X40405Y16561D01*
164 | X40005Y16760D01*
165 | X40405Y16959D01*
166 | X39405Y17059D01*
167 | X40405Y17358D02*
168 | X39405Y17358D01*
169 | X40405Y17955D02*
170 | X39405Y17955D01*
171 | X39905Y17358D02*
172 | X39905Y17955D01*
173 | X40405Y18453D02*
174 | X40405Y18652D01*
175 | X39405Y18453D02*
176 | X39405Y18652D01*
177 | X40405Y18552D02*
178 | X39405Y18552D01*
179 | X40405Y19448D02*
180 | X39405Y19448D01*
181 | X39405Y19150D02*
182 | X39405Y19747D01*
183 | X40405Y20643D02*
184 | X40405Y20046D01*
185 | X39905Y20046D01*
186 | X39405Y20046D01*
187 | X39405Y20643D01*
188 | X39905Y20046D02*
189 | X39905Y20444D01*
190 | X39405Y21539D02*
191 | X39405Y20942D01*
192 | X39805Y20942D01*
193 | X39805Y21340D01*
194 | X40005Y21539D01*
195 | X40205Y21539D01*
196 | X40405Y21340D01*
197 | X40405Y20942D01*
198 | X20150Y24604D02*
199 | X19150Y24604D01*
200 | X19150Y25002D01*
201 | X19350Y25201D01*
202 | X19450Y25201D01*
203 | X19650Y25002D01*
204 | X19650Y24604D01*
205 | X19650Y24703D02*
206 | X20150Y25201D01*
207 | X20150Y25898D02*
208 | X20150Y25699D01*
209 | X19950Y25500D01*
210 | X19750Y25500D01*
211 | X19650Y25599D01*
212 | X19550Y25500D01*
213 | X19350Y25500D01*
214 | X19150Y25699D01*
215 | X19150Y25898D01*
216 | X19350Y26097D01*
217 | X19550Y26097D01*
218 | X19650Y25997D01*
219 | X19750Y26097D01*
220 | X19950Y26097D01*
221 | X20150Y25898D01*
222 | X19650Y25599D02*
223 | X19650Y25997D01*
224 | X25230Y24604D02*
225 | X24230Y24604D01*
226 | X24230Y25002D01*
227 | X24430Y25201D01*
228 | X24530Y25201D01*
229 | X24730Y25002D01*
230 | X24730Y24604D01*
231 | X24730Y24703D02*
232 | X25230Y25201D01*
233 | X25030Y25500D02*
234 | X25230Y25699D01*
235 | X25230Y25898D01*
236 | X25030Y26097D01*
237 | X24630Y26097D01*
238 | X24430Y26097D01*
239 | X24230Y25898D01*
240 | X24230Y25699D01*
241 | X24430Y25500D01*
242 | X24630Y25500D01*
243 | X24830Y25699D01*
244 | X24830Y25898D01*
245 | X24630Y26097D01*
246 | X30310Y24156D02*
247 | X29310Y24156D01*
248 | X29310Y24554D01*
249 | X29510Y24753D01*
250 | X29610Y24753D01*
251 | X29810Y24554D01*
252 | X29810Y24156D01*
253 | X29810Y24255D02*
254 | X30310Y24753D01*
255 | X29510Y25151D02*
256 | X29310Y25350D01*
257 | X30310Y25350D01*
258 | X30310Y25052D02*
259 | X30310Y25649D01*
260 | X29510Y25948D02*
261 | X29310Y26147D01*
262 | X29310Y26346D01*
263 | X29510Y26545D01*
264 | X30110Y26545D01*
265 | X30310Y26346D01*
266 | X30310Y26147D01*
267 | X30110Y25948D01*
268 | X29510Y25948D01*
269 | X29510Y26545D02*
270 | X30110Y25948D01*
271 | X35390Y24156D02*
272 | X34390Y24156D01*
273 | X34390Y24554D01*
274 | X34590Y24753D01*
275 | X34690Y24753D01*
276 | X34890Y24554D01*
277 | X34890Y24156D01*
278 | X34890Y24255D02*
279 | X35390Y24753D01*
280 | X34590Y25151D02*
281 | X34390Y25350D01*
282 | X35390Y25350D01*
283 | X35390Y25052D02*
284 | X35390Y25649D01*
285 | X34590Y26047D02*
286 | X34390Y26246D01*
287 | X35390Y26246D01*
288 | X35390Y25948D02*
289 | X35390Y26545D01*
290 | X40470Y24156D02*
291 | X39470Y24156D01*
292 | X39470Y24554D01*
293 | X39670Y24753D01*
294 | X39770Y24753D01*
295 | X39970Y24554D01*
296 | X39970Y24156D01*
297 | X39970Y24255D02*
298 | X40470Y24753D01*
299 | X39670Y25151D02*
300 | X39470Y25350D01*
301 | X40470Y25350D01*
302 | X40470Y25052D02*
303 | X40470Y25649D01*
304 | X39670Y25948D02*
305 | X39470Y26147D01*
306 | X39470Y26346D01*
307 | X39670Y26545D01*
308 | X39770Y26545D01*
309 | X40470Y25948D01*
310 | X40470Y26545D01*
311 | X40370Y26545D01*
312 | X20085Y9738D02*
313 | X19085Y9738D01*
314 | X19085Y10136D01*
315 | X19285Y10335D01*
316 | X19385Y10335D01*
317 | X19585Y10136D01*
318 | X19585Y9738D01*
319 | X19585Y9837D02*
320 | X20085Y10335D01*
321 | X20085Y11231D02*
322 | X20085Y10634D01*
323 | X19585Y10634D01*
324 | X19085Y10634D01*
325 | X19085Y11231D01*
326 | X19585Y10634D02*
327 | X19585Y11032D01*
328 | X20085Y11530D02*
329 | X20085Y11928D01*
330 | X19885Y12127D01*
331 | X19285Y12127D01*
332 | X19085Y11928D01*
333 | X19085Y11530D01*
334 | X19085Y11629D02*
335 | X20085Y11629D01*
336 | X19085Y13023D02*
337 | X19085Y12426D01*
338 | X19485Y12426D01*
339 | X19485Y12824D01*
340 | X19685Y13023D01*
341 | X19885Y13023D01*
342 | X20085Y12824D01*
343 | X20085Y12426D01*
344 | X25165Y9738D02*
345 | X24165Y9738D01*
346 | X24165Y10136D01*
347 | X24365Y10335D01*
348 | X24465Y10335D01*
349 | X24665Y10136D01*
350 | X24665Y9738D01*
351 | X24665Y9837D02*
352 | X25165Y10335D01*
353 | X25165Y11231D02*
354 | X25165Y10634D01*
355 | X24665Y10634D01*
356 | X24165Y10634D01*
357 | X24165Y11231D01*
358 | X24665Y10634D02*
359 | X24665Y11032D01*
360 | X25165Y11530D02*
361 | X25165Y11928D01*
362 | X24965Y12127D01*
363 | X24365Y12127D01*
364 | X24165Y11928D01*
365 | X24165Y11530D01*
366 | X24165Y11629D02*
367 | X25165Y11629D01*
368 | X24765Y13023D02*
369 | X24765Y12426D01*
370 | X24165Y12923D01*
371 | X25165Y12923D01*
372 | X25165Y12824D02*
373 | X25165Y13023D01*
374 | X30245Y9738D02*
375 | X29245Y9738D01*
376 | X29245Y10136D01*
377 | X29445Y10335D01*
378 | X29545Y10335D01*
379 | X29745Y10136D01*
380 | X29745Y9738D01*
381 | X29745Y9837D02*
382 | X30245Y10335D01*
383 | X30245Y11231D02*
384 | X30245Y10634D01*
385 | X29745Y10634D01*
386 | X29245Y10634D01*
387 | X29245Y11231D01*
388 | X29745Y10634D02*
389 | X29745Y11032D01*
390 | X30245Y11530D02*
391 | X30245Y11928D01*
392 | X30045Y12127D01*
393 | X29445Y12127D01*
394 | X29245Y11928D01*
395 | X29245Y11530D01*
396 | X29245Y11629D02*
397 | X30245Y11629D01*
398 | X29345Y12525D02*
399 | X29245Y12625D01*
400 | X29245Y12824D01*
401 | X29445Y13023D01*
402 | X29645Y13023D01*
403 | X29745Y12923D01*
404 | X29845Y13023D01*
405 | X30045Y13023D01*
406 | X30245Y12824D01*
407 | X30245Y12625D01*
408 | X30145Y12525D01*
409 | X29745Y12625D02*
410 | X29745Y12923D01*
411 | X35325Y9738D02*
412 | X34325Y9738D01*
413 | X34325Y10136D01*
414 | X34525Y10335D01*
415 | X34625Y10335D01*
416 | X34825Y10136D01*
417 | X34825Y9738D01*
418 | X34825Y9837D02*
419 | X35325Y10335D01*
420 | X35325Y11231D02*
421 | X35325Y10634D01*
422 | X34825Y10634D01*
423 | X34325Y10634D01*
424 | X34325Y11231D01*
425 | X34825Y10634D02*
426 | X34825Y11032D01*
427 | X35325Y11530D02*
428 | X35325Y11928D01*
429 | X35125Y12127D01*
430 | X34525Y12127D01*
431 | X34325Y11928D01*
432 | X34325Y11530D01*
433 | X34325Y11629D02*
434 | X35325Y11629D01*
435 | X34525Y12426D02*
436 | X34325Y12625D01*
437 | X34325Y12824D01*
438 | X34525Y13023D01*
439 | X34625Y13023D01*
440 | X35325Y12426D01*
441 | X35325Y13023D01*
442 | X35225Y13023D01*
443 | X40405Y9738D02*
444 | X39405Y9738D01*
445 | X39405Y10136D01*
446 | X39605Y10335D01*
447 | X39705Y10335D01*
448 | X39905Y10136D01*
449 | X39905Y9738D01*
450 | X39905Y9837D02*
451 | X40405Y10335D01*
452 | X40405Y11231D02*
453 | X40405Y10634D01*
454 | X39905Y10634D01*
455 | X39405Y10634D01*
456 | X39405Y11231D01*
457 | X39905Y10634D02*
458 | X39905Y11032D01*
459 | X40405Y11530D02*
460 | X40405Y11928D01*
461 | X40205Y12127D01*
462 | X39605Y12127D01*
463 | X39405Y11928D01*
464 | X39405Y11530D01*
465 | X39405Y11629D02*
466 | X40405Y11629D01*
467 | X39605Y12525D02*
468 | X39405Y12724D01*
469 | X40405Y12724D01*
470 | X40405Y12426D02*
471 | X40405Y13023D01*
472 | X20150Y4284D02*
473 | X19150Y4284D01*
474 | X19150Y4682D01*
475 | X19350Y4881D01*
476 | X19450Y4881D01*
477 | X19650Y4682D01*
478 | X19650Y4284D01*
479 | X19650Y4383D02*
480 | X20150Y4881D01*
481 | X19150Y5677D02*
482 | X19150Y5379D01*
483 | X19350Y5180D01*
484 | X19750Y5180D01*
485 | X19950Y5180D01*
486 | X20150Y5379D01*
487 | X20150Y5578D01*
488 | X19950Y5777D01*
489 | X19750Y5777D01*
490 | X19550Y5578D01*
491 | X19550Y5379D01*
492 | X19750Y5180D01*
493 | X25230Y4284D02*
494 | X24230Y4284D01*
495 | X24230Y4682D01*
496 | X24430Y4881D01*
497 | X24530Y4881D01*
498 | X24730Y4682D01*
499 | X24730Y4284D01*
500 | X24730Y4383D02*
501 | X25230Y4881D01*
502 | X24230Y5777D02*
503 | X24230Y5180D01*
504 | X24630Y5180D01*
505 | X24630Y5578D01*
506 | X24830Y5777D01*
507 | X25030Y5777D01*
508 | X25230Y5578D01*
509 | X25230Y5180D01*
510 | X30310Y4284D02*
511 | X29310Y4284D01*
512 | X29310Y4682D01*
513 | X29510Y4881D01*
514 | X29610Y4881D01*
515 | X29810Y4682D01*
516 | X29810Y4284D01*
517 | X29810Y4383D02*
518 | X30310Y4881D01*
519 | X29910Y5777D02*
520 | X29910Y5180D01*
521 | X29310Y5677D01*
522 | X30310Y5677D01*
523 | X30310Y5578D02*
524 | X30310Y5777D01*
525 | X35390Y4284D02*
526 | X34390Y4284D01*
527 | X34390Y4682D01*
528 | X34590Y4881D01*
529 | X34690Y4881D01*
530 | X34890Y4682D01*
531 | X34890Y4284D01*
532 | X34890Y4383D02*
533 | X35390Y4881D01*
534 | X34490Y5279D02*
535 | X34390Y5379D01*
536 | X34390Y5578D01*
537 | X34590Y5777D01*
538 | X34790Y5777D01*
539 | X34890Y5677D01*
540 | X34990Y5777D01*
541 | X35190Y5777D01*
542 | X35390Y5578D01*
543 | X35390Y5379D01*
544 | X35290Y5279D01*
545 | X34890Y5379D02*
546 | X34890Y5677D01*
547 | X40470Y4284D02*
548 | X39470Y4284D01*
549 | X39470Y4682D01*
550 | X39670Y4881D01*
551 | X39770Y4881D01*
552 | X39970Y4682D01*
553 | X39970Y4284D01*
554 | X39970Y4383D02*
555 | X40470Y4881D01*
556 | X39670Y5180D02*
557 | X39470Y5379D01*
558 | X39470Y5578D01*
559 | X39670Y5777D01*
560 | X39770Y5777D01*
561 | X40470Y5180D01*
562 | X40470Y5777D01*
563 | X40370Y5777D01*
564 | X13600Y20159D02*
565 | X13800Y20358D01*
566 | X13800Y20557D01*
567 | X13600Y20756D01*
568 | X13000Y20756D01*
569 | X12800Y20557D01*
570 | X12800Y20358D01*
571 | X13000Y20159D01*
572 | X13600Y20159D01*
573 | X13600Y20557D02*
574 | X13800Y20756D01*
575 | X13000Y21055D02*
576 | X12800Y21254D01*
577 | X12800Y21453D01*
578 | X13000Y21652D01*
579 | X13100Y21652D01*
580 | X13800Y21055D01*
581 | X13800Y21652D01*
582 | X13700Y21652D01*
583 | X13800Y8094D02*
584 | X12800Y8094D01*
585 | X12800Y8492D01*
586 | X13000Y8691D01*
587 | X13100Y8691D01*
588 | X13300Y8492D01*
589 | X13300Y8094D01*
590 | X13300Y8193D02*
591 | X13800Y8691D01*
592 | X13800Y9288D02*
593 | X13300Y9288D01*
594 | X13000Y9587D01*
595 | X12800Y9587D01*
596 | X12800Y8990D01*
597 | X13000Y8990D01*
598 | X44280Y20794D02*
599 | X43280Y20794D01*
600 | X43280Y21192D01*
601 | X43480Y21391D01*
602 | X43580Y21391D01*
603 | X43780Y21192D01*
604 | X43780Y20794D01*
605 | X43780Y20893D02*
606 | X44280Y21391D01*
607 | X43480Y21789D02*
608 | X43280Y21988D01*
609 | X44280Y21988D01*
610 | X44280Y21690D02*
611 | X44280Y22287D01*
612 | X44080Y8729D02*
613 | X44280Y8928D01*
614 | X44280Y9127D01*
615 | X44080Y9326D01*
616 | X43480Y9326D01*
617 | X43280Y9127D01*
618 | X43280Y8928D01*
619 | X43480Y8729D01*
620 | X44080Y8729D01*
621 | X44080Y9127D02*
622 | X44280Y9326D01*
623 | X43480Y9724D02*
624 | X43280Y9923D01*
625 | X44280Y9923D01*
626 | X44280Y9625D02*
627 | X44280Y10222D01*
628 | X7020Y11082D02*
629 | X8020Y11181D01*
630 | X7620Y11380D01*
631 | X8020Y11579D01*
632 | X7020Y11679D01*
633 | X7520Y14020D02*
634 | X7520Y14219D01*
635 | X7820Y14219D01*
636 | X8020Y14020D01*
637 | X8020Y13821D01*
638 | X7820Y13622D01*
639 | X7220Y13622D01*
640 | X7020Y13821D01*
641 | X7020Y14219D01*
642 | X8020Y15714D02*
643 | X7020Y15714D01*
644 | X7020Y16112D01*
645 | X7220Y16311D01*
646 | X7320Y16311D01*
647 | X7520Y16112D01*
648 | X7520Y15714D01*
649 | X7520Y15813D02*
650 | X8020Y16311D01*
651 | X7020Y18851D02*
652 | X7020Y18254D01*
653 | X7420Y18254D01*
654 | X7420Y18652D01*
655 | X7620Y18851D01*
656 | X7820Y18851D01*
657 | X8020Y18652D01*
658 | X8020Y18254D01*
659 | X7020Y19150D02*
660 | X8020Y19448D01*
661 | X7020Y19747D01*
662 | X47660Y11231D02*
663 | X47660Y10634D01*
664 | X48060Y10634D01*
665 | X48060Y11032D01*
666 | X48260Y11231D01*
667 | X48460Y11231D01*
668 | X48660Y11032D01*
669 | X48660Y10634D01*
670 | X47660Y11530D02*
671 | X48660Y11828D01*
672 | X47660Y12127D01*
673 | X48660Y13174D02*
674 | X47660Y13174D01*
675 | X47660Y13572D01*
676 | X47860Y13771D01*
677 | X47960Y13771D01*
678 | X48160Y13572D01*
679 | X48160Y13174D01*
680 | X48160Y13273D02*
681 | X48660Y13771D01*
682 | X48160Y16560D02*
683 | X48160Y16759D01*
684 | X48460Y16759D01*
685 | X48660Y16560D01*
686 | X48660Y16361D01*
687 | X48460Y16162D01*
688 | X47860Y16162D01*
689 | X47660Y16361D01*
690 | X47660Y16759D01*
691 | X47660Y18702D02*
692 | X48660Y18801D01*
693 | X48260Y19000D01*
694 | X48660Y19199D01*
695 | X47660Y19299D01*
696 | G54D12*
697 | X18780Y21550D02*
698 | X16780Y21550D01*
699 | X16780Y16550D02*
700 | X18780Y16550D01*
701 | X16780Y18300D02*
702 | X16780Y16550D01*
703 | X18780Y16550D02*
704 | X18780Y18300D01*
705 | X16780Y21550D02*
706 | X16780Y19800D01*
707 | X18780Y21550D02*
708 | X18780Y19800D01*
709 | X23860Y21550D02*
710 | X21860Y21550D01*
711 | X21860Y16550D02*
712 | X23860Y16550D01*
713 | X21860Y18300D02*
714 | X21860Y16550D01*
715 | X23860Y16550D02*
716 | X23860Y18300D01*
717 | X21860Y21550D02*
718 | X21860Y19800D01*
719 | X23860Y21550D02*
720 | X23860Y19800D01*
721 | X28940Y21550D02*
722 | X26940Y21550D01*
723 | X26940Y16550D02*
724 | X28940Y16550D01*
725 | X26940Y18300D02*
726 | X26940Y16550D01*
727 | X28940Y16550D02*
728 | X28940Y18300D01*
729 | X26940Y21550D02*
730 | X26940Y19800D01*
731 | X28940Y21550D02*
732 | X28940Y19800D01*
733 | X34020Y21550D02*
734 | X32020Y21550D01*
735 | X32020Y16550D02*
736 | X34020Y16550D01*
737 | X32020Y18300D02*
738 | X32020Y16550D01*
739 | X34020Y16550D02*
740 | X34020Y18300D01*
741 | X32020Y21550D02*
742 | X32020Y19800D01*
743 | X34020Y21550D02*
744 | X34020Y19800D01*
745 | X39100Y21550D02*
746 | X37100Y21550D01*
747 | X37100Y16550D02*
748 | X39100Y16550D01*
749 | X37100Y18300D02*
750 | X37100Y16550D01*
751 | X39100Y16550D02*
752 | X39100Y18300D01*
753 | X37100Y21550D02*
754 | X37100Y19800D01*
755 | X39100Y21550D02*
756 | X39100Y19800D01*
757 | X16780Y8930D02*
758 | X18780Y8930D01*
759 | X18780Y13930D02*
760 | X16780Y13930D01*
761 | X18780Y12180D02*
762 | X18780Y13930D01*
763 | X16780Y13930D02*
764 | X16780Y12180D01*
765 | X18780Y8930D02*
766 | X18780Y10680D01*
767 | X16780Y8930D02*
768 | X16780Y10680D01*
769 | X21860Y8930D02*
770 | X23860Y8930D01*
771 | X23860Y13930D02*
772 | X21860Y13930D01*
773 | X23860Y12180D02*
774 | X23860Y13930D01*
775 | X21860Y13930D02*
776 | X21860Y12180D01*
777 | X23860Y8930D02*
778 | X23860Y10680D01*
779 | X21860Y8930D02*
780 | X21860Y10680D01*
781 | X26940Y8930D02*
782 | X28940Y8930D01*
783 | X28940Y13930D02*
784 | X26940Y13930D01*
785 | X28940Y12180D02*
786 | X28940Y13930D01*
787 | X26940Y13930D02*
788 | X26940Y12180D01*
789 | X28940Y8930D02*
790 | X28940Y10680D01*
791 | X26940Y8930D02*
792 | X26940Y10680D01*
793 | X32020Y8930D02*
794 | X34020Y8930D01*
795 | X34020Y13930D02*
796 | X32020Y13930D01*
797 | X34020Y12180D02*
798 | X34020Y13930D01*
799 | X32020Y13930D02*
800 | X32020Y12180D01*
801 | X34020Y8930D02*
802 | X34020Y10680D01*
803 | X32020Y8930D02*
804 | X32020Y10680D01*
805 | X37100Y8930D02*
806 | X39100Y8930D01*
807 | X39100Y13930D02*
808 | X37100Y13930D01*
809 | X39100Y12180D02*
810 | X39100Y13930D01*
811 | X37100Y13930D02*
812 | X37100Y12180D01*
813 | X39100Y8930D02*
814 | X39100Y10680D01*
815 | X37100Y8930D02*
816 | X37100Y10680D01*
817 | G54D13*
818 | X17180Y22050D02*
819 | X18380Y22050D01*
820 | X22260Y22050D02*
821 | X23460Y22050D01*
822 | X27340Y22050D02*
823 | X28540Y22050D01*
824 | X32420Y22050D02*
825 | X33620Y22050D01*
826 | X37500Y22050D02*
827 | X38700Y22050D01*
828 | X18380Y8430D02*
829 | X17180Y8430D01*
830 | X23460Y8430D02*
831 | X22260Y8430D01*
832 | X28540Y8430D02*
833 | X27340Y8430D01*
834 | X33620Y8430D02*
835 | X32420Y8430D01*
836 | X38700Y8430D02*
837 | X37500Y8430D01*
838 | G54D14*
839 | X18580Y24800D02*
840 | X18580Y26000D01*
841 | X16980Y24800D02*
842 | X16980Y26000D01*
843 | X16980Y24800D02*
844 | X16980Y26000D01*
845 | X23660Y24800D02*
846 | X23660Y26000D01*
847 | X22060Y24800D02*
848 | X22060Y26000D01*
849 | X22060Y24800D02*
850 | X22060Y26000D01*
851 | X28740Y24800D02*
852 | X28740Y26000D01*
853 | X27140Y24800D02*
854 | X27140Y26000D01*
855 | X27140Y24800D02*
856 | X27140Y26000D01*
857 | X33820Y24800D02*
858 | X33820Y26000D01*
859 | X32220Y24800D02*
860 | X32220Y26000D01*
861 | X32220Y24800D02*
862 | X32220Y26000D01*
863 | X38900Y24800D02*
864 | X38900Y26000D01*
865 | X37300Y24800D02*
866 | X37300Y26000D01*
867 | X37300Y24800D02*
868 | X37300Y26000D01*
869 | X16980Y5680D02*
870 | X16980Y4480D01*
871 | X18580Y5680D02*
872 | X18580Y4480D01*
873 | X18580Y5680D02*
874 | X18580Y4480D01*
875 | X22060Y5680D02*
876 | X22060Y4480D01*
877 | X23660Y5680D02*
878 | X23660Y4480D01*
879 | X23660Y5680D02*
880 | X23660Y4480D01*
881 | X27140Y5680D02*
882 | X27140Y4480D01*
883 | X28740Y5680D02*
884 | X28740Y4480D01*
885 | X28740Y5680D02*
886 | X28740Y4480D01*
887 | X32220Y5680D02*
888 | X32220Y4480D01*
889 | X33820Y5680D02*
890 | X33820Y4480D01*
891 | X33820Y5680D02*
892 | X33820Y4480D01*
893 | X37300Y5680D02*
894 | X37300Y4480D01*
895 | X38900Y5680D02*
896 | X38900Y4480D01*
897 | X38900Y5680D02*
898 | X38900Y4480D01*
899 | X14150Y17480D02*
900 | X14150Y18080D01*
901 | X11250Y18080D02*
902 | X11250Y17480D01*
903 | X14150Y17480D01*
904 | X14150Y18080D02*
905 | X11250Y18080D01*
906 | X12700Y10880D02*
907 | X12700Y11980D01*
908 | X12700Y10880D02*
909 | X12700Y11980D01*
910 | X43180Y19600D02*
911 | X43180Y18500D01*
912 | X43180Y19600D02*
913 | X43180Y18500D01*
914 | X41730Y13000D02*
915 | X41730Y12400D01*
916 | X44630Y12400D02*
917 | X44630Y13000D01*
918 | X41730Y13000D01*
919 | X41730Y12400D02*
920 | X44630Y12400D01*
921 | G54D15*
922 | X10825Y16380D02*
923 | G75*
924 | D01*
925 | G02X10825Y16380I125J0*
926 | G01*
927 | X44805Y14100D02*
928 | G75*
929 | D01*
930 | G02X44805Y14100I125J0*
931 | G01*
932 |
933 | M02*
934 |
--------------------------------------------------------------------------------
/Hardware/LED light setup/LED PCB designs/Design1 - Solder Mask Bottom.gbr:
--------------------------------------------------------------------------------
1 | G04 Generated by Ultiboard 14.0 *
2 | %FSLAX33Y33*%
3 | %MOMM*%
4 |
5 | %ADD10C,0.001*%
6 | %ADD11C,3.300*%
7 | %ADD12C,1.600*%
8 |
9 |
10 | G04 ColorRGB 9900CC for the following layer *
11 | %LNSolder Mask Bottom*%
12 | %LPD*%
13 | G54D10*
14 | G54D11*
15 | X10160Y25400D03*
16 | X10160Y5080D03*
17 | X45720Y25400D03*
18 | X45720Y5080D03*
19 | G54D12*
20 | X5080Y19050D03*
21 | X5080Y13970D03*
22 | X5080Y16510D03*
23 | X5080Y11430D03*
24 | X50800Y16510D03*
25 | X50800Y11430D03*
26 | X50800Y19050D03*
27 | X50800Y13970D03*
28 |
29 | M02*
30 |
--------------------------------------------------------------------------------
/Hardware/LED light setup/LED PCB designs/Design1 - Solder Mask Top.gbr:
--------------------------------------------------------------------------------
1 | G04 Generated by Ultiboard 14.0 *
2 | %FSLAX33Y33*%
3 | %MOMM*%
4 |
5 | %ADD10C,0.001*%
6 | %ADD11C,3.300*%
7 | %ADD12R,1.500X1.500*%
8 | %ADD13R,1.750X1.050*%
9 | %ADD14R,0.600X1.050*%
10 | %ADD15R,1.050X1.400*%
11 | %ADD16C,1.600*%
12 |
13 |
14 | G04 ColorRGB FF00CC for the following layer *
15 | %LNSolder Mask Top*%
16 | %LPD*%
17 | G54D10*
18 | G54D11*
19 | X10160Y25400D03*
20 | X10160Y5080D03*
21 | X45720Y25400D03*
22 | X45720Y5080D03*
23 | G54D12*
24 | X17780Y20600D03*
25 | X17780Y17500D03*
26 | X22860Y20600D03*
27 | X22860Y17500D03*
28 | X27940Y20600D03*
29 | X27940Y17500D03*
30 | X33020Y20600D03*
31 | X33020Y17500D03*
32 | X38100Y20600D03*
33 | X38100Y17500D03*
34 | X17780Y12980D03*
35 | X17780Y9880D03*
36 | X22860Y12980D03*
37 | X22860Y9880D03*
38 | X27940Y12980D03*
39 | X27940Y9880D03*
40 | X33020Y12980D03*
41 | X33020Y9880D03*
42 | X38100Y12980D03*
43 | X38100Y9880D03*
44 | G54D13*
45 | X17780Y23900D03*
46 | X17780Y26900D03*
47 | X22860Y23900D03*
48 | X22860Y26900D03*
49 | X27940Y23900D03*
50 | X27940Y26900D03*
51 | X33020Y23900D03*
52 | X33020Y26900D03*
53 | X38100Y23900D03*
54 | X38100Y26900D03*
55 | X17780Y3580D03*
56 | X17780Y6580D03*
57 | X22860Y3580D03*
58 | X22860Y6580D03*
59 | X27940Y3580D03*
60 | X27940Y6580D03*
61 | X33020Y3580D03*
62 | X33020Y6580D03*
63 | X38100Y3580D03*
64 | X38100Y6580D03*
65 | G54D14*
66 | X11750Y16630D03*
67 | X13650Y16630D03*
68 | X12700Y18930D03*
69 | X43180Y11550D03*
70 | X42230Y13850D03*
71 | X44130Y13850D03*
72 | G54D15*
73 | X11750Y11430D03*
74 | X13650Y11430D03*
75 | X42230Y19050D03*
76 | X44130Y19050D03*
77 | G54D16*
78 | X5080Y19050D03*
79 | X5080Y13970D03*
80 | X5080Y16510D03*
81 | X5080Y11430D03*
82 | X50800Y16510D03*
83 | X50800Y11430D03*
84 | X50800Y19050D03*
85 | X50800Y13970D03*
86 |
87 | M02*
88 |
--------------------------------------------------------------------------------
/Hardware/LED light setup/laser cutter/COPYRIGHT NOTICE:
--------------------------------------------------------------------------------
1 | Copyright Gregory Pask, Marcy Kittredge, Owen Meng, and Matt Lamparter 2022.
2 |
3 | This source describes Open Hardware and is licensed under the CERNOHL-S v2.
4 |
5 | You may redistribute and modify this source and make products using it
6 | under the terms of the CERN-OHL-S v2
7 | (https://ohwr.org/cern ohl s v2.txt ).
8 |
9 | This source is distributed WITHOUT ANY EXPRESS OR IMPLIED
10 | WARRANTY, INCLUDING OF MERCHANTABILITY, SATISFACTORY
11 | QUALITY AND FITNESS FOR A PARTICULAR PURPOSE. Please see
12 | the CERN-OHL-S v2 for applicable conditions.
13 |
14 | Source location: https://github.com/gpask/PiSpy
15 |
16 | As per CERN-OHL-S v2 section 4, should You produce hardware based
17 | on this source, You must where practicable maintain the Source Location
18 | visible on the external case of the PiSpy or other products you make using
19 | this source.
20 |
--------------------------------------------------------------------------------
/Hardware/LED light setup/laser cutter/LED diffuser.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
52 |
--------------------------------------------------------------------------------
/Hardware/LICENSE:
--------------------------------------------------------------------------------
1 | CERN Open Hardware Licence Version 2 - Strongly Reciprocal
2 |
3 |
4 | Preamble
5 |
6 | CERN has developed this licence to promote collaboration among
7 | hardware designers and to provide a legal tool which supports the
8 | freedom to use, study, modify, share and distribute hardware designs
9 | and products based on those designs. Version 2 of the CERN Open
10 | Hardware Licence comes in three variants: CERN-OHL-P (permissive); and
11 | two reciprocal licences: CERN-OHL-W (weakly reciprocal) and this
12 | licence, CERN-OHL-S (strongly reciprocal).
13 |
14 | The CERN-OHL-S is copyright CERN 2020. Anyone is welcome to use it, in
15 | unmodified form only.
16 |
17 | Use of this Licence does not imply any endorsement by CERN of any
18 | Licensor or their designs nor does it imply any involvement by CERN in
19 | their development.
20 |
21 |
22 | 1 Definitions
23 |
24 | 1.1 'Licence' means this CERN-OHL-S.
25 |
26 | 1.2 'Compatible Licence' means
27 |
28 | a) any earlier version of the CERN Open Hardware licence, or
29 |
30 | b) any version of the CERN-OHL-S, or
31 |
32 | c) any licence which permits You to treat the Source to which
33 | it applies as licensed under CERN-OHL-S provided that on
34 | Conveyance of any such Source, or any associated Product You
35 | treat the Source in question as being licensed under
36 | CERN-OHL-S.
37 |
38 | 1.3 'Source' means information such as design materials or digital
39 | code which can be applied to Make or test a Product or to
40 | prepare a Product for use, Conveyance or sale, regardless of its
41 | medium or how it is expressed. It may include Notices.
42 |
43 | 1.4 'Covered Source' means Source that is explicitly made available
44 | under this Licence.
45 |
46 | 1.5 'Product' means any device, component, work or physical object,
47 | whether in finished or intermediate form, arising from the use,
48 | application or processing of Covered Source.
49 |
50 | 1.6 'Make' means to create or configure something, whether by
51 | manufacture, assembly, compiling, loading or applying Covered
52 | Source or another Product or otherwise.
53 |
54 | 1.7 'Available Component' means any part, sub-assembly, library or
55 | code which:
56 |
57 | a) is licensed to You as Complete Source under a Compatible
58 | Licence; or
59 |
60 | b) is available, at the time a Product or the Source containing
61 | it is first Conveyed, to You and any other prospective
62 | licensees
63 |
64 | i) as a physical part with sufficient rights and
65 | information (including any configuration and
66 | programming files and information about its
67 | characteristics and interfaces) to enable it either to
68 | be Made itself, or to be sourced and used to Make the
69 | Product; or
70 | ii) as part of the normal distribution of a tool used to
71 | design or Make the Product.
72 |
73 | 1.8 'Complete Source' means the set of all Source necessary to Make
74 | a Product, in the preferred form for making modifications,
75 | including necessary installation and interfacing information
76 | both for the Product, and for any included Available Components.
77 | If the format is proprietary, it must also be made available in
78 | a format (if the proprietary tool can create it) which is
79 | viewable with a tool available to potential licensees and
80 | licensed under a licence approved by the Free Software
81 | Foundation or the Open Source Initiative. Complete Source need
82 | not include the Source of any Available Component, provided that
83 | You include in the Complete Source sufficient information to
84 | enable a recipient to Make or source and use the Available
85 | Component to Make the Product.
86 |
87 | 1.9 'Source Location' means a location where a Licensor has placed
88 | Covered Source, and which that Licensor reasonably believes will
89 | remain easily accessible for at least three years for anyone to
90 | obtain a digital copy.
91 |
92 | 1.10 'Notice' means copyright, acknowledgement and trademark notices,
93 | Source Location references, modification notices (subsection
94 | 3.3(b)) and all notices that refer to this Licence and to the
95 | disclaimer of warranties that are included in the Covered
96 | Source.
97 |
98 | 1.11 'Licensee' or 'You' means any person exercising rights under
99 | this Licence.
100 |
101 | 1.12 'Licensor' means a natural or legal person who creates or
102 | modifies Covered Source. A person may be a Licensee and a
103 | Licensor at the same time.
104 |
105 | 1.13 'Convey' means to communicate to the public or distribute.
106 |
107 |
108 | 2 Applicability
109 |
110 | 2.1 This Licence governs the use, copying, modification, Conveying
111 | of Covered Source and Products, and the Making of Products. By
112 | exercising any right granted under this Licence, You irrevocably
113 | accept these terms and conditions.
114 |
115 | 2.2 This Licence is granted by the Licensor directly to You, and
116 | shall apply worldwide and without limitation in time.
117 |
118 | 2.3 You shall not attempt to restrict by contract or otherwise the
119 | rights granted under this Licence to other Licensees.
120 |
121 | 2.4 This Licence is not intended to restrict fair use, fair dealing,
122 | or any other similar right.
123 |
124 |
125 | 3 Copying, Modifying and Conveying Covered Source
126 |
127 | 3.1 You may copy and Convey verbatim copies of Covered Source, in
128 | any medium, provided You retain all Notices.
129 |
130 | 3.2 You may modify Covered Source, other than Notices, provided that
131 | You irrevocably undertake to make that modified Covered Source
132 | available from a Source Location should You Convey a Product in
133 | circumstances where the recipient does not otherwise receive a
134 | copy of the modified Covered Source. In each case subsection 3.3
135 | shall apply.
136 |
137 | You may only delete Notices if they are no longer applicable to
138 | the corresponding Covered Source as modified by You and You may
139 | add additional Notices applicable to Your modifications.
140 | Including Covered Source in a larger work is modifying the
141 | Covered Source, and the larger work becomes modified Covered
142 | Source.
143 |
144 | 3.3 You may Convey modified Covered Source (with the effect that You
145 | shall also become a Licensor) provided that You:
146 |
147 | a) retain Notices as required in subsection 3.2;
148 |
149 | b) add a Notice to the modified Covered Source stating that You
150 | have modified it, with the date and brief description of how
151 | You have modified it;
152 |
153 | c) add a Source Location Notice for the modified Covered Source
154 | if You Convey in circumstances where the recipient does not
155 | otherwise receive a copy of the modified Covered Source; and
156 |
157 | d) license the modified Covered Source under the terms and
158 | conditions of this Licence (or, as set out in subsection
159 | 8.3, a later version, if permitted by the licence of the
160 | original Covered Source). Such modified Covered Source must
161 | be licensed as a whole, but excluding Available Components
162 | contained in it, which remain licensed under their own
163 | applicable licences.
164 |
165 |
166 | 4 Making and Conveying Products
167 |
168 | You may Make Products, and/or Convey them, provided that You either
169 | provide each recipient with a copy of the Complete Source or ensure
170 | that each recipient is notified of the Source Location of the Complete
171 | Source. That Complete Source is Covered Source, and You must
172 | accordingly satisfy Your obligations set out in subsection 3.3. If
173 | specified in a Notice, the Product must visibly and securely display
174 | the Source Location on it or its packaging or documentation in the
175 | manner specified in that Notice.
176 |
177 |
178 | 5 Research and Development
179 |
180 | You may Convey Covered Source, modified Covered Source or Products to
181 | a legal entity carrying out development, testing or quality assurance
182 | work on Your behalf provided that the work is performed on terms which
183 | prevent the entity from both using the Source or Products for its own
184 | internal purposes and Conveying the Source or Products or any
185 | modifications to them to any person other than You. Any modifications
186 | made by the entity shall be deemed to be made by You pursuant to
187 | subsection 3.2.
188 |
189 |
190 | 6 DISCLAIMER AND LIABILITY
191 |
192 | 6.1 DISCLAIMER OF WARRANTY -- The Covered Source and any Products
193 | are provided 'as is' and any express or implied warranties,
194 | including, but not limited to, implied warranties of
195 | merchantability, of satisfactory quality, non-infringement of
196 | third party rights, and fitness for a particular purpose or use
197 | are disclaimed in respect of any Source or Product to the
198 | maximum extent permitted by law. The Licensor makes no
199 | representation that any Source or Product does not or will not
200 | infringe any patent, copyright, trade secret or other
201 | proprietary right. The entire risk as to the use, quality, and
202 | performance of any Source or Product shall be with You and not
203 | the Licensor. This disclaimer of warranty is an essential part
204 | of this Licence and a condition for the grant of any rights
205 | granted under this Licence.
206 |
207 | 6.2 EXCLUSION AND LIMITATION OF LIABILITY -- The Licensor shall, to
208 | the maximum extent permitted by law, have no liability for
209 | direct, indirect, special, incidental, consequential, exemplary,
210 | punitive or other damages of any character including, without
211 | limitation, procurement of substitute goods or services, loss of
212 | use, data or profits, or business interruption, however caused
213 | and on any theory of contract, warranty, tort (including
214 | negligence), product liability or otherwise, arising in any way
215 | in relation to the Covered Source, modified Covered Source
216 | and/or the Making or Conveyance of a Product, even if advised of
217 | the possibility of such damages, and You shall hold the
218 | Licensor(s) free and harmless from any liability, costs,
219 | damages, fees and expenses, including claims by third parties,
220 | in relation to such use.
221 |
222 |
223 | 7 Patents
224 |
225 | 7.1 Subject to the terms and conditions of this Licence, each
226 | Licensor hereby grants to You a perpetual, worldwide,
227 | non-exclusive, no-charge, royalty-free, irrevocable (except as
228 | stated in subsections 7.2 and 8.4) patent licence to Make, have
229 | Made, use, offer to sell, sell, import, and otherwise transfer
230 | the Covered Source and Products, where such licence applies only
231 | to those patent claims licensable by such Licensor that are
232 | necessarily infringed by exercising rights under the Covered
233 | Source as Conveyed by that Licensor.
234 |
235 | 7.2 If You institute patent litigation against any entity (including
236 | a cross-claim or counterclaim in a lawsuit) alleging that the
237 | Covered Source or a Product constitutes direct or contributory
238 | patent infringement, or You seek any declaration that a patent
239 | licensed to You under this Licence is invalid or unenforceable
240 | then any rights granted to You under this Licence shall
241 | terminate as of the date such process is initiated.
242 |
243 |
244 | 8 General
245 |
246 | 8.1 If any provisions of this Licence are or subsequently become
247 | invalid or unenforceable for any reason, the remaining
248 | provisions shall remain effective.
249 |
250 | 8.2 You shall not use any of the name (including acronyms and
251 | abbreviations), image, or logo by which the Licensor or CERN is
252 | known, except where needed to comply with section 3, or where
253 | the use is otherwise allowed by law. Any such permitted use
254 | shall be factual and shall not be made so as to suggest any kind
255 | of endorsement or implication of involvement by the Licensor or
256 | its personnel.
257 |
258 | 8.3 CERN may publish updated versions and variants of this Licence
259 | which it considers to be in the spirit of this version, but may
260 | differ in detail to address new problems or concerns. New
261 | versions will be published with a unique version number and a
262 | variant identifier specifying the variant. If the Licensor has
263 | specified that a given variant applies to the Covered Source
264 | without specifying a version, You may treat that Covered Source
265 | as being released under any version of the CERN-OHL with that
266 | variant. If no variant is specified, the Covered Source shall be
267 | treated as being released under CERN-OHL-S. The Licensor may
268 | also specify that the Covered Source is subject to a specific
269 | version of the CERN-OHL or any later version in which case You
270 | may apply this or any later version of CERN-OHL with the same
271 | variant identifier published by CERN.
272 |
273 | 8.4 This Licence shall terminate with immediate effect if You fail
274 | to comply with any of its terms and conditions.
275 |
276 | 8.5 However, if You cease all breaches of this Licence, then Your
277 | Licence from any Licensor is reinstated unless such Licensor has
278 | terminated this Licence by giving You, while You remain in
279 | breach, a notice specifying the breach and requiring You to cure
280 | it within 30 days, and You have failed to come into compliance
281 | in all material respects by the end of the 30 day period. Should
282 | You repeat the breach after receipt of a cure notice and
283 | subsequent reinstatement, this Licence will terminate
284 | immediately and permanently. Section 6 shall continue to apply
285 | after any termination.
286 |
287 | 8.6 This Licence shall not be enforceable except by a Licensor
288 | acting as such, and third party beneficiary rights are
289 | specifically excluded.
290 |
--------------------------------------------------------------------------------
/Hardware/Original PiSpy/COPYRIGHT NOTICE:
--------------------------------------------------------------------------------
1 | Copyright Gregory Pask, Marcy Kittredge, and Thomas Thul 2022.
2 |
3 | This source describes Open Hardware and is licensed under the CERNOHL-S v2.
4 |
5 | You may redistribute and modify this source and make products using it
6 | under the terms of the CERN-OHL-S v2
7 | (https://ohwr.org/cern ohl s v2.txt ).
8 |
9 | This source is distributed WITHOUT ANY EXPRESS OR IMPLIED
10 | WARRANTY, INCLUDING OF MERCHANTABILITY, SATISFACTORY
11 | QUALITY AND FITNESS FOR A PARTICULAR PURPOSE. Please see
12 | the CERN-OHL-S v2 for applicable conditions.
13 |
14 | Source location: https://github.com/gpask/PiSpy
15 |
16 | As per CERN-OHL-S v2 section 4, should You produce hardware based
17 | on this source, You must where practicable maintain the Source Location
18 | visible on the external case of the PiSpy or other products you make using
19 | this source.
20 |
--------------------------------------------------------------------------------
/Hardware/Original PiSpy/Camera extension.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gpask/PiSpy/4395658d6053857533d4da31a2e011c20931ea8d/Hardware/Original PiSpy/Camera extension.STL
--------------------------------------------------------------------------------
/Hardware/Original PiSpy/Camera mount.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gpask/PiSpy/4395658d6053857533d4da31a2e011c20931ea8d/Hardware/Original PiSpy/Camera mount.stl
--------------------------------------------------------------------------------
/Hardware/Original PiSpy/Laser Cut Wooden Stand.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
92 |
--------------------------------------------------------------------------------
/Hardware/Original PiSpy/RPi mount.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gpask/PiSpy/4395658d6053857533d4da31a2e011c20931ea8d/Hardware/Original PiSpy/RPi mount.STL
--------------------------------------------------------------------------------
/Hardware/alternative designs/antbox from above/COPYRIGHT NOTICE:
--------------------------------------------------------------------------------
1 | Copyright Gregory Pask, Marcy Kittredge, and Thomas Thul 2022.
2 |
3 | This source describes Open Hardware and is licensed under the CERNOHL-S v2.
4 |
5 | You may redistribute and modify this source and make products using it
6 | under the terms of the CERN-OHL-S v2
7 | (https://ohwr.org/cern ohl s v2.txt ).
8 |
9 | This source is distributed WITHOUT ANY EXPRESS OR IMPLIED
10 | WARRANTY, INCLUDING OF MERCHANTABILITY, SATISFACTORY
11 | QUALITY AND FITNESS FOR A PARTICULAR PURPOSE. Please see
12 | the CERN-OHL-S v2 for applicable conditions.
13 |
14 | Source location: https://github.com/gpask/PiSpy
15 |
16 | As per CERN-OHL-S v2 section 4, should You produce hardware based
17 | on this source, You must where practicable maintain the Source Location
18 | visible on the external case of the PiSpy or other products you make using
19 | this source.
20 |
--------------------------------------------------------------------------------
/Hardware/alternative designs/antbox from above/antbox camera mount.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gpask/PiSpy/4395658d6053857533d4da31a2e011c20931ea8d/Hardware/alternative designs/antbox from above/antbox camera mount.STL
--------------------------------------------------------------------------------
/Hardware/alternative designs/antbox from above/antbox wooden stand 6mm.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
232 |
--------------------------------------------------------------------------------
/Hardware/alternative designs/lid integration with aerial camera and light/COPYRIGHT NOTICE:
--------------------------------------------------------------------------------
1 | Copyright Gregory Pask, Benjamin Morris, and Eamon McMahon 2022.
2 |
3 | This source describes Open Hardware and is licensed under the CERNOHL-S v2.
4 |
5 | You may redistribute and modify this source and make products using it
6 | under the terms of the CERN-OHL-S v2
7 | (https://ohwr.org/cern ohl s v2.txt ).
8 |
9 | This source is distributed WITHOUT ANY EXPRESS OR IMPLIED
10 | WARRANTY, INCLUDING OF MERCHANTABILITY, SATISFACTORY
11 | QUALITY AND FITNESS FOR A PARTICULAR PURPOSE. Please see
12 | the CERN-OHL-S v2 for applicable conditions.
13 |
14 | Source location: https://github.com/gpask/PiSpy
15 |
16 | As per CERN-OHL-S v2 section 4, should You produce hardware based
17 | on this source, You must where practicable maintain the Source Location
18 | visible on the external case of the PiSpy or other products you make using
19 | this source.
20 |
--------------------------------------------------------------------------------
/Hardware/alternative designs/lid integration with aerial camera and light/camera and LED board mount_laser cut.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
160 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/PiSpy User Manual v1.1.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gpask/PiSpy/4395658d6053857533d4da31a2e011c20931ea8d/PiSpy User Manual v1.1.pdf
--------------------------------------------------------------------------------
/PiSpy desktop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gpask/PiSpy/4395658d6053857533d4da31a2e011c20931ea8d/PiSpy desktop.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PiSpy: An Affordable, Accessible, and Flexible Imaging Platform for the Automated Observation of Organismal Biology and Behavior
2 |
3 |
4 |
5 |
6 |
7 | PiSpy has now been published at PLOS One! Check it out [here](https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0276652)\!
8 |
9 | This project is licensed under [GNU General Public License v3.0](https://github.com/gpask/PiSpy/blob/master/LICENSE)\
10 | The hardware is licensed under [CERN-OHL-S v2](https://github.com/gpask/PiSpy/blob/master/Hardware/LICENSE)\
11 |
12 | PiSpy by Benjamin I. Morris, Marcy J. Kittredge, Bea Casey, Owen Meng, André Maia Chagas, Matt Lamparter, Thomas Thul, Gregory M. Pask is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
13 |
14 | 
15 |
16 | \
17 | This project is Open Source Hardware Association certified [OSHWA UID US002095](https://certification.oshwa.org/us002095.html)
18 |
19 |
20 |
21 | **Contents:**
22 | * [Summary](#summary)
23 | * [Overview of the PiSpy](#overview-of-the-pispy)
24 | * [Video and time lapse image recording across various scales](#video-and-time-lapse-image-recording-across-various-scales)
25 | * [Custom setup for monitoring ant behavior](#custom-setup-for-monitoring-ant-behavior)
26 |
27 |
28 | ## Summary
29 | A great deal of understanding can be gleaned from direct observation of
30 | organismal growth, development, and behavior. However, direct
31 | observation can be time consuming and influence the organism through
32 | unintentional stimuli. Additionally, video capturing equipment can often
33 | be prohibitively expensive, difficult to modify to one's specific needs,
34 | and may come with unnecessary features. Here, we describe the PiSpy, a
35 | low-cost, automated video acquisition platform that uses a Raspberry Pi
36 | computer and camera to record video or images at specified time
37 | intervals or when externally triggered. All settings and controls, such
38 | as programmable light cycling, are accessible to users with no
39 | programming experience through an easy-to-use graphical user.
40 | Importantly, the entire PiSpy system can be assembled for less than
41 | \$100 using laser-cut and 3D-printed components. We demonstrate the
42 | broad applications and flexibility of the PiSpy across a range of model
43 | and non-model organisms. Designs, instructions, and code can be accessed
44 | through an online repository, where a global community of PiSpy users
45 | can also contribute their own unique customizations and help grow the
46 | community of open-source research solutions.
47 |
48 | ## Overview of the PiSpy
49 |
50 |
51 |
52 |
53 | Shown above is the base model of the PiSpy for simple image or video
54 | capture (Fig. 1a). A 3D printable holder mounts both the Raspberry Pi
55 | and PiCamera to a laser cut wooden frame, allowing for easy height
56 | adjustment (Fig. 1A-B). The stands on the frame are also reversible, and
57 | a 3D-printed ball and socket mounts the PiCamera, allowing for free
58 | rotation (Fig. 1C). Optionally, the Raspberry Pi computer can connect to
59 | input and/or output components, such as a motion sensor or lighting,
60 | respectively. This entire setup can be assembled for less than \$100, or
61 | cheaper if multiple setups are being bought at once or certain features
62 | are omitted (see Bill of Materials in GitHub. A complete user's guide
63 | and assembly manual can be found in the Supplementary Materials of the
64 | published paper and will also be continually updated on the GitHub
65 | repository (https://github.com/gpask/PiSpy). The GUI for the PiSpy,
66 | written in Python3 using the TKinter package, controls the functionality
67 | of the PiSpy. Features include capture mode, timed or input-triggered
68 | capture, light control, and camera resolution (Fig. 1D). For more
69 | advanced controls, such as changing the default image/video name and
70 | storage location or the specific camera settings, instructions are
71 | written in the user's manual for how to edit these in the code itself.
72 |
73 | ## Video and time lapse image recording across various scales
74 |
75 |
76 | Imaging of 10 *D. melanogaster* larval locomotion on an agar plate
77 | provided sufficient resolution for analysis with the ImageJ image
78 | processing software, as shown in the above video (sped up to 5x speed):
79 |
80 |
81 |
82 |
83 | Video of crayfish behavior when placed in an aquarium allowed for the
84 | observation of subtle movements of the swimmerets and legs, even though
85 | the animals were underwater and being viewed through a plastic
86 | container:
87 |
88 |
89 |
90 |
91 | Automated image capture also makes the PiSpy an effective device for
92 | capturing and visualizing organismal growth over time. Time-lapse
93 | imaging every 5 minutes (and converted to a video at 225 fps) of various beans (*Phaseolus vulgaris*) growing in clear
94 | planters showed detailed root and shoot growth:
95 |
96 |
97 |
98 |
99 | At a smaller scale, imaging every 5 minutes (and converted to a video at 90 fps of the soil bacterium *Bacillus mycoides*
100 | captured the growth and expansion process over time:
101 |
102 |
103 |
104 |
105 | ## Custom setup for monitoring ant behavior
106 |
107 |
108 |
109 |
110 |
111 | The flexibility of the PiSpy allows it to be customized for more
112 | specific research purposes, as shown above. For example, we have used the PiSpy to
113 | monitor the social behaviors in colonies of the Indian jumping ant,
114 | *Harpegnathos saltator*. Because the ants are housed in nestboxes of a
115 | fixed size, we have modified the wooden frame and mount to enclose the
116 | container to allow for easy overhead recording of the colony, as shown in the image above.
117 | To maintain a light-dark cycle for the ants, we used the LED light
118 | control capabilities of the PiSpy to be able to record social behaviors
119 | throughout the day. Custom LED printed circuit boards (PCBs) can be
120 | connected to the general-purpose input output (GPIO) pin of the
121 | Raspberry Pi and allow for the cycling of white and red lighting.
122 |
123 | The sample videos below show the ability of the PiSpy to record animal behavior
124 | in both day and night, with sufficient resolution to capture specific behaviors
125 | such as antennal dueling (asseen in the daytime recording).
126 | In our experiment, the red light is not detected by the ants but allows
127 | for both day and night imaging. Specific camera settings are used to
128 | record in each different lighting conditions to ensure the desirable
129 | imaging quality. We have programmed in default camera settings for day
130 | and night recording, but the user's manual provides instructions for how
131 | to modify these within the PiSpy code.
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 | The GPIO pins of the Raspberry Pi can also be used to trigger image or
140 | video capture with an external sensor, such as a motion sensor or IR
141 | break beam. In our setup (below), an ant disrupts the IR beam as it walks to a
142 | foraging arena, and again when it returns to the main colony. The physical setup is
143 | shown in the image below, including the LEGO contraption to holding the break beam (right side):
144 |
145 |
146 |
147 |
148 | A sample video in which ants return to the main colony carrying crickets is shown below:
149 |
150 |
151 |
152 |
153 | As an alternative to automated recordings at fixed time intervals, triggered recordings such as these
154 | could be used to monitor specific activities, such as feeding patterns
155 | or other behaviors. It is our hope that users will create their own
156 | modifications of the PiSpy hardware and/or software and will share these
157 | for use by other researchers and inspire further customizations,
158 | allowing it to serve as both a general use tool and one that can be
159 | applied to highly specific experimental approaches.
160 |
161 | Contributors to PiSpy:
162 | Benjamin I. Morris, Marcy J. Kittredge, Bea Casey, Owen Meng, André Maia Chagas, Matt Lamparter, Thomas Thul, Gregory M. Pask
163 |
164 | For this README, all videos were converted to GIF using ezgif.com
165 |
--------------------------------------------------------------------------------
/Software/PiSpy disk image.md:
--------------------------------------------------------------------------------
1 | Click here to download the [PiSpy disk image](https://drive.google.com/file/d/1WO9Z7CKua31OQFlMTX8l0zChpEt_H-ME/view?usp=sharing).
2 |
3 |
--------------------------------------------------------------------------------
/Software/PiSpy/Day_Night_Mode.py:
--------------------------------------------------------------------------------
1 | '''
2 | Class controlling day/night cycling and camera settings
3 | Copyright (C) 2022 Benjamin Morris, Marcy Kittredge, Bea Casey, Gregory Pask
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License version 3 as published by
7 | the Free Software Foundation.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 | '''
17 |
18 | from datetime import datetime
19 | from picamera import PiCamera
20 | from time import sleep
21 | from timeit import Timer
22 | from datetime import datetime
23 | import RPi.GPIO as GPIO
24 |
25 |
26 | class Day_Night:
27 |
28 | def camDay(self, cam, resolution): #function for daytime camera settings for image recording
29 | cam.resolution = (resolution) #set resolution of the camera
30 | cam.framerate = 15 #set the framerate of the camera
31 | cam.shutter_speed = 40000 #set the shutter speed of the camera
32 | cam.iso = 200 #set the camera iso (sensitivity of image sensor)
33 |
34 | def cam_day(self, cam, resolution, framerate): #function for daytime camera settings for video recording
35 | cam.resolution = (resolution) #set resolution of the camera
36 | cam.framerate = int(framerate) #set the framerate of the camera
37 | cam.shutter_speed = 40000 #set the shutter speed of the camera
38 | cam.iso = 200 #set the camera iso (sensitivity of image sensor)
39 |
40 | def camNight(self, cam, resolution): #function for nighttime camera settings for image recording
41 | cam.resolution = (resolution) #set resolution of the camera
42 | cam.framerate = 15 #set framerate of the camera
43 | cam.shutter_speed = 40000 #set the shutter speed of the camera
44 | cam.brightness = 43 #decrease brightness of camera (improves nighttime image quality)
45 | cam.contrast = -8 #decrease contrast of camera (improves nighttime image quality)
46 | cam.iso = 800 #set the camera iso (sensitivity of image sensor)
47 |
48 | def cam_night(self, cam, resolution, framerate): #function for nighttime camera settings for video recording
49 | cam.resolution = (resolution) #set resolution of the camera
50 | cam.framerate = int(framerate) #set framerate of the camera
51 | cam.shutter_speed = 40000 #set the shutter speed of the camera
52 | cam.brightness = 43 #decrease brightness of camera (improves nighttime image quality)
53 | cam.contrast = -8 #decrease contrast of camera (improves nighttime image quality)
54 | cam.iso = 800 #set the camera iso (sensitivity of image sensor)
55 |
56 | def light_on(self, RONTime, WONTime, ROFFTime, WOFFTime): #helper function for while the light is on
57 | self.lock = 1; # set lock
58 | myTime = datetime.now().strftime('%H:%M') # get current time in hour:minute format
59 | curRONTime = RONTime #red light
60 | curWONTime = WONTime #white light
61 | curROFFTime = ROFFTime
62 | curWOFFTime = WOFFTime
63 | if myTime == curRONTime: # turn on red light
64 | sleep(1) #camera sleeps for one second
65 | self.redLight('on') #turns red light on
66 | if myTime == curWOFFTime:
67 | self.whiteLight('off') #turns white light off
68 | elif myTime == curWONTime: # turn on white light
69 | sleep(1) #camera sleeps for one second
70 | self.whiteLight('on') #turns white light on
71 | if myTime == curROFFTime:
72 | self.redLight('off') #turns red light off
73 | elif myTime == curWOFFTime: #turn off white light
74 | self.whiteLight('off')
75 | elif myTime == curROFFTime: #turn off red light
76 | self.redLight('off')
77 | else: # keep current light on
78 | pass
79 | self.lock = 0 # release lock
80 |
81 |
82 | def whiteLight(self, key): #sets white light
83 | if key == 'on': #if the function is called to turn light on
84 | GPIO.setmode(GPIO.BCM) #set BCM GPIO numbering (how pins are referenced)
85 | GPIO.setwarnings(False) # disables warnings
86 | GPIO.setup(18,GPIO.OUT) #set GPIO 18 as output (output mode)
87 | GPIO.output(18,GPIO.HIGH) #set to 3.3V
88 | elif key == 'off': #if the function is called to turn light off
89 | GPIO.setmode(GPIO.BCM) #set BCM GPIO numbering (how pins are referenced)
90 | GPIO.setwarnings(False) #disables warnings
91 | GPIO.setup(18,GPIO.OUT) # set GPIO 18 as output (output mode)
92 | GPIO.output(18,GPIO.LOW) #set to 0V
93 |
94 | def redLight(self, key): #sets red light
95 | if key == 'on': #if function is called to turn light on
96 | GPIO.setmode(GPIO.BCM) #set BCM GPIO numbering (how pins are referenced) **CHANGE TO GPIO.BOARD- SAFER**
97 | GPIO.setwarnings(False) #disable warnings
98 | GPIO.setup(14,GPIO.OUT) # set GPIO 14 as output (output mode)
99 | GPIO.output(14,GPIO.HIGH) #set to 3.3V
100 | elif key == 'off': #if function is called to turn light off
101 | GPIO.setmode(GPIO.BCM) #set BCM GPIO numbering (how pins are referenced) **CHANGE TO GPIO.BOARD- SAFER**
102 | GPIO.setwarnings(False) #disable warnings
103 | GPIO.setup(14,GPIO.OUT) #set GPIO as output (output mode)
104 | GPIO.output(14,GPIO.LOW) #set to 0V
--------------------------------------------------------------------------------
/Software/PiSpy/Image.py:
--------------------------------------------------------------------------------
1 | '''
2 | Class that controls image capture for the PiSpy
3 | Copyright (C) 2022 Benjamin Morris, Marcy Kittredge, Bea Casey, Gregory Pask
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License version 3 as published by
7 | the Free Software Foundation.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 | '''
17 |
18 | from datetime import datetime
19 | from time import sleep
20 | from picamera import PiCamera
21 | import RPi.GPIO as GPIO
22 | from Day_Night_Mode import *
23 |
24 |
25 | class Image:
26 |
27 | def image_capture(self, ID, resolution): #captures image, using settings based off which lights are on
28 | cam = PiCamera()
29 | lights = Day_Night() #initiates lights class
30 | GPIO.setmode(GPIO.BCM) #set BCM GPIO numbering (how pins are referenced)
31 | GPIO.setup(18,GPIO.OUT) #tells computer that GPIO pins used for red/white lights are outputs
32 | GPIO.setup(14,GPIO.OUT) #tells computer that GPIO pins used for red/white lights are outputs
33 | GPIO.setwarnings(False) # disables warnings
34 | if GPIO.input(14) == 1: #if red lights are on, use night settings
35 | lights.camNight(cam, resolution)
36 | else: #otherwise, use day settings
37 | lights.camDay(cam, resolution)
38 | timestamp = datetime.now().strftime("%Y_%m_%d_%H_%M_%S") #sets variable for current time (to minutes)
39 | time = datetime.now().strftime("%H:%M:%S") #sets variable for current time (to seconds)
40 | print('image captured at ' + time)
41 | timestamp = ID + timestamp
42 | sleep(2) # sleep for 2 seconds to let camera "warmup"
43 | cam.capture("/home/pi/Pictures/{}.jpg".format(timestamp)) #takes image, saves to specified path with the timestamp as the format
44 | cam.stop_preview() #hides preview window
45 | cam.close() #closes camera
--------------------------------------------------------------------------------
/Software/PiSpy/Import_Trigger.py:
--------------------------------------------------------------------------------
1 | '''
2 | Class for triggered recording of images or videos
3 | Copyright (C) 2022 Benjamin Morris, Marcy Kittredge, Bea Casey, Gregory Pask
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License version 3 as published by
7 | the Free Software Foundation.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 | '''
17 |
18 | from Image import *
19 | from Record import *
20 | from Day_Night_Mode import *
21 | import RPi.GPIO as GPIO
22 | from datetime import datetime
23 | from picamera import PiCamera
24 |
25 | class Import_Trigger: #class for triggered recording
26 |
27 | def timed_delay(self, delay, RONTime, WONTime, ROFFTime, WOFFTime): #function used to check for lights on/off while delay is happening
28 | lights = Day_Night() #initiates lights class
29 | for x in range(delay): #every second for the length of the specified delay, checks if lights need to be switched then sleeps for 1 second
30 | lights.light_on(RONTime, WONTime, ROFFTime, WOFFTime)
31 | sleep(1)
32 |
33 | def image_trigger(self, ID, delay, trigger, duration, RONTime, WONTime, ROFFTime, WOFFTime, resolution): #manages sensing and acquisition of images
34 | z = 0 #counter for how many images have been taken
35 | GPIO.setmode(GPIO.BCM) #set BCM GPIO numbering (how pins are referenced)
36 | GPIO.setwarnings(False) # disables warnings
37 | GPIO.setup(trigger, GPIO.IN) # sets GPIO connected to sensor as an input
38 | lights = Day_Night() #initiates lights class
39 | delay = int(delay[0:2])*60 + int(delay[3:5]) #calculates delay in seconds from input string in hh:mm format
40 | duration = int(duration * 60) #converts duration to minutes
41 | end_mins = int(datetime.now().strftime("%M")) + duration
42 | end_hours = int(end_mins // 60) + int(datetime.now().strftime("%H")) #calculate hour of ending time
43 | end_mins = int(end_mins % 60) #calculates minutes of ending time (along with line 24
44 | days = 0
45 | while end_hours >= 24: #sets number of days during which recording will occur
46 | end_hours = end_hours - 24
47 | days += 1
48 | end_hours = str(end_hours) #recalculates hour of ending time after removing days
49 | if len(end_hours) == 1:
50 | end_hours = '0' + end_hours #reformats hours
51 | end_mins = str(end_mins)
52 | if len(end_mins) == 1:
53 | end_mins = '0' + end_mins #reformats minutes
54 | end_time = end_hours + end_mins #sets end time with correct formatting
55 | cam = PiCamera() #initates PiCamera. Recording is managed here to avoid camera needing to sleep after being triggered
56 | if GPIO.input(14) == 1:# if red light is on, use night settings
57 | lights.camNight(cam, resolution)
58 | else:# otherwise, use day settings
59 | lights.camDay(cam, resolution)
60 | while days >= 0:
61 | if datetime.now().strftime('%H%M') == end_time: #if reaches end time but there are still 1 or more days remaining, decrease days by 1
62 | days = days - 1
63 | self.timed_delay(60, RONTime, WONTime, ROFFTime, WOFFTime) #delays for 1 minute to prevent loop from running again
64 | i = GPIO.input(trigger)
65 | lights.light_on(RONTime, WONTime, ROFFTime, WOFFTime)
66 | x =0
67 | j = 0
68 | while j < 750: #remove this while loop if using motion sensor. For a break beam, the output is 0 when the beam is broken and 1 when it is not, but the output is not consistent when it should be 1. This loop creates a threshold to prevent accidental activation
69 | #print(i) #this line can be helpful to make sure the break beam is working correctly (if uncommented, output should be repeatedly printing 1 until break beam is triggered
70 | x = x + i
71 | j += 1
72 | i = GPIO.input(trigger)
73 | #print(GPIO.input(trigger))
74 | if x==0: #break beam is broken, for motion sensor switch to if i >= 1 (some sensors output a 1 when triggered and some output a 0, for other sensors test the output by uncommenting the above print statement to determine what to use
75 | print('capturing image')
76 | timestamp = datetime.now().strftime("%Y_%m_%d_%H_%M_%S") #sets variable for current time (to seconds)
77 | timestamp = ID + 'image' + str(z).zfill(5) + '_' + timestamp
78 | cam.capture("/home/pi/Pictures/{}.jpg".format(timestamp)) #takes image, saves to specified path with the timestamp as the format
79 | cam.close() #close camera
80 | self.timed_delay(delay, RONTime, WONTime, ROFFTime, WOFFTime) #delays specified amount of time, but still checks if lights need to be switched
81 | cam = PiCamera() #re-opens camera
82 | if GPIO.input(14) == 1:# if red light is on, use night settings
83 | lights.camNight(cam, resolution)
84 | else:# otherwise, use day settings
85 | lights.camDay(cam, resolution)
86 | z += 1
87 | print('ready to capture again')
88 |
89 |
90 | def video_trigger(self, ID, delay, trigger, duration, length, RONTime, WONTime, ROFFTime, WOFFTime, resolution, framerate): #manages sensing and acquisition of videos
91 | z = 0 #counter for how many videos have been recorded
92 | GPIO.setmode(GPIO.BCM) #set BCM GPIO numbering (how pins are referenced)
93 | GPIO.setwarnings(False) # disables warnings
94 | GPIO.setup(trigger, GPIO.IN) # sets GPIO connected to sensor as an input
95 | lights = Day_Night() #initiates lights class
96 | delay = int(delay[0:2])*60 + int(delay[3:5]) #calculates delay in seconds from input string in mm:ss format
97 | length = int(length[0:2])*60 + int(length[3:5]) #calculates video length in seconds from input string in mm:ss format
98 | duration = int(duration * 60) #converts duration to minutes
99 | end_mins = int(datetime.now().strftime("%M")) + duration
100 | end_hours = int(end_mins // 60) + int(datetime.now().strftime("%H")) #calculate hour of ending time
101 | end_mins = int(end_mins % 60)#calculates minutes of ending time (along with line 24
102 | days = 0
103 | while end_hours >= 24: #sets number of days during which recording will occur
104 | end_hours = end_hours - 24
105 | days += 1
106 | end_hours = str(end_hours) #recalculates hour of ending time after removing days
107 | if len(end_hours) == 1:
108 | end_hours = '0' + end_hours #reformats hours
109 | end_mins = str(end_mins)
110 | if len(end_mins) == 1:
111 | end_mins = '0' + end_mins #reformats minutes
112 | end_time = end_hours + end_mins #sets end time with correct formatting
113 | cam = PiCamera() #initates PiCamera. Recording is managed here to avoid camera needing to sleep after being triggered
114 | if GPIO.input(14) == 1: # if red light is on, use night settings
115 | lights.cam_night(cam, resolution, framerate)
116 | else: #otherwise, use day settings
117 | lights.cam_day(cam, resolution, framerate)
118 | while days >= 0:
119 | if datetime.now().strftime('%H%M') == end_time: #if reaches end time but there are still 1 or more days remaining, decrease days by 1
120 | days = days - 1
121 | self.timed_delay(60, RONTime, WONTime, ROFFTime, WOFFTime) #delays for 1 minute to prevent loop from running again
122 | i = GPIO.input(trigger)
123 | lights.light_on(RONTime, WONTime, ROFFTime, WOFFTime)
124 | x =0
125 | j = 0
126 | while j < 750: #remove this while loop if using motion sensor. For a break beam, the output is 0 when the beam is broken and 1 when it is not, but the output is not consistent when it should be 1. This loop creates a threshold to prevent accidental activation
127 | #print(i) #this line can be helpful to make sure the break beam is working correctly (if uncommented, output should be repeatedly printing 1 until break beam is triggered
128 | x = x + i
129 | j += 1
130 | i = GPIO.input(trigger)
131 | if x==0: #break beam is broken, for motion sensor switch to if i >= 1 (some sensors output a 1 when triggered and some output a 0, for other sensors test the output by uncommenting the above print statement to determine what to use
132 | print('capturing video')
133 | timestamp = datetime.now().strftime("%Y_%m_%d_%H_%M_%S") #sets variable for current time (to seconds)
134 | timestamp = ID + 'video' + str(z).zfill(5) + '_' + timestamp
135 | name = "/home/pi/Videos/{}".format(timestamp)
136 | cam.start_recording(name + ".h264".format(timestamp)) #begins recording, saves to specified path with the timestamp as the format
137 | cam.wait_recording(length) #checks for exceptions- if error occurs the recording will stop
138 | cam.stop_recording() #ends the recording. If there is an error it will raise the exception
139 | rate = cam.framerate
140 | cam.close()
141 | print('done recording')
142 | os.system("MP4Box -quiet -add //{name}.h264:fps={rate} //{name}.mp4".format(name = name, rate = rate)) #converts to MP4 using MP4Box. If GPAC cannot be installed, remove this line
143 | os.remove("//{name}.h264".format(name = name)) #removes .h264 file. If GPAC cannot be installed, remove this line
144 | self.timed_delay(delay, RONTime, WONTime, ROFFTime, WOFFTime) #delays specified amount of time, but still checks if lights need to be switched
145 | cam = PiCamera() #re-opens camera
146 | if GPIO.input(14) == 1: # if red light is on, use night settings
147 | lights.cam_night(cam, resolution, framerate)
148 | else: #otherwise, use day settings
149 | lights.cam_day(cam, resolution, framerate)
150 | z += 1
151 | print('ready to record again')
152 |
153 |
154 |
--------------------------------------------------------------------------------
/Software/PiSpy/PiSpy.py:
--------------------------------------------------------------------------------
1 | '''
2 | Class for opening and operating the PiSpy GUI
3 | Copyright (C) 2022 Benjamin Morris, Marcy Kittredge, Bea Casey, Gregory Pask
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License version 3 as published by
7 | the Free Software Foundation.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 | '''
17 |
18 | from tkinter import *
19 | from datetime import datetime
20 | from Time_Lists import *
21 | from Import_Trigger import *
22 | from Image import *
23 | from picamera import PiCamera
24 | import sched
25 | import time as t
26 |
27 | class App:
28 |
29 | def __init__(self, master, title):
30 | self.master = master
31 | self.master.title(title)
32 | self.master.maxsize(2000, 20000)
33 | self.resolution = [1280, 720] #default resolution if none selected
34 | self.framerate = 0 #must be reset if video mode selected
35 | self._setUpDisplay()
36 | self._takeAction()
37 | super(Time_Lists).__init__()
38 |
39 |
40 |
41 | def _takeAction(self):
42 |
43 | def enable_video(): #function to check if video box is checked
44 | if video.get() %2 != 0:#if video box is checked, enable video setting control
45 | self.capture_box.config(state = NORMAL)
46 | self.framerate_box.config(state = NORMAL)
47 | if timedVideoMode.get() %2 != 0: #if timed video selected
48 | self.frequency_box.config(state = NORMAL)
49 | if triggerVideoMode.get() %2 != 0: #if triggered video selected
50 | self.input_trigger_box.config(state = NORMAL)
51 | self.delay_box.config(state = NORMAL)
52 | self.duration_box.config(state = NORMAL)
53 | else: #otherwise, disable video setting controls
54 | self.capture_box.config(state = DISABLED)
55 | self.frequency_box.config(state = DISABLED)
56 | self.duration_box.config(state = DISABLED)
57 | self.input_trigger_box.config(state = DISABLED)
58 | self.delay_box.config(state = DISABLED)
59 | self.framerate_box.config(state = DISABLED)
60 |
61 | video = IntVar() #creates variable to enable video controls
62 | self.video_capture_mode = Checkbutton(self.master, text = "Video Capture Mode", variable=video, command=enable_video) #create video check box
63 | self.video_capture_mode.grid(row=0, column=0, sticky=W) #set location of video check box
64 |
65 | def enable_timed_video(): #checks if timed video selected and enables/disables boxes accordingly
66 | if timedVideoMode.get() %2 != 0 and video.get() %2 != 0:
67 | self.capture_box.config(state = NORMAL)
68 | self.frequency_box.config(state = NORMAL)
69 | self.duration_box.config(state = NORMAL)
70 | else:
71 | self.frequency_box.config(state = DISABLED)
72 |
73 | timedVideoMode = IntVar() #creates variable to enable timed video mode
74 | self.timed_video_capture_mode = Checkbutton(self.master, text = "Timed", variable=timedVideoMode, command=enable_timed_video) #create timed video check box
75 | self.timed_video_capture_mode.grid(row=4, column=0, sticky=W) #set location of timed video check box
76 |
77 | def enable_trigger_video(): #checks if triggered video selected and enables/disables boxes accordingly
78 | if triggerVideoMode.get() %2 != 0 and video.get() %2 != 0:
79 | self.capture_box.config(state = NORMAL)
80 | self.duration_box.config(state = NORMAL)
81 | self.input_trigger_box.config(state = NORMAL)
82 | self.delay_box.config(state = NORMAL)
83 | else:
84 | self.input_trigger_box.config(state = DISABLED)
85 | self.delay_box.config(state = DISABLED)
86 |
87 | triggerVideoMode = IntVar() #creates variable to enable triggered video mode
88 | self.trigger_video_capture_mode = Checkbutton(self.master, text = "Input Trigger", variable=triggerVideoMode, command=enable_trigger_video) #create input trigger video check box
89 | self.trigger_video_capture_mode.grid(row=6, column=0, sticky=W) #set location of triggered video check box
90 |
91 | def enable_image(): #function to check if image mode is selected
92 | if image.get() %2 != 0: #image is selected
93 | if timedImageMode.get() %2 != 0: #timed image is selected
94 | self.i_frequency_box.config(state = NORMAL)
95 | if triggerImageMode.get() %2 != 0: #triggered image is selected
96 | self.i_input_trigger_box.config(state = NORMAL)
97 | self.i_delay_box.config(state = NORMAL)
98 | self.i_duration_box.config(state = NORMAL)
99 | else: #image is not selected
100 | self.i_frequency_box.config(state = DISABLED)
101 | self.i_duration_box.config(state = DISABLED)
102 | self.i_input_trigger_box.config(state = DISABLED)
103 | self.i_delay_box.config(state = DISABLED)
104 |
105 | image = IntVar() #creates variable to enable image mode
106 | self.image_capture_mode = Checkbutton(self.master, text = "Image Capture Mode", variable=image, command=enable_image) #creates check box for image mode
107 | self.image_capture_mode.grid(row=9, column=0, sticky=W) #sets location of image check box
108 |
109 |
110 | def enable_timed_image(): #checks if timed image mode is selected
111 | if timedImageMode.get() %2 != 0 and image.get() %2 != 0:
112 | self.i_frequency_box.config(state = NORMAL)
113 | self.i_duration_box.config(state = NORMAL)
114 | else:
115 | self.i_frequency_box.config(state = DISABLED)
116 |
117 | timedImageMode = IntVar() #creates variable to enable timed image mode
118 | self.timed_image_capture_mode = Checkbutton(self.master, text = "Timed", variable=timedImageMode, command=enable_timed_image) #creates check box for timed image mode
119 | self.timed_image_capture_mode.grid(row=11, column=0, sticky=W) #sets location of check box for timed image mode
120 |
121 | def enable_trigger_image(): #checks if triggered image mode is selected
122 | if triggerImageMode.get() %2 != 0 and image.get() %2 != 0:
123 | self.i_duration_box.config(state = NORMAL)
124 | self.i_input_trigger_box.config(state = NORMAL)
125 | self.i_delay_box.config(state = NORMAL)
126 | else:
127 | self.i_input_trigger_box.config(state = DISABLED)
128 | self.i_delay_box.config(state = DISABLED)
129 |
130 | triggerImageMode = IntVar() #creates variable to enable triggered image mode
131 | self.trigger_video_capture_mode = Checkbutton(self.master, text = "Input Trigger", variable=triggerImageMode, command=enable_trigger_image) #creates check box for triggered image mode
132 | self.trigger_video_capture_mode.grid(row=13, column=0, sticky=W) #sets location of triggered image mode
133 |
134 | def enable_light(): #enables light control boxes if Light Control box is checked
135 | if light.get() % 2 != 0:
136 | self.won_box.config(state = NORMAL)
137 | self.ron_box.config(state = NORMAL)
138 | self.woff_box.config(state = NORMAL)
139 | self.roff_box.config(state = NORMAL)
140 | else:
141 | self.won_box.config(state = DISABLED)
142 | self.ron_box.config(state = DISABLED)
143 | self.woff_box.config(state = DISABLED)
144 | self.roff_box.config(state = DISABLED)
145 |
146 | light = IntVar() #creates variable to enable light control
147 | self.light_control = Checkbutton(self.master, text = "Light Control", variable=light, command=enable_light) #creates check box for light control
148 | self.light_control.grid(row=0, column=4, sticky=W) #positions light control box
149 |
150 | def set_resolution(): #sets camera resolution based on selected box
151 | if resolution1.get() % 2 != 0:
152 | self.resolution = [1920, 1080]
153 | elif resolution2.get() % 2 != 0:
154 | self.resolution = [3280, 2464]
155 | elif resolution3.get() % 2 != 0:
156 | self.resolution = [1640, 1232]
157 | elif resolution4.get() % 2 != 0:
158 | self.resolution = [1640, 922]
159 | elif resolution6.get() % 2 != 0:
160 | self.resolution = [640, 480]
161 | elif resolution5.get() % 2 != 0:
162 | self.resolution = [1280, 720]
163 | else:
164 | self.resolution = [1280, 720]
165 |
166 | resolution1 = IntVar() #along with following lines, creates variables to check for selected resolution
167 | resolution2 = IntVar()
168 | resolution3 = IntVar()
169 | resolution4 = IntVar()
170 | resolution5 = IntVar()
171 | resolution6 = IntVar()
172 |
173 |
174 | self.resolution_description = Label(self.master, text= "Select Camera Resolution:").grid(row = 16, column = 0, sticky = W)
175 | self.resolution1_box = Checkbutton(self.master, text = "1920x1080", variable = resolution1, command = set_resolution).grid(row = 17, column = 0, sticky = W) #along with following lines, creates and sets location of resolution check boxes
176 | self.resolution2_box = Checkbutton(self.master, text = "3280x2464", variable = resolution2, command = set_resolution).grid(row = 18, column = 0, sticky = W)
177 | self.resolution3_box = Checkbutton(self.master, text = "1640x1232", variable = resolution3, command = set_resolution).grid(row = 19, column = 0, sticky = W)
178 | self.resolution4_box = Checkbutton(self.master, text = "1640x922", variable = resolution4, command = set_resolution).grid(row = 17, column = 1, sticky = W)
179 | self.resolution5_box = Checkbutton(self.master, text = "1280x720", variable = resolution5, command = set_resolution).grid(row = 18, column = 1, sticky = W)
180 | self.resolution6_box = Checkbutton(self.master, text = "640x480", variable = resolution6, command = set_resolution).grid(row = 19, column = 1, sticky = W)
181 |
182 | self.framerate_description = Label(self.master, text= "Frame Rate:").grid(row = 2, column = 0, sticky = W)
183 | self.framerate_description1 = Label(self.master, text="(fps)").grid(row=2, column = 2, sticky = W)
184 | self.framerate_box = Entry(self.master, state = DISABLED) #creates framerate selection box
185 | self.framerate_box.grid(row = 2, column = 1, sticky = W) #places framerate selection box
186 |
187 |
188 | times = Time_Lists() #initiates Time_Lists class
189 | lights = Day_Night() #initiates Day_Night class
190 |
191 | def set_on(): #sets screen when recording is started
192 | # disable all buttons and text boxes that can possibly alter program
193 | self.lock = 0 # initialize to free
194 | self.apply_button.config(state=DISABLED)
195 | self.capture_box.config(state=DISABLED)
196 | self.frequency_box.config(state=DISABLED)
197 | self.duration_box.config(state=DISABLED)
198 | time = datetime.now().strftime("%H:%M") # get current system time in hour:minute format
199 | ID = ''
200 | if self.filename_box.get() != '':
201 | ID = self.filename_box.get().replace(" ", "_") + '_'
202 | if timedImageMode.get() == 1 or timedVideoMode.get() == 1: #timed mode selected
203 | if video.get() == 1: #timed video mode selected
204 | self.times = times.createList(time, float(self.duration_box.get()), ((int(self.frequency_box.get()[0:2])*60) + (int(self.frequency_box.get()[3:5])))) # create list of all recording times
205 | self.captureLength = int(self.capture_box.get()[0:2])*60 + int(self.capture_box.get()[3:5]) # record captureLength once initially and store for duration of recordings
206 | elif image.get() == 1: #timed image mode selected
207 | self.image_times = times.createList(time, float(self.i_duration_box.get()), ((int(float(self.i_frequency_box.get()[0:2])*60)) + (int(float(self.i_frequency_box.get()[3:5]))))) # create list of all recording times
208 | RONTime = self.ron_box.get()
209 | WONTime = self.won_box.get()
210 | ROFFTime = self.roff_box.get()
211 | WOFFTime = self.woff_box.get()
212 | if video.get() == 1:
213 | duration = str(self.duration_box.get())
214 | frequency = str(int(self.frequency_box.get()[0:2])*60 + int(self.frequency_box.get()[3:5]))
215 | self.framerate = self.framerate_box.get()
216 | if image.get() == 1:
217 | i_duration = str(self.i_duration_box.get())
218 | i_frequency = str(int(self.i_frequency_box.get()[0:2])*60 + int(self.i_frequency_box.get()[3:5]))
219 | root.destroy() #closes GUI window
220 | if video.get() == 1: #print selected settings
221 | print("Chosen settings:")
222 | print("Timed Video Mode")
223 | print("Clip Length: " + str(self.captureLength) + " seconds")
224 | print("Duration: " + duration + " hours")
225 | print("Frequency: " + frequency + " minutes")
226 | print("Camera Resolution: " + str(self.resolution[0]) + "x" + str(self.resolution[1]))
227 | print("Camera Frame Rate: " + str(self.framerate))
228 | if ID != '':
229 | print("File Identifier: " + ID[:-1])
230 | if WONTime != '':
231 | print('White lights on at ' + WONTime)
232 | if WOFFTime != '':
233 | print('White lights off at ' + WOFFTime)
234 | if RONTime != '':
235 | print('Red lights on at ' + RONTime)
236 | if ROFFTime != '':
237 | print('Red lights off at ' + ROFFTime)
238 | start_length = len(self.times)
239 | while len(self.times) > 0: #run program with selected settings
240 | s = sched.scheduler(t.time, t.sleep)
241 | light_thread = s.enter(.5, 1, lights.light_on(RONTime, WONTime, ROFFTime, WOFFTime))
242 | time_thread = s.enter(20.25, 1, times.checkVidTime(str(ID+'video'+str(start_length-len(self.times)).zfill(5)+'_'), self.captureLength, self.resolution, self.framerate))
243 |
244 |
245 | elif image.get() == 1: #prints selected settings using scheduler
246 | print("Chosen settings:")
247 | print("Timed Image Mode")
248 | print("Duration: " + i_duration + " hours")
249 | print("Frequency: " + i_frequency + " minutes")
250 | print("Camera Resolution: " + str(self.resolution[0]) + "x" + str(self.resolution[1]))
251 | if ID != '':
252 | print("File Identifier: " + ID[:-1])
253 | if WONTime != '':
254 | print('White lights on at ' + WONTime)
255 | if WOFFTime != '':
256 | print('White lights off at ' + WOFFTime)
257 | if RONTime != '':
258 | print('Red lights on at ' + RONTime)
259 | if ROFFTime != '':
260 | print('Red lights off at ' + ROFFTime)
261 | start_length = len(self.image_times)
262 | while len(self.image_times) > 0: #run program with selected settings using scheduler
263 | s = sched.scheduler(t.time, t.sleep)
264 | image_light_thread = s.enter(.5, 1, lights.light_on(RONTime, WONTime, ROFFTime, WOFFTime))
265 | image_time_thread = s.enter(20.25, 1, times.checkImageTime(str(ID+'image'+str(start_length-len(self.image_times)).zfill(5)+'_'), self.resolution))
266 |
267 | elif triggerImageMode.get() == 1 or triggerVideoMode.get() == 1: #triggered mode selected
268 | trigger_mode = Import_Trigger()
269 | if video.get() == 1: #triggered video selected
270 | delay = self.delay_box.get()
271 | input_trigger = int(self.input_trigger_box.get())
272 | duration = int(self.duration_box.get())
273 | length = self.capture_box.get()
274 | RONTime = self.ron_box.get()
275 | WONTime = self.won_box.get()
276 | ROFFTime = self.roff_box.get()
277 | WOFFTime = self.woff_box.get()
278 | self.framerate = int(self.framerate_box.get())
279 | root.destroy() #closes GUI window
280 |
281 | print("Chosen settings:") #print chosen settings
282 | print("Triggered Video Mode")
283 | print("Clip Length: " + str(int(length[0:2])*60 + int(length[3:5])) +" seconds")
284 | print("Duration: " + str(duration) + " hours")
285 | print("Source: GPIO" + str(input_trigger))
286 | print("Delay: " + str(int(delay[0:2])*60 + int(delay[3:5])) + " seconds")
287 | print("Camera Resolution: " + str(self.resolution[0]) + "x" + str(self.resolution[1]))
288 | print("Camera Frame Rate: " + str(self.framerate))
289 | if ID != '':
290 | print("File Identifier: " + ID[:-1])
291 | if WONTime != '':
292 | print('White lights on at ' + WONTime)
293 | if WOFFTime != '':
294 | print('White lights off at ' + WOFFTime)
295 | if RONTime != '':
296 | print('Red lights on at ' + RONTime)
297 | if ROFFTime != '':
298 | print('Red lights off at ' + ROFFTime)
299 |
300 | trigger_mode.video_trigger(ID, delay, input_trigger, duration, length, RONTime, WONTime, ROFFTime, WOFFTime, self.resolution, self.framerate) #run program for triggered video mode
301 |
302 | elif image.get() == 1: #triggered image mode
303 | i_delay = self.i_delay_box.get()
304 | i_input_trigger = int(self.i_input_trigger_box.get())
305 | i_duration = int(self.i_duration_box.get())
306 | RONTime = self.ron_box.get()
307 | WONTime = self.won_box.get()
308 | ROFFTime = self.roff_box.get()
309 | WOFFTime = self.woff_box.get()
310 | root.destroy() #closes GUI window
311 |
312 | print("Chosen settings:") #print chosen settings
313 | print("Triggered Image Mode")
314 | print("Duration: " + str(i_duration) + " hours")
315 | print("Source: GPIO" + str(i_input_trigger))
316 | print("Delay: " + str(int(i_delay[0:2])*60 + int(i_delay[3:5])) + " seconds")
317 | print("Camera Resolution: " + str(self.resolution[0]) + "x" + str(self.resolution[1]))
318 | if ID != '':
319 | print("File Identifier: " + ID[:-1])
320 | if WONTime != '':
321 | print('White lights on at ' + WONTime)
322 | if WOFFTime != '':
323 | print('White lights off at ' + WOFFTime)
324 | if RONTime != '':
325 | print('Red lights on at ' + RONTime)
326 | if ROFFTime != '':
327 | print('Red lights off at ' + ROFFTime)
328 |
329 | trigger_mode.image_trigger(ID, i_delay, i_input_trigger, i_duration, RONTime, WONTime, ROFFTime, WOFFTime, self.resolution) #run program for triggered video mode
330 |
331 |
332 |
333 | self.apply_button = Button(self.master, text = "Run Program", command = set_on) #creates run program button
334 | self.apply_button.grid(row=14, column= 5, sticky=W) #places run program buttom
335 |
336 | self.filename_description1 = Label(self.master, text="File Identifier:").grid(row=13, column = 4, sticky = E)
337 | self.filename_box = Entry(self.master) #creates framerate selection box
338 | self.filename_box.grid(row = 13, column = 5, sticky = W) #places framerate selection box
339 |
340 | # def cancel_program(): #allows for changes to parameters
341 | # # enable all the buttons and boxes disabled when 'Apply' was clicked
342 | # self.capture_box.delete(0, 'end')
343 | # self.frequency_box.delete(0, 'end')
344 | # self.duration_box.delete(0, 'end')
345 | # self.i_frequency_box.delete(0, 'end')
346 | # self.i_duration_box.delete(0, 'end')
347 | # self.won_box.delete(0, 'end')
348 | # self.ron_box.delete(0, 'end')
349 | # self.woff_box.delete(0, 'end')
350 | # self.roff_box.delete(0, 'end')
351 | # self.capture_box.config(state=DISABLED)
352 | # self.frequency_box.config(state=DISABLED)
353 | # self.duration_box.config(state=DISABLED)
354 | # self.i_frequency_box.config(state=DISABLED)
355 | # self.i_duration_box.config(state=DISABLED)
356 | # self.won_box.config(state=DISABLED)
357 | # self.ron_box.config(state=DISABLED)
358 | # self.woff_box.config(state=DISABLED)
359 | # self.roff_box.config(state=DISABLED)
360 | # self.apply_button.config(state=NORMAL)
361 | # self.video_capture_mode.deselect()
362 | # self.image_capture_mode.deselect()
363 | # self.light_control.deselect()
364 | # print("Stop button was pressed")
365 | # #apply_button.cancel(light_on) # cancel apply_button.repeat(500, light_on)
366 | # #apply_button.cancel(checkTime) # cancel apply_button.repeat(500, checkTime)
367 | # lights.whiteLight('off') #turns off light
368 | # lights.redLight('off') #turns off light
369 |
370 | #self.cancel_button = Button(self.master, text = "Reset", command = cancel_program)
371 | #self.cancel_button.grid(row=17, column= 5, sticky=W)
372 |
373 | def test_red_light(): #test the camera//used for preview
374 | lights.redLight('on')
375 |
376 | self.red_light_button = Button(self.master, text = "Red Light On", command = test_red_light)
377 | self.red_light_button.grid(row=6, column = 5, sticky=W)
378 |
379 | def test_white_light(): #test the camera//used for preview
380 | lights.whiteLight('on')
381 |
382 | self.white_light_button = Button(self.master, text = "White Light On", width = 10, command = test_white_light)
383 | self.white_light_button.grid(row=7, column = 5, sticky=W)
384 |
385 | def lights_off(): #turns off lights
386 | lights.whiteLight('off')
387 | lights.redLight('off')
388 |
389 | self.clear_light_button = Button(self.master, text = "Lights Off", width = 10, command = lights_off)
390 | self.clear_light_button.grid(row=8, column = 5, sticky=W)
391 |
392 | def quick_capture(): #function to capture a single image or video
393 | if image.get()%2 != 0: #if image is selected, will take a picture
394 | picture = Image()
395 | ID = ''
396 | if self.filename_box.get() != '':
397 | ID = self.filename_box.get().replace(" ", "_") + '_'
398 | picture.image_capture(ID, self.resolution)
399 | print("picture taken")
400 | elif video.get()%2 != 0: #if video is selected, will take a video
401 | capture_length = int(self.capture_box.get()[0:2])*60 + int(self.capture_box.get()[3:5])
402 | self.framerate = int(self.framerate_box.get())
403 | recording = Record()
404 | ID = ''
405 | if self.filename_box.get() != '':
406 | ID = self.filename_box.get().replace(" ", "_") + '_'
407 | recording.start_record(ID, capture_length, self.resolution, self.framerate)
408 | else: #if none selected, will say so and not record anything
409 | print("no mode selected")
410 |
411 | self.quick_capture_button = Button(self.master, text = "Quick Capture", width = 10, command = quick_capture) #creates button for quick capture
412 | self.quick_capture_button.grid(row=11, column = 5, sticky=W) #places button for quick capture
413 |
414 |
415 |
416 | def test_cam(): #test the camera//used for preview
417 | cam = PiCamera()
418 | if GPIO.input(14) == 1: #if red light is on, use night settings
419 | if self.resolution == [3280,2464]:#3280x2464 doesnt work for preview so scales down to 1640x1232 which has same field of view
420 | lights.camNight(cam, [1640,1232])
421 | else:
422 | lights.camNight(cam, self.resolution)
423 | else:#use day settings
424 | if self.resolution == [3280,2464]:#3280x2464 doesnt work for preview so scales down to 1640x1232 which has same field of view
425 | lights.camDay(cam, [1640,1232])
426 | else:
427 | lights.camDay(cam, self.resolution)
428 | cam.preview_fullscreen=True #preview screen is not fullscreen
429 | cam.preview_window=(950, 220, 640, 480) #sets window size for window
430 | cam.start_preview() #opens preview window
431 | if self.preview_length_box.get() != '':#if a preview length is specified
432 | sleep(int(self.preview_length_box.get())) #camera sleeps for specified number of seconds
433 | else:#if no length specified, default is a 10 second preview
434 | sleep(10)
435 | cam.stop_preview() #closes preview window
436 | cam.close()
437 |
438 | self.preview_button = Button(self.master, text = "Preview Camera", command = test_cam) #creates preview camera button
439 | self.preview_button.grid(row=10, column = 5, sticky=W) #places preview camera button
440 |
441 |
442 | def _setUpDisplay(self): #sets up display, creating and placing remaining buttons
443 | GPIO.setmode(GPIO.BCM) #set BCM GPIO numbering (how pins are referenced)
444 | GPIO.setwarnings(False) # disables warnings
445 | GPIO.setup(18,GPIO.OUT) #set GPIO 18 as output (output mode)
446 | GPIO.setup(14,GPIO.OUT) #set GPIO 14 as output (output mode)
447 |
448 | self.preview_length_description = Label(self.master, text= "Preview Length:").grid(row = 10, column = 6, sticky = W)
449 | self.preview_length_description1 = Label(self.master, text="(seconds)").grid(row=10, column = 8, sticky = W)
450 | self.preview_length_box = Entry(self.master)
451 | self.preview_length_box.grid(row = 10, column = 7, sticky = W)
452 |
453 | self.capture_description = Label(self.master, text= "Video Clip Length:").grid(row = 1, column = 0, sticky = W)
454 | self.timecapture_description = Label(self.master, text="(mm:ss)").grid(row=1, column = 2, sticky = W)
455 |
456 | self.frequency_description = Label(self.master, text = "Video Frequency: every").grid(row = 5, column = 0, sticky = W)
457 | self.timefrequency_description = Label(self.master, text = "(hh:mm)").grid(row = 5, column = 2, sticky = W)
458 |
459 | self.duration_description = Label(self.master, text= "Duration:").grid(row = 3, column = 0, sticky = W)
460 | self.timeduration_description = Label(self.master, text = "(hours)").grid(row = 3, column = 2, sticky = W)
461 |
462 | self.input_description = Label(self.master, text= "Input:").grid(row = 7, column = 0, sticky = W)
463 | self.triggerinput_description = Label(self.master, text = "(GPIO# (BCM))").grid(row = 7, column = 2, sticky = W)
464 |
465 | self.delay_description = Label(self.master, text= "Delay:").grid(row = 8, column = 0, sticky = W)
466 | self.triggerinput_description = Label(self.master, text = "(mm:ss)").grid(row = 8, column = 2, sticky = W)
467 |
468 | self.capture_box = Entry(self.master, state=DISABLED)
469 | self.capture_box.grid(row = 1, column = 1, sticky = W)
470 | self.frequency_box = Entry(self.master, state=DISABLED)
471 | self.frequency_box.grid(row = 5, column = 1, sticky = W)
472 | self.duration_box = Entry(self.master, state=DISABLED)
473 | self.duration_box.grid(row = 3, column = 1, sticky = W)
474 | self.input_trigger_box = Entry(self.master, state=DISABLED)
475 | self.input_trigger_box.grid(row = 7, column = 1, sticky = W)
476 | self.delay_box = Entry(self.master, state=DISABLED)
477 | self.delay_box.grid(row = 8, column = 1, sticky = W)
478 |
479 | self.i_frequency_description = Label(self.master, text = "Image Frequency: every").grid(row = 12, column = 0, sticky = W)
480 | self.i_timefrequency_description = Label(self.master, text = "(hh:mm)").grid(row = 12, column = 2, sticky = W)
481 |
482 | self.i_duration_description = Label(self.master, text= "Duration:").grid(row = 10, column = 0, sticky = W)
483 | self.i_timeduration_description = Label(self.master, text = "(hours)").grid(row = 10, column = 2, sticky = W)
484 |
485 | self.i_input_description = Label(self.master, text= "Input:").grid(row = 14, column = 0, sticky = W)
486 | self.i_triggerinput_description = Label(self.master, text = "(GPIO# (BCM))").grid(row = 14, column = 2, sticky = W)
487 |
488 | self.i_delay_description = Label(self.master, text= "Delay:").grid(row = 15, column = 0, sticky = W)
489 | self.i_triggerinput_description = Label(self.master, text = "(mm:ss)").grid(row = 15, column = 2, sticky = W)
490 |
491 | self.i_frequency_box = Entry(self.master, state=DISABLED)
492 | self.i_frequency_box.grid(row = 12, column = 1, sticky = W)
493 | self.i_duration_box = Entry(self.master, state=DISABLED)
494 | self.i_duration_box.grid(row = 10, column = 1, sticky = W)
495 | self.i_input_trigger_box = Entry(self.master, state=DISABLED)
496 | self.i_input_trigger_box.grid(row = 14, column = 1, sticky = W)
497 | self.i_delay_box = Entry(self.master, state=DISABLED)
498 | self.i_delay_box.grid(row = 15, column = 1, sticky = W)
499 |
500 | self.light_on_text = Label(self.master, text = "Light Start Times:").grid(row=1, column=4, sticky=W)
501 | self.light_off_text = Label(self.master, text = "Light Stop Times:").grid(row=1, column=7, sticky=W)
502 |
503 | self.won_box = Entry(self.master, state=DISABLED)
504 | self.won_box.grid(row = 2, column = 5, sticky=N)
505 | self.won_box_description = Label(self.master, text= "White LED ON").grid(row=2, column=4, sticky=W)
506 | self.timewon_description = Label(self.master, text="(hh:mm)").grid(row=2, column=6, sticky=W)
507 |
508 | self.woff_box = Entry(self.master, state=DISABLED)
509 | self.woff_box.grid(row=2, column=8, sticky= N)
510 | self.woff_box_description = Label(self.master, text= "White LED OFF").grid(row=2, column=7, sticky=W)
511 | self.timewoff_description = Label(self.master, text="(hh:mm)").grid(row=2, column=9, sticky=W)
512 |
513 | self.ron_box = Entry(self.master, state=DISABLED)
514 | self.ron_box.grid(row = 4, column = 5, sticky=N)
515 | self.ron_box_description = Label(self.master, text= "Red LED ON").grid(row=4, column=4, sticky=W)
516 | self.timeron_description = Label(self.master, text="(hh:mm)").grid(row=4, column=6, sticky=W)
517 |
518 | self.roff_box = Entry(self.master, state=DISABLED)
519 | self.roff_box.grid(row=4, column=8, sticky= N)
520 | self.roff_box_description = Label(self.master, text= "Red LED OFF").grid(row=4, column=7, sticky=W)
521 | self.timeroff_description = Label(self.master, text="(hh:mm)").grid(row=4, column=9, sticky=W)
522 |
523 |
524 |
525 | root = Tk()
526 | root.geometry("25000x500")
527 |
528 | app = App(root, "PiSpy Control")
529 | root.mainloop()
530 |
--------------------------------------------------------------------------------
/Software/PiSpy/Record.py:
--------------------------------------------------------------------------------
1 | '''
2 | Class to record videos using the PiSpy
3 | Copyright (C) 2022 Benjamin Morris, Marcy Kittredge, Bea Casey, Gregory Pask
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License version 3 as published by
7 | the Free Software Foundation.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 | '''
17 |
18 | from datetime import datetime
19 | from time import sleep
20 | from picamera import PiCamera
21 | import RPi.GPIO as GPIO
22 | from Day_Night_Mode import *
23 | import os as os
24 |
25 | class Record:
26 |
27 | def start_record(self, ID, captureLength, resolution, framerate): #captures video, using settings based off which lights are on
28 | cam = PiCamera()
29 | GPIO.setmode(GPIO.BCM) #set BCM GPIO numbering (how pins are referenced)
30 | GPIO.setwarnings(False) # disables warnings
31 | GPIO.setup(18,GPIO.OUT) #tells computer that GPIO pins used for red/white lights are outputs
32 | GPIO.setup(14,GPIO.OUT) #tells computer that GPIO pins used for red/white lights are outputs
33 | lights = Day_Night() #initiates lights class
34 | if GPIO.input(14) == 1: #if red lights are on, use night settings
35 | lights.cam_night(cam, resolution, framerate)
36 | else: #otherwise, use day settings
37 | lights.cam_day(cam, resolution, framerate)
38 | timestamp = datetime.now().strftime("%Y_%m_%d_%H_%M_%S") #sets variable for current time (to minutes)
39 | timestamp = ID + timestamp
40 | sleep(2) # sleep for 2 seconds to let camera "warmup"
41 | time = datetime.now().strftime("%H:%M:%S") #sets variable for current time (to seconds)
42 | print("Recording began at " + time) #prints to monitor
43 | name = "/home/pi/Videos/{}".format(timestamp)
44 | cam.start_recording(name + ".h264", bitrate = 6000000) #begins recording, saves to specified path with the timestamp as the format. to manually set the bitrate, replace 6000000 with selected value
45 | cam.wait_recording(captureLength) #checks for exceptions- if error occurs the recording will stop, otherwise records for specified length
46 | cam.stop_recording() #ends the recording. If there is an error it will raise the exception
47 | time = datetime.now().strftime("%H:%M:%S") #sets variable for current time (to seconds)
48 | cam.stop_preview() #hides preview window
49 | rate = cam.framerate
50 | cam.close()
51 | os.system("MP4Box -quiet -add //{name}.h264:fps={rate} //{name}.mp4".format(name = name, rate = rate)) #converts to MP4 using MP4Box. If GPAC cannot be installed, remove this line
52 | os.remove("//{name}.h264".format(name = name)) #removes .h264 file. If GPAC cannot be installed, remove this line
53 | print("Recording is finished!") #prints to monitor
54 |
55 |
56 |
--------------------------------------------------------------------------------
/Software/PiSpy/Time_Lists.py:
--------------------------------------------------------------------------------
1 | '''
2 | Class to generate times at which recording will take place
3 | Copyright (C) 2022 Benjamin Morris, Marcy Kittredge, Bea Casey, Gregory Pask
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License version 3 as published by
7 | the Free Software Foundation.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 | '''
17 |
18 | from Image import *
19 | from Record import *
20 |
21 | class Time_Lists:
22 |
23 | def __init__(self):
24 | self.times = list()
25 | self.image_times = list()
26 | self.captureLength = int()
27 | self.lock = int()
28 | self.duration_min = int()
29 | self.frequency_min = int()
30 |
31 | def createList(self, time, hours, freq): #function to create list of times for recording, freq is in minutes
32 | self.times.append(time) #add initial time to list of times
33 | i = 0 #iterator
34 | currentTime = time #set the time to an iterable variable
35 | while i<((hours*(60/freq)-1)): #while i is less than the number of times recorded
36 | if (int(currentTime[3:]) + freq ) < 60: # if not going to pass xx:59
37 | currentTime = (currentTime[0:2] + ":" + str((int(currentTime[3:]) + freq))) #make the time a string
38 | if len(currentTime[3:]) == 1: #check if minutes is single digit
39 | currentTime = currentTime[0:3] + "0" + currentTime[3] #add zero before single digit
40 | self.times.append(currentTime) #add string to the list of times
41 | else: # add an hour
42 | #print(currentTime)
43 | if (int(currentTime[0:2]) + (int(currentTime[3:]) + freq) // 60) > 23: # if past 24:00
44 | extra = (int(currentTime[0:2]) + (int(currentTime[3:]) + freq) // 60) - 24 #calculates how far into the next day the next time is
45 | if extra > 9: #if next recording is after 10:00
46 | hour = str(extra) + ":"
47 | else:
48 | hour = "0" + str(extra) + ":" #if hours is a single digit, add leading zero for correct formatting
49 | if (int(currentTime[3:]) - (freq // 60) * 60 + freq) >= 60: #if passing 24:00 and minutes also passing xx:59
50 | currentTime = hour + str(int(currentTime[3:]) - 60 - (freq // 60) * 60 + freq) #sets next time
51 | else: #passing 24:00 but not xx:59
52 | currentTime = hour + str(int(currentTime[3:]) - (freq // 60) * 60 + freq) #sets next time
53 | if (len(currentTime)==4): #if the minutes over the hour is under 10 eg 00:66, which would be set as 01:6
54 | currentTime = str((currentTime[0:3])) + "0" + str(int(currentTime[3:])) #set currentTime to be in the new hour with appropriate minutes (in above example, would be 01:06
55 | self.times.append(currentTime) #add time to list of times
56 | else: #if going to pass xx:59 and not going to pass 24:00
57 | currentTime = str(int(currentTime[0:2]) + (int(currentTime[3:]) + freq) // 60) + ":" + str(int(currentTime[3:]) - ((int(currentTime[3:]) + freq) // 60) * 60 + freq) #set currentTime to be in the new hour with appropriate minutes
58 | if currentTime[1] == ":": #if the second index of the time string is a colon add a zero in front of first digit
59 | currentTime = "0" + currentTime #add zero in front of the currentTime
60 | if (len(currentTime)==4): #if the minutes over the hour is under 10 eg 00:66
61 | currentTime = str((currentTime[0:3])) + "0" + str(int(currentTime[3:])) #set currentTime to be in the new hour with appropriate minutes
62 | self.times.append(currentTime) #add this time to the list of recorded times
63 | i += 1 #increment i by 1
64 | #print(self.times) #print the list of times to the monitor
65 | return(self.times) #return it to the computer
66 |
67 |
68 | def checkVidTime(self, ID, captureLength, resolution, framerate): #finds the current time
69 | time = datetime.now().strftime("%H:%M") # get current system time in hour:minute format
70 | if time == self.times[0]: # if current system time is next recording time
71 | del self.times[0] # removes current time from list
72 | while(self.lock == 1): #while light is on
73 | pass;
74 | self.apply_video_program(ID, captureLength, resolution, framerate) #call function to start recording
75 | #print(times)
76 |
77 |
78 | def checkImageTime(self, ID, resolution): #finds the current time
79 | time = datetime.now().strftime("%H:%M") # get current system time in hour:minute format
80 | if time == self.times[0]:
81 | del self.times[0]
82 | while(self.lock==1):
83 | pass;
84 | self.apply_image_program(ID, resolution)
85 |
86 |
87 | def apply_video_program(self, ID, captureLength, resolution, framerate): #helper function to start recording
88 | recording = Record()
89 | picture = Image()
90 | recording.start_record(ID, captureLength, resolution, framerate) #calling start_record function
91 |
92 |
93 | def apply_image_program(self, ID, resolution): #helper function to start recording
94 | picture = Image()
95 | timestamp = datetime.now().strftime("%H:%M") #sets variable for current time (to seconds)
96 | picture.image_capture(ID, resolution)
--------------------------------------------------------------------------------
/okh-PiSpy.yml:
--------------------------------------------------------------------------------
1 | title: PiSpy
2 | description: An Affordable, Accessible, and Flexible Imaging Platform based on a Raspberry
3 | Pi computer and Pi camera
4 | intended-use: Automated Observation of Organismal Biology and Behavior
5 | keywords:
6 | - video recording
7 | - Raspberry Pi
8 | - automated imaging
9 | - null
10 | project-link: https://github.com/gpask/PiSpy
11 | image: https://user-images.githubusercontent.com/64978673/158457158-29e40e41-570e-40ec-b083-b43d4f998991.png
12 | made: true
13 | made-independently: true
14 | license:
15 | hardware: CERN-OHL-1.2
16 | documentation: CC-BY-SA-2.0
17 | software: GPL-3.0-only
18 | licensor:
19 | name: Greg Pask
20 | affiliation: Middlebury College
21 | email: gpask@middlebury.edu
22 | okh-manifest-version: 1.0.0
23 | date-created: 2022-03-22
24 | date-updated: 2022-03-22
25 | manifest-author:
26 | name: Greg Pask
27 | affiliation: Middlebury College
28 | email: gpask@middlebury.edu
29 | manifest-language: en-US
30 | contact:
31 | name: Greg Pask
32 | affiliation: Middlebury College
33 | email: gpask@middlebury.edu
34 | social:
35 | - platform: Twitter
36 | user-handle: G_Pask
37 | contributors:
38 | - name: Benjamin Morris
39 | - name: Marcy Kittredge
40 | - name: Bea Casey
41 | - name: Owen Meng
42 | - name: André Maia Chagas
43 | - name: Matt Lamparter
44 | - name: Thomas Thul
45 | - name: Gregory Pask
46 | version: "1.0"
47 | development-stage: product
48 | documentation-home: https://github.com/gpask/PiSpy
49 |
--------------------------------------------------------------------------------