From 4ae9a7d52359faf86c2557763caabc23f2fc8c1b Mon Sep 17 00:00:00 2001 From: Christopher Stone Date: Fri, 9 Mar 2018 13:41:49 +0000 Subject: [PATCH] Tidied up directory structure to better reflect contents. Also copied file from older version moved to version1. Same file, but there's no such thing as git cp, and the file in its current state should be preserved for use with the old graph plotter --- robots/little_john/telemetry/code/monitor/colours.py | 5 ----- robots/little_john/telemetry/code/monitor/graph_plotter.py | 109 ------------------------------------------------------------------------------------------------------------- robots/little_john/telemetry/code/monitor/graph_plotter_rewrite.py | 185 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- robots/little_john/telemetry/code/monitor/serialselect.py | 66 ------------------------------------------------------------------ robots/little_john/telemetry/code/monitor/version0/colours.py | 5 +++++ robots/little_john/telemetry/code/monitor/version0/graph_plotter.py | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ robots/little_john/telemetry/code/monitor/version1/colours.py | 5 +++++ robots/little_john/telemetry/code/monitor/version1/main.py | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ robots/little_john/telemetry/code/monitor/version1/serialselect.py | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 370 insertions(+), 365 deletions(-) delete mode 100644 robots/little_john/telemetry/code/monitor/colours.py delete mode 100755 robots/little_john/telemetry/code/monitor/graph_plotter.py delete mode 100755 robots/little_john/telemetry/code/monitor/graph_plotter_rewrite.py delete mode 100644 robots/little_john/telemetry/code/monitor/serialselect.py create mode 100644 robots/little_john/telemetry/code/monitor/version0/colours.py create mode 100755 robots/little_john/telemetry/code/monitor/version0/graph_plotter.py create mode 100644 robots/little_john/telemetry/code/monitor/version1/colours.py create mode 100755 robots/little_john/telemetry/code/monitor/version1/main.py create mode 100644 robots/little_john/telemetry/code/monitor/version1/serialselect.py diff --git a/robots/little_john/telemetry/code/monitor/colours.py b/robots/little_john/telemetry/code/monitor/colours.py deleted file mode 100644 index bd6601d..0000000 --- a/robots/little_john/telemetry/code/monitor/colours.py +++ /dev/null @@ -1,5 +0,0 @@ -WHITE = (255, 255, 255, 255) -BLACK = (0, 0, 0, 255) -RED = (255, 0, 0, 255) -GREEN = (0, 255, 0, 255) -BLUE = (0, 0, 255, 255) \ No newline at end of file diff --git a/robots/little_john/telemetry/code/monitor/graph_plotter.py b/robots/little_john/telemetry/code/monitor/graph_plotter.py deleted file mode 100755 index ba8e827..0000000 --- a/robots/little_john/telemetry/code/monitor/graph_plotter.py +++ /dev/null @@ -1,109 +0,0 @@ -#!/usr/bin/env python2 - -import pyglet -import math -import random -import time -import serial - -try: - datafeed = serial.Serial( - port='/dev/rfcomm0', - baudrate = 115200, - parity=serial.PARITY_NONE, - stopbits=serial.STOPBITS_ONE, - bytesize=serial.EIGHTBITS, - timeout=1 - ) -except: - print("Serial port setup failure; exiting") - exit() - -red = [1, 0, 0] -green = [0, 1, 0] -blue = [0.2, 0.5, 1] - -window0 = pyglet.window.Window(800, 480, resizable=True) -window0.set_caption("First graph") - -window1 = pyglet.window.Window(800, 480, resizable=True) -window1.set_caption("Second graph") - -starttime = time.time() - - -def drawgrid(target, xlines, ylines, xlimits, ylimits): - pyglet.gl.glColor3f(0.5, 0.5, 0.5) - for xpos in range(0, target.width, target.width/xlines): - pyglet.graphics.draw(2, pyglet.gl.GL_LINES, ('v2i', (xpos, 0, xpos, target.height))) - tagtext = str(round((xlimits[1]-xlimits[0])*(float(xpos)/target.width) + xlimits[0], 1)) - tag = pyglet.text.Label(tagtext, font_name='Sans', font_size=10, x=xpos-2, y=0, anchor_x='right', anchor_y='bottom') - tag.draw() - for ypos in range(0, target.width, target.height/ylines): - pyglet.graphics.draw(2, pyglet.gl.GL_LINES, ('v2i', (0, ypos, target.width, ypos))) - tagtext = str(round((ylimits[1]-ylimits[0])*(float(ypos)/target.height) + ylimits[0], 1)) - tag = pyglet.text.Label(tagtext, font_name='Sans', font_size=10, x=0, y=ypos-2, anchor_x='left', anchor_y='top') - tag.draw() - - -def plotline(target, xdata, ydata, colour): - pyglet.gl.glColor3f(colour[0], colour[1], colour[2]) - points = [] - for n in range(max(len(xdata), len(ydata))): - try: - xpos = ((xdata[n]-min(xdata))*target.width)/(max(xdata)-min(xdata)) - except: - xpos = 0 - xpos = int(xpos) - try: - ypos = ((ydata[n]-min(ydata))*target.height)/(max(ydata)-min(ydata)) - except: - ypos = 0 - ypos = int(ypos) - points.append([xpos, ypos]) - for n in range(len(points)-1): - pyglet.graphics.draw(2, pyglet.gl.GL_LINES, ('v2i', (points[n][0], points[n][1], points[n+1][0], points[n+1][1]))) - - -xdata = [0] -y0data = [0] -y1data = [0] - -def poll_serial(foo): - max_points = 200 - value0 = datafeed.readline().strip().split(", ")[0] - value1 = datafeed.readline().strip().split(", ")[1] - try: - value0 = float(value0) - y0data.append(value0) - if len(y0data) > max_points: - del y0data[0] - - value1 = float(value1) - y1data.append(value1) - if len(y1data) > max_points: - del y1data[0] - - xdata.append(round(time.time() - starttime, 3)) - if len(xdata) > max_points: - del xdata[0] - except: - pass - -pyglet.clock.schedule_interval(poll_serial, 0.001) - -def drawgraph(target, xpoints, ypoints, colour): - plotline(target, xpoints, ypoints, colour) - drawgrid(target, 16, 10, [min(xpoints), max(xpoints)], [min(ypoints), max(ypoints)]) - -@window0.event -def on_draw(): - window0.clear() - drawgraph(window0, xdata, y0data, red) - -@window1.event -def on_draw(): - window1.clear() - drawgraph(window1, xdata, y1data, green) - -pyglet.app.run() diff --git a/robots/little_john/telemetry/code/monitor/graph_plotter_rewrite.py b/robots/little_john/telemetry/code/monitor/graph_plotter_rewrite.py deleted file mode 100755 index cc04f0a..0000000 --- a/robots/little_john/telemetry/code/monitor/graph_plotter_rewrite.py +++ /dev/null @@ -1,185 +0,0 @@ -#!/usr/bin/env python3 -# Note that this should mostly work with python2, if necessary - -# Tool to draw live graphs of data coming in from serial port -# Written as a telemetry tool by: -# The UoN Robot Wars Project, 2018 - -# This code is incomplete, and is missing core features - -#import math -#import time -#import serial - -import pyglet -import numpy -import os -import platform -import sys -import easygui -import logging - -from serialselect import selectserial -from colours import * - -logging.basicConfig(format='%(levelname)s:\t%(message)s', level=logging.DEBUG) -logging.info("Logging system active") - -datafeed = selectserial() - -if datafeed == None: - logging.critical("Failed to open serial port") - sys.exit() - -if platform.system()=='Windows': - os='Windows' -else: - os='Other' -logging.info('OS = ' + os) - -class Series: - def __init__(self, points=100, title="Series title", xname="x-axis name", yname="y-axis name"): - """Set up an object to store a 2D data series""" - # Proposal: - # In order to neatly handle multiple lines on the same graph - # a series is not so much a set of 2D data points, but a number - # of series sharing an x axis. For example - # (time, temperature) - # (time, xaccel, yaccel, zaccel) - # The latter seta of points much be of like nature and share an axis - # (time, temperature, xaccel) - # would be a meaningless thing to plot on a single graph anyway - - self.title = title - self.xname = xname - self.yname = yname - self.xlimits = (100, 0) - self.ylimits = (0, 255) - self.data = [] - self.points = points - def addpoint(self, point): - """Add a point to the dataset, and remove the oldest, if necessary""" - self.data.append(point) - if len(self.data) > self.points: - del self.data[0] - -class Plot(pyglet.window.Window): - def __init__(self, series): - """Setup a the details of a plot, and create a corresponding window""" - pyglet.window.Window.__init__(self, resizable=True) - self.set_minimum_size(320,320) - self.series = series - self.font = 'Arkhip' - self.margins = (0.09, 0.08) # Fractions of window size - self.lines = (10, 8) - #self.resizable = True - self.set_caption(self.series.title) - - def on_resize(self, width, height): - """Handle a resize event from the pyglet event loop""" - try: - self.bounds = ((int(self.width * self.margins[0]), int(self.width * (1 - self.margins[0]))), - (int(self.height * self.margins[1]), int(self.height * (1 - self.margins[1])))) - except Exception as e: - logging.critical(str(e)) - self.close() - logging.critical('Instance closed') - sys.exit() - self.tag_size = min(self.height*self.margins[1]*0.3,self.width*self.margins[0]*0.3) - # 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 - pyglet.window.Window.on_resize(self, width, height) - - def on_draw(self): - """Draw all the components of the graph""" - self.drawBackground() - self.drawHeading() - self.drawAxis(0) - self.drawAxis(1) - - def drawBackground(self): - """Draw the graph background, currently a plain colour""" - pyglet.image.SolidColorImagePattern(WHITE).create_image(self.width, self.height).blit(0, 0) - - def drawHeading(self): - """Draw a title for the graph (duplicated in the window titlebar, if present""" - heading = pyglet.text.Label(self.series.title, color=BLACK, - font_name=self.font, font_size=self.height*self.margins[0]*0.5, - x=self.width/2, y=self.height-(self.margins[1]), - anchor_x='center', anchor_y='top') - heading.draw() - - def drawLine(self): - for n in range(len(data) - 1): - a, b = data[n], data[n+1] - pass - - def drawAxis(self, axis): # axis=0 is x, 1 is y - """Draw the gridlines and labels for one axis, specified in the last argument""" - limita = self.bounds[1-axis][1] - limitb = self.bounds[1-axis][0] - start = self.bounds[axis][0] - stop = self.bounds[axis][1] - increment = float(stop-start)/self.lines[axis] - for pos in numpy.arange(start, stop+1, increment): - # Using fp arithmetic to avoid intermittent fencepost errors - pos = int(pos) - if axis==0: # x axis, vertical lines - scale = float(self.series.xlimits[1]-self.series.xlimits[0])/(stop-start) - tagvalue = ((pos-start) * scale) + self.series.xlimits[0] - tagtext = str(int(tagvalue)) - pyglet.graphics.draw(2, pyglet.gl.GL_LINES, ('v2i', (pos, limita, pos, limitb)), - ('c3B', (0, 0, 0, 0, 0, 0))) - tag = pyglet.text.Label(tagtext, color=BLACK, - font_name=self.font, font_size=self.tag_size, - x=pos, y=self.height*self.margins[1], - anchor_x='left', anchor_y='top') - axistitle = pyglet.text.Label(self.series.xname, color=BLACK, - font_name=self.font, font_size=self.tag_size, - x=self.width/2, y=0, - anchor_x='center', anchor_y='bottom') - axistitle.draw() - if axis==1: # y axis, horizontal lines - scale = float(self.series.ylimits[1]-self.series.ylimits[0])/(stop-start) - tagvalue = ((pos-start) * scale) + self.series.ylimits[0] - tagtext = str(int(tagvalue)) - pyglet.graphics.draw(2, pyglet.gl.GL_LINES, ('v2i', (limita, pos, limitb, pos)), - ('c3B', (0, 0, 0, 0, 0, 0))) - tag = pyglet.text.Label(tagtext, color=BLACK, - font_name=self.font, font_size=self.tag_size, - x=self.width*self.margins[0]*0.9, y=pos, - anchor_x='right', anchor_y='center') - axistitle = pyglet.text.Label(self.series.yname, color=BLACK, - font_name=self.font, font_size=self.tag_size, - x=0, y=self.height/2, - anchor_x='center', anchor_y='top') - pyglet.gl.glPushMatrix() # Set up a new context to avoid confusing the main one - # Tranformation to rotate label, and ensure it ends up in the right place - pyglet.gl.glTranslatef(self.height//2, self.height//2, 0.0) - pyglet.gl.glRotatef(90.0, 0.0, 0.0, 1.0) - # Draw the axis title using the rotated coordinate system - axistitle.draw() - # Return everything to its previous state - pyglet.gl.glPopMatrix() - - tag.draw() - -testseries = Series() -logging.info("Series created") -plots = [] -plots.append(Plot(testseries)) - -def pollSerial(elapsed): - """Check serial port for incoming data""" - # Note: 'elapsed' is time since last call of this function - # This works, but it might be better for performance to have two seperate functions, only one of which is run. - if os=='Windows': - values = datafeed.readline().strip().split(b", ") - else: - values = datafeed.readline().strip() - values = str(values).split(", ") - testseries.addpoint(values) - -# Pyglet looks after the main event loop, but this ensures that data keeps being read in -pyglet.clock.schedule_interval(pollSerial, 0.1) - -pyglet.app.run() diff --git a/robots/little_john/telemetry/code/monitor/serialselect.py b/robots/little_john/telemetry/code/monitor/serialselect.py deleted file mode 100644 index 91ef300..0000000 --- a/robots/little_john/telemetry/code/monitor/serialselect.py +++ /dev/null @@ -1,66 +0,0 @@ -# Module to choose and open a serial port -# Written as a telemetry tool by: -# The UoN Robot Wars Project, 2018 - -def selectserial(): - """Cross-platform function to find appropriate serial ports, query the user if necessary, and open one of them""" - import platform - import serial - import os - import easygui - import logging - - devpatterns = ['ttyACM', 'ttyUSB', 'rfcomm'] - targetdevs = [] - if platform.system()=='Windows': - com_ports = ['COM%s' % (i + 1) for i in range(256)] - for port in com_ports: - try: - s = serial.Serial(port) - s.close() - targetdevs.append(port) - # Temporarily broadened exception in attempt to make this work on uni PCs - except: # (OSError, serial.SerialException): - pass - os='Windows' #may be useful - else: - alldevs = os.listdir("/dev/") - targetdevs = [] - for dev in alldevs: - for pattern in devpatterns: - if pattern in dev: - targetdevs.append("/dev/" + dev) - os='Other' #may be useful - - if len(targetdevs) == 0: - logging.info("No serial device found.") - return None - elif len(targetdevs) > 1: - logging.info("Found multiple serial devices: ") - for i, dev in enumerate(targetdevs): - logging.info(" " + str(i) + ": " + dev) - message = "Please choose a serial port to recieve data through:" - title = "Found multiple serial ports!" - serialport = easygui.choicebox(message, title, targetdevs) - if serialport == None: - logging.info("User cancelled selection dialogue") - return None - else: - logging.info("Only found one likely serial device: " + targetdevs[0]) - serialport = targetdevs[0] - - try: - datafeed = serial.Serial( - port=serialport, - baudrate = 9600, - parity=serial.PARITY_NONE, - stopbits=serial.STOPBITS_ONE, - bytesize=serial.EIGHTBITS, - timeout=1 - ) - - logging.info("Sucessfully opened " + serialport + " as data source!") - return datafeed - except Exception as e: - logging.critical(str(e)) - return None diff --git a/robots/little_john/telemetry/code/monitor/version0/colours.py b/robots/little_john/telemetry/code/monitor/version0/colours.py new file mode 100644 index 0000000..bd6601d --- /dev/null +++ b/robots/little_john/telemetry/code/monitor/version0/colours.py @@ -0,0 +1,5 @@ +WHITE = (255, 255, 255, 255) +BLACK = (0, 0, 0, 255) +RED = (255, 0, 0, 255) +GREEN = (0, 255, 0, 255) +BLUE = (0, 0, 255, 255) \ No newline at end of file diff --git a/robots/little_john/telemetry/code/monitor/version0/graph_plotter.py b/robots/little_john/telemetry/code/monitor/version0/graph_plotter.py new file mode 100755 index 0000000..ba8e827 --- /dev/null +++ b/robots/little_john/telemetry/code/monitor/version0/graph_plotter.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python2 + +import pyglet +import math +import random +import time +import serial + +try: + datafeed = serial.Serial( + port='/dev/rfcomm0', + baudrate = 115200, + parity=serial.PARITY_NONE, + stopbits=serial.STOPBITS_ONE, + bytesize=serial.EIGHTBITS, + timeout=1 + ) +except: + print("Serial port setup failure; exiting") + exit() + +red = [1, 0, 0] +green = [0, 1, 0] +blue = [0.2, 0.5, 1] + +window0 = pyglet.window.Window(800, 480, resizable=True) +window0.set_caption("First graph") + +window1 = pyglet.window.Window(800, 480, resizable=True) +window1.set_caption("Second graph") + +starttime = time.time() + + +def drawgrid(target, xlines, ylines, xlimits, ylimits): + pyglet.gl.glColor3f(0.5, 0.5, 0.5) + for xpos in range(0, target.width, target.width/xlines): + pyglet.graphics.draw(2, pyglet.gl.GL_LINES, ('v2i', (xpos, 0, xpos, target.height))) + tagtext = str(round((xlimits[1]-xlimits[0])*(float(xpos)/target.width) + xlimits[0], 1)) + tag = pyglet.text.Label(tagtext, font_name='Sans', font_size=10, x=xpos-2, y=0, anchor_x='right', anchor_y='bottom') + tag.draw() + for ypos in range(0, target.width, target.height/ylines): + pyglet.graphics.draw(2, pyglet.gl.GL_LINES, ('v2i', (0, ypos, target.width, ypos))) + tagtext = str(round((ylimits[1]-ylimits[0])*(float(ypos)/target.height) + ylimits[0], 1)) + tag = pyglet.text.Label(tagtext, font_name='Sans', font_size=10, x=0, y=ypos-2, anchor_x='left', anchor_y='top') + tag.draw() + + +def plotline(target, xdata, ydata, colour): + pyglet.gl.glColor3f(colour[0], colour[1], colour[2]) + points = [] + for n in range(max(len(xdata), len(ydata))): + try: + xpos = ((xdata[n]-min(xdata))*target.width)/(max(xdata)-min(xdata)) + except: + xpos = 0 + xpos = int(xpos) + try: + ypos = ((ydata[n]-min(ydata))*target.height)/(max(ydata)-min(ydata)) + except: + ypos = 0 + ypos = int(ypos) + points.append([xpos, ypos]) + for n in range(len(points)-1): + pyglet.graphics.draw(2, pyglet.gl.GL_LINES, ('v2i', (points[n][0], points[n][1], points[n+1][0], points[n+1][1]))) + + +xdata = [0] +y0data = [0] +y1data = [0] + +def poll_serial(foo): + max_points = 200 + value0 = datafeed.readline().strip().split(", ")[0] + value1 = datafeed.readline().strip().split(", ")[1] + try: + value0 = float(value0) + y0data.append(value0) + if len(y0data) > max_points: + del y0data[0] + + value1 = float(value1) + y1data.append(value1) + if len(y1data) > max_points: + del y1data[0] + + xdata.append(round(time.time() - starttime, 3)) + if len(xdata) > max_points: + del xdata[0] + except: + pass + +pyglet.clock.schedule_interval(poll_serial, 0.001) + +def drawgraph(target, xpoints, ypoints, colour): + plotline(target, xpoints, ypoints, colour) + drawgrid(target, 16, 10, [min(xpoints), max(xpoints)], [min(ypoints), max(ypoints)]) + +@window0.event +def on_draw(): + window0.clear() + drawgraph(window0, xdata, y0data, red) + +@window1.event +def on_draw(): + window1.clear() + drawgraph(window1, xdata, y1data, green) + +pyglet.app.run() diff --git a/robots/little_john/telemetry/code/monitor/version1/colours.py b/robots/little_john/telemetry/code/monitor/version1/colours.py new file mode 100644 index 0000000..bd6601d --- /dev/null +++ b/robots/little_john/telemetry/code/monitor/version1/colours.py @@ -0,0 +1,5 @@ +WHITE = (255, 255, 255, 255) +BLACK = (0, 0, 0, 255) +RED = (255, 0, 0, 255) +GREEN = (0, 255, 0, 255) +BLUE = (0, 0, 255, 255) \ No newline at end of file diff --git a/robots/little_john/telemetry/code/monitor/version1/main.py b/robots/little_john/telemetry/code/monitor/version1/main.py new file mode 100755 index 0000000..cc04f0a --- /dev/null +++ b/robots/little_john/telemetry/code/monitor/version1/main.py @@ -0,0 +1,185 @@ +#!/usr/bin/env python3 +# Note that this should mostly work with python2, if necessary + +# Tool to draw live graphs of data coming in from serial port +# Written as a telemetry tool by: +# The UoN Robot Wars Project, 2018 + +# This code is incomplete, and is missing core features + +#import math +#import time +#import serial + +import pyglet +import numpy +import os +import platform +import sys +import easygui +import logging + +from serialselect import selectserial +from colours import * + +logging.basicConfig(format='%(levelname)s:\t%(message)s', level=logging.DEBUG) +logging.info("Logging system active") + +datafeed = selectserial() + +if datafeed == None: + logging.critical("Failed to open serial port") + sys.exit() + +if platform.system()=='Windows': + os='Windows' +else: + os='Other' +logging.info('OS = ' + os) + +class Series: + def __init__(self, points=100, title="Series title", xname="x-axis name", yname="y-axis name"): + """Set up an object to store a 2D data series""" + # Proposal: + # In order to neatly handle multiple lines on the same graph + # a series is not so much a set of 2D data points, but a number + # of series sharing an x axis. For example + # (time, temperature) + # (time, xaccel, yaccel, zaccel) + # The latter seta of points much be of like nature and share an axis + # (time, temperature, xaccel) + # would be a meaningless thing to plot on a single graph anyway + + self.title = title + self.xname = xname + self.yname = yname + self.xlimits = (100, 0) + self.ylimits = (0, 255) + self.data = [] + self.points = points + def addpoint(self, point): + """Add a point to the dataset, and remove the oldest, if necessary""" + self.data.append(point) + if len(self.data) > self.points: + del self.data[0] + +class Plot(pyglet.window.Window): + def __init__(self, series): + """Setup a the details of a plot, and create a corresponding window""" + pyglet.window.Window.__init__(self, resizable=True) + self.set_minimum_size(320,320) + self.series = series + self.font = 'Arkhip' + self.margins = (0.09, 0.08) # Fractions of window size + self.lines = (10, 8) + #self.resizable = True + self.set_caption(self.series.title) + + def on_resize(self, width, height): + """Handle a resize event from the pyglet event loop""" + try: + self.bounds = ((int(self.width * self.margins[0]), int(self.width * (1 - self.margins[0]))), + (int(self.height * self.margins[1]), int(self.height * (1 - self.margins[1])))) + except Exception as e: + logging.critical(str(e)) + self.close() + logging.critical('Instance closed') + sys.exit() + self.tag_size = min(self.height*self.margins[1]*0.3,self.width*self.margins[0]*0.3) + # 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 + pyglet.window.Window.on_resize(self, width, height) + + def on_draw(self): + """Draw all the components of the graph""" + self.drawBackground() + self.drawHeading() + self.drawAxis(0) + self.drawAxis(1) + + def drawBackground(self): + """Draw the graph background, currently a plain colour""" + pyglet.image.SolidColorImagePattern(WHITE).create_image(self.width, self.height).blit(0, 0) + + def drawHeading(self): + """Draw a title for the graph (duplicated in the window titlebar, if present""" + heading = pyglet.text.Label(self.series.title, color=BLACK, + font_name=self.font, font_size=self.height*self.margins[0]*0.5, + x=self.width/2, y=self.height-(self.margins[1]), + anchor_x='center', anchor_y='top') + heading.draw() + + def drawLine(self): + for n in range(len(data) - 1): + a, b = data[n], data[n+1] + pass + + def drawAxis(self, axis): # axis=0 is x, 1 is y + """Draw the gridlines and labels for one axis, specified in the last argument""" + limita = self.bounds[1-axis][1] + limitb = self.bounds[1-axis][0] + start = self.bounds[axis][0] + stop = self.bounds[axis][1] + increment = float(stop-start)/self.lines[axis] + for pos in numpy.arange(start, stop+1, increment): + # Using fp arithmetic to avoid intermittent fencepost errors + pos = int(pos) + if axis==0: # x axis, vertical lines + scale = float(self.series.xlimits[1]-self.series.xlimits[0])/(stop-start) + tagvalue = ((pos-start) * scale) + self.series.xlimits[0] + tagtext = str(int(tagvalue)) + pyglet.graphics.draw(2, pyglet.gl.GL_LINES, ('v2i', (pos, limita, pos, limitb)), + ('c3B', (0, 0, 0, 0, 0, 0))) + tag = pyglet.text.Label(tagtext, color=BLACK, + font_name=self.font, font_size=self.tag_size, + x=pos, y=self.height*self.margins[1], + anchor_x='left', anchor_y='top') + axistitle = pyglet.text.Label(self.series.xname, color=BLACK, + font_name=self.font, font_size=self.tag_size, + x=self.width/2, y=0, + anchor_x='center', anchor_y='bottom') + axistitle.draw() + if axis==1: # y axis, horizontal lines + scale = float(self.series.ylimits[1]-self.series.ylimits[0])/(stop-start) + tagvalue = ((pos-start) * scale) + self.series.ylimits[0] + tagtext = str(int(tagvalue)) + pyglet.graphics.draw(2, pyglet.gl.GL_LINES, ('v2i', (limita, pos, limitb, pos)), + ('c3B', (0, 0, 0, 0, 0, 0))) + tag = pyglet.text.Label(tagtext, color=BLACK, + font_name=self.font, font_size=self.tag_size, + x=self.width*self.margins[0]*0.9, y=pos, + anchor_x='right', anchor_y='center') + axistitle = pyglet.text.Label(self.series.yname, color=BLACK, + font_name=self.font, font_size=self.tag_size, + x=0, y=self.height/2, + anchor_x='center', anchor_y='top') + pyglet.gl.glPushMatrix() # Set up a new context to avoid confusing the main one + # Tranformation to rotate label, and ensure it ends up in the right place + pyglet.gl.glTranslatef(self.height//2, self.height//2, 0.0) + pyglet.gl.glRotatef(90.0, 0.0, 0.0, 1.0) + # Draw the axis title using the rotated coordinate system + axistitle.draw() + # Return everything to its previous state + pyglet.gl.glPopMatrix() + + tag.draw() + +testseries = Series() +logging.info("Series created") +plots = [] +plots.append(Plot(testseries)) + +def pollSerial(elapsed): + """Check serial port for incoming data""" + # Note: 'elapsed' is time since last call of this function + # This works, but it might be better for performance to have two seperate functions, only one of which is run. + if os=='Windows': + values = datafeed.readline().strip().split(b", ") + else: + values = datafeed.readline().strip() + values = str(values).split(", ") + testseries.addpoint(values) + +# Pyglet looks after the main event loop, but this ensures that data keeps being read in +pyglet.clock.schedule_interval(pollSerial, 0.1) + +pyglet.app.run() diff --git a/robots/little_john/telemetry/code/monitor/version1/serialselect.py b/robots/little_john/telemetry/code/monitor/version1/serialselect.py new file mode 100644 index 0000000..91ef300 --- /dev/null +++ b/robots/little_john/telemetry/code/monitor/version1/serialselect.py @@ -0,0 +1,66 @@ +# Module to choose and open a serial port +# Written as a telemetry tool by: +# The UoN Robot Wars Project, 2018 + +def selectserial(): + """Cross-platform function to find appropriate serial ports, query the user if necessary, and open one of them""" + import platform + import serial + import os + import easygui + import logging + + devpatterns = ['ttyACM', 'ttyUSB', 'rfcomm'] + targetdevs = [] + if platform.system()=='Windows': + com_ports = ['COM%s' % (i + 1) for i in range(256)] + for port in com_ports: + try: + s = serial.Serial(port) + s.close() + targetdevs.append(port) + # Temporarily broadened exception in attempt to make this work on uni PCs + except: # (OSError, serial.SerialException): + pass + os='Windows' #may be useful + else: + alldevs = os.listdir("/dev/") + targetdevs = [] + for dev in alldevs: + for pattern in devpatterns: + if pattern in dev: + targetdevs.append("/dev/" + dev) + os='Other' #may be useful + + if len(targetdevs) == 0: + logging.info("No serial device found.") + return None + elif len(targetdevs) > 1: + logging.info("Found multiple serial devices: ") + for i, dev in enumerate(targetdevs): + logging.info(" " + str(i) + ": " + dev) + message = "Please choose a serial port to recieve data through:" + title = "Found multiple serial ports!" + serialport = easygui.choicebox(message, title, targetdevs) + if serialport == None: + logging.info("User cancelled selection dialogue") + return None + else: + logging.info("Only found one likely serial device: " + targetdevs[0]) + serialport = targetdevs[0] + + try: + datafeed = serial.Serial( + port=serialport, + baudrate = 9600, + parity=serial.PARITY_NONE, + stopbits=serial.STOPBITS_ONE, + bytesize=serial.EIGHTBITS, + timeout=1 + ) + + logging.info("Sucessfully opened " + serialport + " as data source!") + return datafeed + except Exception as e: + logging.critical(str(e)) + return None -- libgit2 0.21.2