Skip to content

Commit df70605

Browse files
committed
Make the data logging system more general
- Add support for any device type on any port - Add support for collecting any attributes - Output is in JSON format and includes input data - Separate thread for each port to improve throughput
1 parent 2190067 commit df70605

File tree

3 files changed

+113
-67
lines changed

3 files changed

+113
-67
lines changed

tests/motor/run-direct.json

Lines changed: 0 additions & 22 deletions
This file was deleted.

tests/motor/template.json

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
{ "meta": { "name": "run-direct-test",
2+
"interval": 50,
3+
"max_time": 2200,
4+
"ports": { "outA": { "log_attributes": ["speed", "position", "duty_cycle"],
5+
"device_class": "Motor" },
6+
"outB": { "log_attributes": ["speed", "position", "duty_cycle"],
7+
"device_class": "Motor" },
8+
"outC": { "log_attributes": ["speed", "position", "duty_cycle"],
9+
"device_class": "Motor" }
10+
}
11+
},
12+
"actions": [ { "time": 0, "ports": { "outA": [ { "command": "reset" },
13+
{ "duty_cycle_sp": 0 },
14+
{ "command": "run-direct" } ],
15+
"outB": [ { "command": "reset" },
16+
{ "duty_cycle_sp": 0 },
17+
{ "command": "run-direct" } ],
18+
"outC": [ { "command": "reset" },
19+
{ "duty_cycle_sp": 0 },
20+
{ "command": "run-direct" } ] } },
21+
{ "time": 200, "ports": { "outA": [ { "duty_cycle_sp": 20 } ],
22+
"outB": [ { "duty_cycle_sp": 20 } ],
23+
"outC": [ { "duty_cycle_sp": 20 } ] } },
24+
{ "time": 400, "ports": { "outA": [ { "duty_cycle_sp": 40 } ],
25+
"outB": [ { "duty_cycle_sp": 40 } ],
26+
"outC": [ { "duty_cycle_sp": 40 } ] } },
27+
{ "time": 600, "ports": { "outA": [ { "duty_cycle_sp": 60 } ],
28+
"outB": [ { "duty_cycle_sp": 60 } ],
29+
"outC": [ { "duty_cycle_sp": 60 } ] } },
30+
{ "time": 800, "ports": { "outA": [ { "duty_cycle_sp": 80 } ],
31+
"outB": [ { "duty_cycle_sp": 80 } ],
32+
"outC": [ { "duty_cycle_sp": 80 } ] } },
33+
{ "time": 1000, "ports": { "outA": [ { "duty_cycle_sp": 100 } ],
34+
"outB": [ { "duty_cycle_sp": 100 } ],
35+
"outC": [ { "duty_cycle_sp": 100 } ] } },
36+
{ "time": 1200, "ports": { "outA": [ { "duty_cycle_sp": 80 } ],
37+
"outB": [ { "duty_cycle_sp": 80 } ],
38+
"outC": [ { "duty_cycle_sp": 80 } ] } },
39+
{ "time": 1400, "ports": { "outA": [ { "duty_cycle_sp": 60 } ],
40+
"outB": [ { "duty_cycle_sp": 60 } ],
41+
"outC": [ { "duty_cycle_sp": 60 } ] } },
42+
{ "time": 1600, "ports": { "outA": [ { "duty_cycle_sp": 40 } ],
43+
"outB": [ { "duty_cycle_sp": 40 } ],
44+
"outC": [ { "duty_cycle_sp": 40 } ] } },
45+
{ "time": 1800, "ports": { "outA": [ { "duty_cycle_sp": 20 } ],
46+
"outB": [ { "duty_cycle_sp": 20 } ],
47+
"outC": [ { "duty_cycle_sp": 20 } ] } },
48+
{ "time": 2000, "ports": { "outA": [ { "duty_cycle_sp": 0 } ],
49+
"outB": [ { "duty_cycle_sp": 0 } ],
50+
"outC": [ { "duty_cycle_sp": 0 } ] } }
51+
]
52+
}

tests/motor/test.py

100755100644
Lines changed: 61 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,81 @@
1-
#! /usr/bin/python2.7
2-
31
import json
2+
import argparse
43
import time
4+
import threading
5+
56
import ev3dev.ev3 as ev3
67

7-
def next_commands():
8-
for d in test['data']:
9-
for c in d['commands']:
10-
yield c
8+
parser = argparse.ArgumentParser()
9+
parser.add_argument("infile", help="the name of the input specification")
10+
args = parser.parse_args()
11+
12+
# Log device readings at requested intervals
13+
class LogThread(threading.Thread):
14+
def __init__(self, interval, device, attributes):
15+
super(LogThread, self).__init__()
16+
17+
self.interval = interval
18+
self.device = device
19+
self.attributes = attributes
20+
self.done = threading.Event()
1121

12-
test = json.loads( open( './run-direct.json' ).read() )
22+
def run(self):
23+
tic = time.time()
24+
toc = tic
25+
self.results = []
1326

14-
print test['data'][0]['port']
15-
m = ev3.Motor( test['data'][0]['port'] )
27+
while not self.done.isSet():
28+
now = time.time()
29+
s = ()
30+
for a in self.attributes:
31+
s += ( getattr( self.device, a ), )
32+
self.results.append((now-tic, s))
1633

17-
name = test['meta']['name']
18-
interval = test['meta']['interval']
19-
max_time = test['meta']['max_time']
34+
while .005 > toc - time.time():
35+
toc += self.interval
36+
time.sleep(toc - time.time())
2037

21-
start = time.clock()
22-
end = start + max_time/1000
38+
def join(self, timeout=None):
39+
self.done.set()
40+
super(LogThread, self).join(timeout)
2341

24-
intervals = [x/1000.0 for x in range( 0, max_time, interval )]
2542

26-
now = time.clock()
43+
test = json.loads( open( args.infile ).read() )
2744

28-
commands = next_commands()
45+
device = {}
46+
logs = {}
2947

30-
c = commands.next()
48+
for p,v in test['meta']['ports'].items():
49+
device[p] = getattr( ev3, v['device_class'] )( p )
3150

32-
next_interval = c['time']/1000.0
33-
results = []
51+
logs[p] = LogThread(test['meta']['interval'] * 1e-3,
52+
device[p],
53+
v['log_attributes'] )
54+
logs[p].start()
3455

35-
for i in intervals:
36-
i = i + start
37-
while now < i:
38-
now = time.clock()
39-
if now >= start + next_interval:
40-
print i, next_interval, now
41-
for a in c['attributes']:
42-
for k in a.keys():
43-
print " ", k, " = ", a[k]
44-
setattr(m,k,a[k])
45-
try:
46-
c = commands.next()
47-
next_interval = c['time']/1000.0
48-
except StopIteration:
49-
next_interval = max_time/1000.0
50-
results.append( (now-start, (m.speed, m.position, m.duty_cycle)) )
56+
start = time.time()
57+
end = start + test['meta']['max_time'] * 1e-3
5158

59+
for a in test['actions']:
60+
then = start + a['time'] * 1e-3
61+
while time.time() < then: pass
62+
print a['time']
5263

53-
print 'data = ['
64+
for p,c in a['ports'].items():
65+
print " ", p
66+
for b in c:
67+
for k,v in b.items():
68+
setattr( device[p], k, v )
69+
print " ", k, v
5470

55-
first = True
56-
for r in results:
57-
if first:
58-
print( ' ({0}, ({1}, {2}, {3}))'.format(r[0], r[1][0], r[1][1], r[1][2]))
59-
first = False
60-
else:
61-
print( ' , ({0}, ({1}, {2}, {3}))'.format(r[0], r[1][0], r[1][1], r[1][2]))
71+
while time.time() < end:
72+
pass
6273

63-
print ']'
74+
test['data'] = {}
6475

76+
for p,v in test['meta']['ports'].items():
77+
logs[p].join()
78+
test['data'][p] = logs[p].results
6579

80+
# Add a nice JSON formatter here - maybe?
81+
print json.dumps( test, indent = 4 )

0 commit comments

Comments
 (0)