|
@@ -1,19 +1,44 @@
|
1
|
1
|
from wifi import Wifi
|
2
|
2
|
from config import Config
|
3
|
3
|
from toy import Toy
|
|
4
|
+from log import LogDup
|
4
|
5
|
import random
|
|
6
|
+import time
|
5
|
7
|
from machine import Timer
|
|
8
|
+import os
|
|
9
|
+
|
|
10
|
+stdio_data = LogDup()
|
|
11
|
+os.dupterm(stdio_data)
|
|
12
|
+
|
|
13
|
+print("Initializing CatToy...")
|
|
14
|
+t = Toy()
|
6
|
15
|
|
7
|
16
|
max_laser_power = 0.1
|
8
|
17
|
|
9
|
18
|
limits = [
|
10
|
19
|
# pan_min, pan_max, tilt_min, tilt_max, name
|
11
|
|
- (84, 120, 53, 76, 'office desk, front right')
|
|
20
|
+ (84, 120, 53, 76, '3d printer tower, top'),
|
|
21
|
+ (84, 120, 53, 76, 'office desk, front right'),
|
|
22
|
+ (t.maximum_limits[0], t.maximum_limits[1], t.maximum_limits[2], t.maximum_limits[3], 'maximum'),
|
12
|
23
|
]
|
13
|
24
|
|
|
25
|
+minimumBatteryVoltage = 3.25 * 2.0
|
|
26
|
+maximumBatteryVoltage = 4.2 * 2.0
|
|
27
|
+
|
14
|
28
|
timerRunning = False
|
15
|
29
|
timerData = None
|
16
|
30
|
outlineIndex = 0
|
|
31
|
+buttonSelection = 0
|
|
32
|
+ledPattern = None
|
|
33
|
+patternIndex = 0
|
|
34
|
+patternTime = time.ticks_ms()
|
|
35
|
+buttonTime = None
|
|
36
|
+
|
|
37
|
+repeatTimer = Timer()
|
|
38
|
+buttonTimer = Timer()
|
|
39
|
+ledTimer = Timer()
|
|
40
|
+
|
|
41
|
+random.seed()
|
17
|
42
|
|
18
|
43
|
def buildPage(header, footer):
|
19
|
44
|
html = """<!DOCTYPE html>
|
|
@@ -55,7 +80,11 @@ def buildPage(header, footer):
|
55
|
80
|
<input type="submit" name="s" value="Outline"><br>
|
56
|
81
|
Status: %s
|
57
|
82
|
</form>
|
|
83
|
+ <h2>Status</h2>
|
|
84
|
+ <p><b>Battery:</b> %s
|
58
|
85
|
%s
|
|
86
|
+ <h2>Console</h2>
|
|
87
|
+ <pre>%s</pre>
|
59
|
88
|
</body>
|
60
|
89
|
</html>
|
61
|
90
|
"""
|
|
@@ -70,19 +99,30 @@ def buildPage(header, footer):
|
70
|
99
|
if timerRunning:
|
71
|
100
|
status = "Program in progress"
|
72
|
101
|
|
73
|
|
- page = html % (header, int(max_laser_power * 100.0), sl, status, footer)
|
74
|
|
- return page
|
|
102
|
+ vb = t.getBatteryVoltage()
|
|
103
|
+ pb = (vb - minimumBatteryVoltage) / (maximumBatteryVoltage - minimumBatteryVoltage) * 100.0
|
|
104
|
+ pb = max(min(pb, 100), 0)
|
|
105
|
+ battery = str(vb) + "V (" + str(pb) + "%)"
|
75
|
106
|
|
76
|
|
-random.seed()
|
77
|
|
-t = Toy()
|
|
107
|
+ page = html % (header, int(max_laser_power * 100.0), sl, status, battery, footer, stdio_data.data.decode("utf-8"))
|
|
108
|
+ return page
|
78
|
109
|
|
79
|
110
|
def rootCallback(request):
|
|
111
|
+ pan_min, pan_max, tilt_min, tilt_max = t.maximum_limits
|
80
|
112
|
return buildPage(
|
81
|
113
|
'<p>Welcome to the Cat Toy interface by <a href="https://www.xythobuz.de">xythobuz</a>.</p>',
|
82
|
|
- "<p><b>Limits:</b> tMin={} tMax={} pMin={} pMax={}</p>".format(t.tilt_min, t.tilt_max, t.pan_min, t.pan_max)
|
|
114
|
+ "<p><b>Limits:</b> tMin={} tMax={} pMin={} pMax={}</p>".format(tilt_min, tilt_max, pan_min, pan_max)
|
83
|
115
|
)
|
84
|
116
|
|
85
|
117
|
def servoCallback(request):
|
|
118
|
+ if t.getBatteryVoltage() < minimumBatteryVoltage:
|
|
119
|
+ stopRepeat()
|
|
120
|
+ t.free()
|
|
121
|
+ return buildPage(
|
|
122
|
+ '<p>Error: Battery Voltage too low. <b>Please charge them!</b></p>',
|
|
123
|
+ '<p><a href="/">Back to main page</a></p>'
|
|
124
|
+ )
|
|
125
|
+
|
86
|
126
|
q = request.find("/servos?")
|
87
|
127
|
p1 = request.find("s1=")
|
88
|
128
|
p2 = request.find("s2=")
|
|
@@ -119,6 +159,14 @@ def servoCallback(request):
|
119
|
159
|
)
|
120
|
160
|
|
121
|
161
|
def laserCallback(request):
|
|
162
|
+ if t.getBatteryVoltage() < minimumBatteryVoltage:
|
|
163
|
+ stopRepeat()
|
|
164
|
+ t.free()
|
|
165
|
+ return buildPage(
|
|
166
|
+ '<p>Error: Battery Voltage too low. <b>Please charge them!</b></p>',
|
|
167
|
+ '<p><a href="/">Back to main page</a></p>'
|
|
168
|
+ )
|
|
169
|
+
|
122
|
170
|
value = 0.0
|
123
|
171
|
text = "off"
|
124
|
172
|
|
|
@@ -138,6 +186,14 @@ def laserCallback(request):
|
138
|
186
|
)
|
139
|
187
|
|
140
|
188
|
def randomMoveCallback(request):
|
|
189
|
+ if t.getBatteryVoltage() < minimumBatteryVoltage:
|
|
190
|
+ stopRepeat()
|
|
191
|
+ t.free()
|
|
192
|
+ return buildPage(
|
|
193
|
+ '<p>Error: Battery Voltage too low. <b>Please charge them!</b></p>',
|
|
194
|
+ '<p><a href="/">Back to main page</a></p>'
|
|
195
|
+ )
|
|
196
|
+
|
141
|
197
|
tilt = random.randint(t.tilt_min, t.tilt_max)
|
142
|
198
|
pan = random.randint(t.pan_min, t.pan_max)
|
143
|
199
|
print("random: tilt={} pan={}".format(tilt, pan))
|
|
@@ -170,7 +226,13 @@ def doOutline(pan_min, pan_max, tilt_min, tilt_max, dur):
|
170
|
226
|
t.angle(t.pan, pan)
|
171
|
227
|
|
172
|
228
|
def timerCallback(unused):
|
173
|
|
- global timerRunning, timerData
|
|
229
|
+ global timerRunning, timerData, repeatTimer
|
|
230
|
+
|
|
231
|
+ if t.getBatteryVoltage() < minimumBatteryVoltage:
|
|
232
|
+ print("Abort due to low battery voltage: " + str(t.getBatteryVoltage()))
|
|
233
|
+ stopRepeat()
|
|
234
|
+ t.free()
|
|
235
|
+ return
|
174
|
236
|
|
175
|
237
|
if not timerRunning:
|
176
|
238
|
return
|
|
@@ -193,7 +255,7 @@ def timerCallback(unused):
|
193
|
255
|
doMove(pan_min, pan_max, tilt_min, tilt_max, dur)
|
194
|
256
|
else:
|
195
|
257
|
doOutline(pan_min, pan_max, tilt_min, tilt_max, dur)
|
196
|
|
- tim = Timer(period = dur, mode=Timer.ONE_SHOT, callback = timerCallback)
|
|
258
|
+ repeatTimer.init(period = dur, mode = Timer.ONE_SHOT, callback = timerCallback)
|
197
|
259
|
else:
|
198
|
260
|
timerRunning = False
|
199
|
261
|
t.laser(0.0)
|
|
@@ -215,6 +277,14 @@ def stopRepeat():
|
215
|
277
|
t.laser(0.0)
|
216
|
278
|
|
217
|
279
|
def repeatCallback(request):
|
|
280
|
+ if t.getBatteryVoltage() < minimumBatteryVoltage:
|
|
281
|
+ stopRepeat()
|
|
282
|
+ t.free()
|
|
283
|
+ return buildPage(
|
|
284
|
+ '<p>Error: Battery Voltage too low. <b>Please charge them!</b></p>',
|
|
285
|
+ '<p><a href="/">Back to main page</a></p>'
|
|
286
|
+ )
|
|
287
|
+
|
218
|
288
|
q = request.find("/repeat?")
|
219
|
289
|
pl = request.find("limit=", q)
|
220
|
290
|
ps = request.find("steps=", pl)
|
|
@@ -270,6 +340,63 @@ def repeatCallback(request):
|
270
|
340
|
'<p><a href="/">Back to main page</a></p>'
|
271
|
341
|
)
|
272
|
342
|
|
|
343
|
+def buttonCallback(state):
|
|
344
|
+ global timerRunning, buttonSelection, buttonTime
|
|
345
|
+
|
|
346
|
+ if state:
|
|
347
|
+ buttonTime = time.ticks_ms()
|
|
348
|
+ elif buttonTime != None:
|
|
349
|
+ if time.ticks_diff(time.ticks_ms(), buttonTime) <= 500:
|
|
350
|
+ buttonSelection = (buttonSelection + 1) % len(limits)
|
|
351
|
+ print("Selection: " + str(buttonSelection + 1))
|
|
352
|
+ else:
|
|
353
|
+ if not timerRunning:
|
|
354
|
+ pan_min, pan_max, tilt_min, tilt_max, name = limits[buttonSelection]
|
|
355
|
+ print("Start pattern " + name)
|
|
356
|
+ startRepeat(pan_min, pan_max, tilt_min, tilt_max, 200, 2500, False)
|
|
357
|
+ else:
|
|
358
|
+ print("Stop")
|
|
359
|
+ stopRepeat()
|
|
360
|
+
|
|
361
|
+def ledStatus():
|
|
362
|
+ global timerRunning, buttonSelection, ledPattern, patternIndex, patternTime
|
|
363
|
+ patternMode = False
|
|
364
|
+
|
|
365
|
+ if t.getBatteryVoltage() < minimumBatteryVoltage:
|
|
366
|
+ patternMode = True
|
|
367
|
+ pattern = [ 100, 100 ]
|
|
368
|
+ elif timerRunning:
|
|
369
|
+ t.status(True)
|
|
370
|
+ else:
|
|
371
|
+ patternMode = True
|
|
372
|
+ pattern = [ 300 ] * (buttonSelection * 2 + 1) + [ 1500 ]
|
|
373
|
+
|
|
374
|
+ if patternMode:
|
|
375
|
+ if pattern != ledPattern:
|
|
376
|
+ ledPattern = pattern
|
|
377
|
+ patternIndex = 0
|
|
378
|
+ patternTime = time.ticks_ms()
|
|
379
|
+
|
|
380
|
+ if time.ticks_diff(time.ticks_ms(), patternTime) >= ledPattern[patternIndex]:
|
|
381
|
+ t.status(patternIndex % 2 == 1)
|
|
382
|
+ patternIndex = (patternIndex + 1) % len(ledPattern)
|
|
383
|
+ patternTime = time.ticks_ms()
|
|
384
|
+
|
|
385
|
+def buttonTimerCallback(timer):
|
|
386
|
+ global buttonTimer
|
|
387
|
+ t.poll(buttonCallback)
|
|
388
|
+ buttonTimer.init(period = 25, mode = Timer.ONE_SHOT, callback = buttonTimerCallback)
|
|
389
|
+
|
|
390
|
+def ledTimerCallback(timer):
|
|
391
|
+ global ledTimer
|
|
392
|
+ ledStatus()
|
|
393
|
+ ledTimer.init(period = 100, mode = Timer.ONE_SHOT, callback = ledTimerCallback)
|
|
394
|
+
|
|
395
|
+print("Starting Timers...")
|
|
396
|
+buttonTimerCallback(None)
|
|
397
|
+ledTimerCallback(None)
|
|
398
|
+
|
|
399
|
+print("Initializing WiFi...")
|
273
|
400
|
w = Wifi(Config.ssid, Config.password)
|
274
|
401
|
w.add_handler("/", rootCallback)
|
275
|
402
|
w.add_handler("/servos", servoCallback)
|
|
@@ -277,3 +404,5 @@ w.add_handler("/laser", laserCallback)
|
277
|
404
|
w.add_handler("/random_move", randomMoveCallback)
|
278
|
405
|
w.add_handler("/repeat", repeatCallback)
|
279
|
406
|
w.listen()
|
|
407
|
+
|
|
408
|
+print("Ready!")
|