Commit f6931c106e0ce2b1db0489d276082c8037a15838

Authored by Christopher Stone
1 parent c8b904ce
Exists in master

Many minor changes for pep8 compliance, but inadvertently brok e line plotting. …

…Code runs, but lines do not appear!
robots/little_john/telemetry/code/monitor/version1/colours.py
... ... @@ -2,4 +2,4 @@ WHITE = (255, 255, 255, 255)
2 2 BLACK = (0, 0, 0, 255)
3 3 RED = (255, 0, 0, 255)
4 4 GREEN = (0, 255, 0, 255)
5   -BLUE = (0, 0, 255, 255)
6 5 \ No newline at end of file
  6 +BLUE = (0, 0, 255, 255)
... ...
robots/little_john/telemetry/code/monitor/version1/getdata.py
... ... @@ -6,16 +6,17 @@ import logging
6 6 import os
7 7 import time
8 8 import serial
9   -#from serialselect import selectserial
  9 +
10 10  
11 11 def getData(starttime, datafeed, testseries, testseries2, fake=False):
12 12 """Check serial port for incoming data"""
13 13 # Note: 'elapsed' is time since last call of this function
14   - # This works, but it might be better for performance to have two seperate functions, only one of which is run.
  14 + # This works, but it might be better for performance to have two
  15 + # seperate functions, only one of which is run.
15 16 if fake:
16 17 timefromstart = (time.time()-starttime)
17 18 values = [timefromstart, 100*math.sin(timefromstart)]
18   - #logging.info("Generated test data: " + str(values))
  19 + # logging.info("Generated test data: " + str(values))
19 20 testseries.addpoint(values)
20 21 testseries2.addpoint(values)
21 22 else:
... ... @@ -23,9 +24,9 @@ def getData(starttime, datafeed, testseries, testseries2, fake=False):
23 24 incoming = datafeed.readline()
24 25 except:
25 26 logging.error("Failed to read input data")
26   -
  27 +
27 28 try:
28   - if os=='Windows':
  29 + if os == 'Windows':
29 30 values = incoming.strip().split(b", ")
30 31 else:
31 32 values = incoming.strip()
... ... @@ -33,15 +34,13 @@ def getData(starttime, datafeed, testseries, testseries2, fake=False):
33 34 except:
34 35 logging.error("Failed to parse input data")
35 36 return
36   -
  37 +
37 38 try:
38 39 for n, value in enumerate(values):
39 40 values[n] = float(value)
40 41 except:
41 42 logging.error("Failed to convert input to float")
42 43 return
43   - #logging.info("Recieved data: " + str(values))
  44 + # logging.info("Recieved data: " + str(values))
44 45 testseries.addpoint([time.time()-starttime] + values)
45 46 testseries2.addpoint(values)
46   -
47   -
... ...
robots/little_john/telemetry/code/monitor/version1/main.py
... ... @@ -9,7 +9,6 @@
9 9  
10 10 import math
11 11 import time
12   -#import serial
13 12  
14 13 import pyglet
15 14 import numpy
... ... @@ -31,32 +30,40 @@ starttime = time.time()
31 30  
32 31 datafeed = selectserial()
33 32  
34   -if datafeed == None:
  33 +if datafeed is None:
35 34 logging.critical("Failed to open serial port")
36 35 sys.exit()
37   -
38   -if platform.system()=='Windows':
39   - os='Windows'
  36 +
  37 +if platform.system() == 'Windows':
  38 + os = 'Windows'
40 39 else:
41   - os='Other'
  40 + os = 'Other'
42 41 logging.info('OS = ' + os)
43 42  
44 43  
45 44 testseries = Series(points=150, xauto=True, ylimits=(0, 1024),
46   - title="Data from serial (time)", xname="Time (s)", yname="ADC output")
  45 + title="Data from serial (time)",
  46 + xname="Time (s)", yname="ADC output")
47 47 testseries2 = Series(points=150, xlimits=(0, 1024), ylimits=(0, 1024),
48   - title="Data from serial (xy)", xname="ADC0 output", yname="ADC7 output")
  48 + title="Data from serial (xy)",
  49 + xname="ADC0 output", yname="ADC7 output")
49 50  
50 51 plots = []
51 52 plots.append(Plot(testseries))
52 53 plots.append(Plot(testseries2))
53 54  
54   -# Yes I know these are absurd placeholder names. I'm leaving it like that for the moment because I'm not sure if this is really the only (or best) way to achive the desired result. clock.schedule_interval takes a function, not the result of the function as its argument, so how can you pass arguments to it?
55 55  
56 56 def shrubbery(ni):
  57 + """ Yes I know these are absurd placeholder names. I'm leaving it like
  58 + that for the moment because I'm not sure if this is really the only
  59 + (or best) way to achive the desired result. clock.schedule_interval takes
  60 + a function, not the result of the function as its argument, so how can
  61 + you pass arguments to it? """
57 62 getData(starttime, datafeed, testseries, testseries2)
58 63  
59   -# Pyglet looks after the main event loop, but this ensures that data keeps being read in
  64 +
  65 +# Pyglet looks after the main event loop,
  66 +# but this ensures that data keeps being read
60 67 pyglet.clock.schedule_interval(shrubbery, 0.01)
61 68  
62 69 pyglet.app.run()
... ...
robots/little_john/telemetry/code/monitor/version1/plot.py
... ... @@ -7,31 +7,38 @@ import numpy
7 7 import logging
8 8 from colours import *
9 9  
  10 +
10 11 class Plot(pyglet.window.Window):
11 12 def __init__(self, series):
12 13 """Setup a the details of a plot, and create a corresponding window"""
13 14 pyglet.window.Window.__init__(self, resizable=True)
14 15 self.set_icon(pyglet.image.load('32x32.png'))
15   - self.set_minimum_size(320,320)
  16 + self.set_minimum_size(320, 320)
16 17 self.series = series
17 18 self.font = 'Arkhip'
18   - self.margins = (0.09, 0.08) # Fractions of window size
  19 + self.margins = (0.09, 0.08) # Fractions of window size
19 20 self.lines = (10, 8)
20   - #self.resizable = True
  21 + # self.resizable = True
21 22 self.set_caption(self.series.title)
22 23  
23 24 def on_resize(self, width, height):
24 25 """Handle a resize event from the pyglet event loop"""
25 26 try:
26   - self.bounds = ((int(self.width * self.margins[0]), int(self.width * (1 - self.margins[0]))),
27   - (int(self.height * self.margins[1]), int(self.height * (1 - self.margins[1]))))
  27 + self.bounds = ((int(self.width * self.margins[0]),
  28 + int(self.width * (1 - self.margins[0]))),
  29 + (int(self.height * self.margins[1]),
  30 + int(self.height * (1 - self.margins[1]))))
28 31 except Exception as e:
29 32 logging.critical(str(e))
30 33 self.close()
31 34 logging.critical('Instance closed')
32 35 sys.exit()
33   - self.tag_size = min(self.height*self.margins[1]*0.3,self.width*self.margins[0]*0.3)
34   - # This sometimes seems to throw an error ('AttributeError: 'Plot' object has no attribute 'margins') when started for a second time from the same instance. Interesting. Causes the plot windows to freeze
  36 + self.tag_size = min(self.height*self.margins[1]*0.3,
  37 + self.width*self.margins[0]*0.3)
  38 + # This sometimes seems to throw an error
  39 + # ('AttributeError: 'Plot' object has no attribute 'margins')
  40 + # when started for a second time from the same instance.
  41 + # Interesting. Causes the plot windows to freeze
35 42 pyglet.window.Window.on_resize(self, width, height)
36 43  
37 44 def on_draw(self):
... ... @@ -44,49 +51,56 @@ class Plot(pyglet.window.Window):
44 51  
45 52 def drawBackground(self):
46 53 """Draw the graph background, currently a plain colour"""
47   - pyglet.image.SolidColorImagePattern(WHITE).create_image(self.width, self.height).blit(0, 0)
  54 + #whitepattern = pyglet.image.SolidColorImagePattern(WHITE)
  55 + #whitepattern.create_image(self.width, self.height).blit(0, 0)
  56 + pyglet.image.SolidColorImagePattern(RED).create_image(self.width, self.height).blit(0, 0)
48 57  
49 58 def drawHeading(self):
50   - """Draw a title for the graph (duplicated in the window titlebar, if present"""
  59 + """Draw a title for the graph (duplicated in the window titlebar"""
51 60 heading = pyglet.text.Label(self.series.title, color=BLACK,
52   - font_name=self.font, font_size=self.height*self.margins[0]*0.5,
53   - x=self.width/2, y=self.height-(self.margins[1]),
54   - anchor_x='center', anchor_y='top')
  61 + font_name=self.font,
  62 + font_size=self.height*self.margins[0]*0.5,
  63 + x=self.width/2,
  64 + y=self.height-(self.margins[1]),
  65 + anchor_x='center', anchor_y='top')
55 66 heading.draw()
56 67  
57 68 def drawLines(self, series):
58   - xscale = float(self.series.xlimits[1]-self.series.xlimits[0])/(self.bounds[0][1]-self.bounds[0][0])
59   - yscale = float(self.series.ylimits[1]-self.series.ylimits[0])/(self.bounds[1][1]-self.bounds[1][0])
  69 + xscale = float(self.series.xlimits[1]-self.series.xlimits[0] / (self.bounds[0][1]-self.bounds[0][0]))
  70 + yscale = float(self.series.ylimits[1]-self.series.ylimits[0] / (self.bounds[1][1]-self.bounds[1][0]))
  71 +
60 72 lmar = int(self.width * self.margins[0])
61 73 rmar = int(self.width * self.margins[1])
62 74 tmar = int(self.height * self.margins[0])
63 75 bmar = int(self.height * self.margins[1])
64   -
  76 +
65 77 pyglet.gl.glLineWidth(2)
66   -
67   - linecolours = [(255, 0, 0, 255, 0, 0), (0, 220, 0, 0, 220, 0), (0, 0, 255, 0, 0, 255)]
68   -
  78 +
  79 + linecolours = [(255, 0, 0, 255, 0, 0),
  80 + (0, 220, 0, 0, 220, 0),
  81 + (0, 0, 255, 0, 0, 255)]
  82 +
69 83 try:
70 84 for m in range(len(series.data[0])-1):
71 85 for n in range(len(series.data) - 1):
72   - x1, y1 = series.data[n][0]-series.xlimits[0], series.data[n][m+1]-series.ylimits[0]
73   - x2, y2 = series.data[n+1][0]-series.xlimits[0], series.data[n+1][m+1]-series.ylimits[0]
  86 + x1 = series.data[n][0]-series.xlimits[0]
  87 + y1 = series.data[n][m+1]-series.ylimits[0]
  88 + x2 = series.data[n+1][0]-series.xlimits[0]
  89 + y2 = series.data[n+1][m+1]-series.ylimits[0]
74 90 x1 = int((x1/xscale)+lmar)
75 91 y1 = int((y1/yscale)+bmar)
76 92 x2 = int((x2/xscale)+lmar)
77 93 y2 = int((y2/yscale)+bmar)
78 94 pyglet.graphics.draw(2, pyglet.gl.GL_LINES,
79   - ('v2i', (x1, y1, x2, y2)),
80   - ('c3B', linecolours[m]))
  95 + ('v2i', (x1, y1, x2, y2)),
  96 + ('c3B', linecolours[m]))
81 97 except:
82   - logging.error("Failed to plot lines, possibly due to corrupt/missing data. (This happens at startup)")
83   -
84   - pyglet.gl.glLineWidth(1)
85   -
  98 + logging.error("Failed to plot lines: corrupt/missing data?")
86 99  
  100 + pyglet.gl.glLineWidth(1)
87 101  
88   - def drawAxis(self, axis): # axis=0 is x, 1 is y
89   - """Draw the gridlines and labels for one axis, specified in the last argument"""
  102 + def drawAxis(self, axis): # axis=0 is x, 1 is y
  103 + """Draw gridlines & labels for one axis, specified as an argument"""
90 104 limita = self.bounds[1-axis][1]
91 105 limitb = self.bounds[1-axis][0]
92 106 start = self.bounds[axis][0]
... ... @@ -95,37 +109,49 @@ class Plot(pyglet.window.Window):
95 109 for pos in numpy.arange(start, stop+1, increment):
96 110 # Using fp arithmetic to avoid intermittent fencepost errors
97 111 pos = int(pos)
98   - if axis==0: # x axis, vertical lines
99   - scale = float(self.series.xlimits[1]-self.series.xlimits[0])/(stop-start)
  112 + if axis == 0: # x axis, vertical lines
  113 + scale = float(self.series.xlimits[1]-self.series.xlimits[0])
  114 + scale /= (stop-start)
100 115 tagvalue = ((pos-start) * scale) + self.series.xlimits[0]
101 116 tagtext = str(int(tagvalue))
102   - pyglet.graphics.draw(2, pyglet.gl.GL_LINES, ('v2i', (pos, limita, pos, limitb)),
103   - ('c3B', (0, 0, 0, 0, 0, 0)))
  117 + pyglet.graphics.draw(2, pyglet.gl.GL_LINES,
  118 + ('v2i', (pos, limita, pos, limitb)),
  119 + ('c3B', (0, 0, 0, 0, 0, 0)))
104 120 tag = pyglet.text.Label(tagtext, color=BLACK,
105   - font_name=self.font, font_size=self.tag_size,
  121 + font_name=self.font,
  122 + font_size=self.tag_size,
106 123 x=pos, y=self.height*self.margins[1],
107 124 anchor_x='left', anchor_y='top')
108 125 axistitle = pyglet.text.Label(self.series.xname, color=BLACK,
109   - font_name=self.font, font_size=self.tag_size,
110   - x=self.width/2, y=0,
111   - anchor_x='center', anchor_y='bottom')
  126 + font_name=self.font,
  127 + font_size=self.tag_size,
  128 + x=self.width/2, y=0,
  129 + anchor_x='center',
  130 + anchor_y='bottom')
112 131 axistitle.draw()
113   - if axis==1: # y axis, horizontal lines
114   - scale = float(self.series.ylimits[1]-self.series.ylimits[0])/(stop-start)
  132 + if axis == 1: # y axis, horizontal lines
  133 + scale = float(self.series.ylimits[1]-self.series.ylimits[0])
  134 + scale /= (stop-start)
115 135 tagvalue = ((pos-start) * scale) + self.series.ylimits[0]
116 136 tagtext = str(int(tagvalue))
117   - pyglet.graphics.draw(2, pyglet.gl.GL_LINES, ('v2i', (limita, pos, limitb, pos)),
118   - ('c3B', (0, 0, 0, 0, 0, 0)))
  137 + pyglet.graphics.draw(2, pyglet.gl.GL_LINES,
  138 + ('v2i', (limita, pos, limitb, pos)),
  139 + ('c3B', (0, 0, 0, 0, 0, 0)))
119 140 tag = pyglet.text.Label(tagtext, color=BLACK,
120   - font_name=self.font, font_size=self.tag_size,
121   - x=self.width*self.margins[0]*0.9, y=pos,
  141 + font_name=self.font,
  142 + font_size=self.tag_size,
  143 + x=self.width*self.margins[0]*0.9,
  144 + y=pos,
122 145 anchor_x='right', anchor_y='center')
123 146 axistitle = pyglet.text.Label(self.series.yname, color=BLACK,
124   - font_name=self.font, font_size=self.tag_size,
125   - x=0, y=self.height/2,
126   - anchor_x='center', anchor_y='top')
127   - pyglet.gl.glPushMatrix() # Set up a new context to avoid confusing the main one
128   - # Tranformation to rotate label, and ensure it ends up in the right place
  147 + font_name=self.font,
  148 + font_size=self.tag_size,
  149 + x=0, y=self.height/2,
  150 + anchor_x='center',
  151 + anchor_y='top')
  152 + # Set up a new context to avoid confusing the main one
  153 + pyglet.gl.glPushMatrix()
  154 + # Tranformation to move label to the right place
129 155 pyglet.gl.glTranslatef(self.height//2, self.height//2, 0.0)
130 156 pyglet.gl.glRotatef(90.0, 0.0, 0.0, 1.0)
131 157 # Draw the axis title using the rotated coordinate system
... ...
robots/little_john/telemetry/code/monitor/version1/serialselect.py
... ... @@ -2,27 +2,29 @@
2 2 # Written as a telemetry tool by:
3 3 # The UoN Robot Wars Project, 2018
4 4  
  5 +
5 6 def selectserial():
6   - """Cross-platform function to find appropriate serial ports, query the user if necessary, and open one of them"""
  7 + """Cross-platform function to find appropriate serial ports, query the
  8 + user if necessary, and open one of them"""
7 9 import platform
8 10 import serial
9 11 import os
10 12 import easygui
11 13 import logging
12   -
  14 +
13 15 devpatterns = ['ttyACM', 'ttyUSB', 'rfcomm']
14 16 targetdevs = []
15   - if platform.system()=='Windows':
  17 + if platform.system() == 'Windows':
16 18 com_ports = ['COM%s' % (i + 1) for i in range(256)]
17 19 for port in com_ports:
18 20 try:
19 21 s = serial.Serial(port)
20 22 s.close()
21 23 targetdevs.append(port)
22   - # Temporarily broadened exception in attempt to make this work on uni PCs
23   - except: # (OSError, serial.SerialException):
  24 + # Temporarily broadened exception to make this work on uni PCs
  25 + except: # (OSError, serial.SerialException):
24 26 pass
25   - os='Windows' #may be useful
  27 + os = 'Windows' # may be useful
26 28 else:
27 29 alldevs = os.listdir("/dev/")
28 30 targetdevs = []
... ... @@ -30,7 +32,7 @@ def selectserial():
30 32 for pattern in devpatterns:
31 33 if pattern in dev:
32 34 targetdevs.append("/dev/" + dev)
33   - os='Other' #may be useful
  35 + os = 'Other' # may be useful
34 36  
35 37 if len(targetdevs) == 0:
36 38 logging.info("No serial device found.")
... ... @@ -42,22 +44,22 @@ def selectserial():
42 44 message = "Please choose a serial port to recieve data through:"
43 45 title = "Found multiple serial ports!"
44 46 serialport = easygui.choicebox(message, title, targetdevs)
45   - if serialport == None:
  47 + if serialport is None:
46 48 logging.info("User cancelled selection dialogue")
47 49 return None
48 50 else:
49 51 logging.info("Only found one likely serial device: " + targetdevs[0])
50 52 serialport = targetdevs[0]
51   -
  53 +
52 54 try:
53 55 datafeed = serial.Serial(
54   - port=serialport,
55   - baudrate = 9600,
56   - parity=serial.PARITY_NONE,
57   - stopbits=serial.STOPBITS_ONE,
58   - bytesize=serial.EIGHTBITS,
59   - timeout=1
60   - )
  56 + port=serialport,
  57 + baudrate=9600,
  58 + parity=serial.PARITY_NONE,
  59 + stopbits=serial.STOPBITS_ONE,
  60 + bytesize=serial.EIGHTBITS,
  61 + timeout=1
  62 + )
61 63  
62 64 logging.info("Sucessfully opened " + serialport + " as data source!")
63 65 return datafeed
... ...
robots/little_john/telemetry/code/monitor/version1/series.py
... ... @@ -4,10 +4,12 @@
4 4  
5 5 import logging
6 6  
  7 +
7 8 class Series:
8 9 def __init__(self, points=100, xlimits=(0, 100), ylimits=(0, 100),
9 10 xauto=False, yauto=False,
10   - title="Series title", xname="x-axis name", yname="y-axis name"):
  11 + title="Series title",
  12 + xname="x-axis name", yname="y-axis name"):
11 13 """Set up an object to store a 2D data series"""
12 14 # Proposal:
13 15 # In order to neatly handle multiple lines on the same graph
... ... @@ -28,9 +30,9 @@ class Series:
28 30 self.points = points
29 31 self.xauto = xauto
30 32 self.yauto = yauto
31   -
  33 +
32 34 logging.info("Created series: " + title)
33   -
  35 +
34 36 def addpoint(self, point):
35 37 """Add a point to the dataset, and remove the oldest, if necessary"""
36 38 self.data.append(point)
... ... @@ -43,15 +45,15 @@ class Series:
43 45 self.autoscale(1)
44 46 except:
45 47 logging.error("Series autoscale failed")
46   -
47   - def autoscale(self, axis): # axis=0 is x, 1 is y
  48 +
  49 + def autoscale(self, axis): # axis=0 is x, 1 is y
48 50 minval = self.data[0][axis]
49 51 maxval = self.data[0][axis]
50 52 for value in self.data:
51 53 if value[axis] < minval:
52 54 minval = value[axis]
53 55 if value[axis] > maxval:
54   - maxval = value[axis]
  56 + maxval = value[axis]
55 57 if axis == 0:
56 58 self.xlimits = (minval, maxval)
57 59 else:
... ...