Laelaps  2.3.5
RoadNarrows Robotics Small Outdoor Mobile Robot Project
VelPlot.py
Go to the documentation of this file.
1 ###############################################################################
2 #
3 # Module: Laelaps.VelPlot
4 #
5 # Package: RoadNarrows Laelaps Robotic Mobile Platform Package
6 #
7 # Link: https://github.com/roadnarrows-robotics/laelaps
8 #
9 # File: VelPlot.py
10 #
11 ## \file
12 ##
13 ## $LastChangedDate: 2016-02-02 13:47:13 -0700 (Tue, 02 Feb 2016) $
14 ## $Rev: 4293 $
15 ##
16 ## \brief Motor velocity plot class.
17 ##
18 ## \author Robin Knight (robin.knight@roadnarrows.com)
19 ##
20 ## \par Copyright
21 ## \h_copy 2015-2017. RoadNarrows LLC.\n
22 ## http://www.roadnarrows.com\n
23 ## All Rights Reserved
24 ##
25 # @EulaBegin@
26 #
27 # Permission is hereby granted, without written agreement and without
28 # license or royalty fees, to use, copy, modify, and distribute this
29 # software and its documentation for any purpose, provided that
30 # (1) The above copyright notice and the following two paragraphs
31 # appear in all copies of the source code and (2) redistributions
32 # including binaries reproduces these notices in the supporting
33 # documentation. Substantial modifications to this software may be
34 # copyrighted by their authors and need not follow the licensing terms
35 # described here, provided that the new terms are clearly indicated in
36 # all files where they apply.
37 #
38 # IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY MEMBERS/EMPLOYEES
39 # OF ROADNARROW LLC OR DISTRIBUTORS OF THIS SOFTWARE BE LIABLE TO ANY
40 # PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
41 # DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
42 # EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN ADVISED OF
43 # THE POSSIBILITY OF SUCH DAMAGE.
44 #
45 # THE AUTHOR AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
46 # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
47 # FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
48 # "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
49 # PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
50 #
51 # @EulaEnd@
52 #
53 ###############################################################################
54 
55 import sys
56 import os
57 import time
58 import math
59 import getopt
60 
61 import numpy as np
62 
63 import matplotlib
64 matplotlib.use('TkAgg')
65 
66 from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, \
67  NavigationToolbar2TkAgg
68 from matplotlib.figure import Figure
69 
70 import matplotlib.pyplot as mplPlot
71 import matplotlib.lines as mplLine
72 import matplotlib.animation as mplAnim
73 import matplotlib.colors as mplColors
74 
75 if sys.version_info[0] < 3:
76  from Tkinter import *
77  from Tkconstants import *
78  from tkFileDialog import *
79  import tkFont
80 else:
81  from tkinter import *
82  from Tkconstants import *
83  from tkFileDialog import *
84  import tkFont
85 
86 import Laelaps.Utils as ut
87 
88 _spkey = lambda key: 'sp_'+key
89 
90 
91 # ------------------------------------------------------------------------------
92 # Class VelPlotData
93 # ------------------------------------------------------------------------------
94 
96  def __init__(self, ax, maxt=4, dt=0.02):
97  self.ax = ax
98  self.dt = dt
99  self.maxt = maxt
100 
101  self.cntEnabled = 0
102  self.enabled = {}
103  self.lines = {}
104  self.vdata = {}
105  self.setpoints = {}
106 
107  self.tdata = [0]
108 
109  self.ax.set_ylim(-100.1, 100.1)
110  self.ax.set_xlim(0, self.maxt)
111 
112  def addVel(self, key, color):
113  # current velocity
114  self.enabled[key] = False
115  self.vdata[key] = [0]
116  self.lines[key] = mplLine.Line2D(self.tdata, self.vdata[key])
117  self.lines[key].set_color(mplColors.hex2color(color))
118  self.lines[key].set_linestyle('-')
119  self.ax.add_line(self.lines[key])
120 
121  # velocity setpoint
122  key_sp = _spkey(key)
123  self.enabled[key_sp] = False
124  self.vdata[key_sp] = [0]
125  self.setpoints[key_sp] = 0
126  self.lines[key_sp] = mplLine.Line2D(self.tdata, self.vdata[key_sp])
127  self.lines[key_sp].set_color(mplColors.hex2color(color))
128  self.lines[key_sp].set_linestyle('--')
129  self.lines[key_sp].set_linewidth(2.0)
130  self.ax.add_line(self.lines[key_sp])
131 
132  def update(self, y):
133  if self.cntEnabled <= 0 or len(self.lines) == 0:
134  return tuple(self.lines.values())
135  lastt = self.tdata[-1]
136  if lastt > self.tdata[0] + self.maxt: # reset the arrays
137  self.tdata.pop(0)
138  for key in self.vdata.keys():
139  if self.enabled[key]:
140  self.vdata[key].pop(0)
141  self.ax.set_xlim(self.tdata[0], self.tdata[0] + self.maxt)
142  self.ax.figure.canvas.draw()
143  t = self.tdata[-1] + self.dt
144  self.tdata.append(t)
145  for key in self.vdata.keys():
146  if self.enabled[key]:
147  if key.find('sp_') >= 0:
148  self.vdata[key].append(self.setpoints[key])
149  else:
150  self.vdata[key].append(y[key])
151  self.lines[key].set_data(self.tdata, self.vdata[key])
152  return tuple(self.lines.values())
153 
154  def emitter(self):
155  while True:
156  v = {}
157  for k,s in self.enabled.iteritems():
158  if s and k.find('sp_') == -1:
159  v[k] = 200.0 * np.random.rand(1) - 100.0
160  yield v
161  #v = np.random.rand(1)
162  #yield 200.0 * np.random.rand(1) - 100.0
163  #if v > p:
164  # yield 0.
165  #else:
166  # yield 100.0 * np.random.rand(1)
167 
168  def enable(self, key, setpoint):
169  if not self.enabled[key]:
170  self.vdata[key] = [0] * len(self.tdata)
171  self.enabled[key] = True
172 
173  key_sp = _spkey(key)
174  self.setpoints[key_sp] = setpoint
175  self.vdata[key_sp] = [setpoint] * len(self.tdata)
176  self.enabled[key_sp] = True
177 
178  self.cntEnabled += 2
179 
180  def disable(self, key):
181  if self.enabled[key]:
182  self.enabled[key] = False
183 
184  key_sp = _spkey(key)
185  self.enabled[key_sp] = False
186 
187  self.cntEnabled -= 2
188 
189  def setpoint(self, key, setpoint):
190  key_sp = _spkey(key)
191  self.setpoints[key_sp] = setpoint
192 
193 
194 # ------------------------------------------------------------------------------
195 # Class VelPlot
196 # ------------------------------------------------------------------------------
197 
198 class VelPlot:
199  def __init__(self, wCanvas, width, height, motorNames, colors):
200  #
201  # Create matplot subplots.
202  # Note: Size are in ridiculus inches units.
203  #
204  dpi = 100 # does not have to be real
205  color = mplColors.hex2color("#ffcccc")
206 
207  fig = mplPlot.Figure(figsize=(width/dpi, height/dpi), dpi=dpi,
208  facecolor=color)
209 
210  ax = fig.add_subplot(111, xlabel="t (seconds)", ylabel='v (percent)')
211 
212  self.m_rtData = VelPlotData(ax, dt=0.01)
213 
214  for motor in motorNames:
215  self.m_rtData.addVel(motor, colors[motor])
216 
217  canvas = FigureCanvasTkAgg(fig, master=wCanvas)
218  canvas.get_tk_widget().grid(row=0, column=0)
219 
220  # pass a generator in "emitter" to produce data for the update func
221  ani = mplAnim.FuncAnimation(fig, self.m_rtData.update,
222  self.m_rtData.emitter, interval=10, blit=True)
223 
224  canvas.show()
225 
226  def enable(self, motors, setpoints):
227  if type(motors) == str:
228  self.m_rtData.enable(motors, setpoints)
229  elif type(motors) == list or type(motors) == tuple:
230  for motor in motors:
231  self.m_rtData.enable(motor, setpoints[motor])
232  else:
233  print "BUG: Bad paramaters:", repr(motors), repr(setpoints)
234 
235  def disable(self, motors):
236  if type(motors) == str:
237  self.m_rtData.disable(motors)
238  elif type(motors) == list or type(motors) == tuple:
239  for motor in motors:
240  self.m_rtData.disable(motor)
241  else:
242  print "BUG: Bad paramaters:", repr(motors), repr(setpoints)
243 
244  def setpoint(self, motors, setpoints):
245  if type(motors) == str:
246  self.m_rtData.setpoint(motors, setpoints)
247  elif type(motors) == list or type(motors) == tuple:
248  for motor in motors:
249  self.m_rtData.setpoint(motor, setpoints[motor])
250  else:
251  print "BUG: Bad paramaters:", repr(motors), repr(setpoints)