Rev 651 |
Rev 654 |
Go to most recent revision |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-
# generated by wxGlade 0.6.3 on Thu Sep 24 15:46:36 2009
#
# Mikrokopter VibrationTest Rev: $Rev: 653 $
#
# Author: Frederic Goddeeris (frederic@rc-flight.be)
#
import sys
import os
import time
import thread
import ConfigParser
import math
import wx
import wx.lib
import wx.lib.plot
import wx.lib.newevent
import wx.lib.agw.speedmeter as speedmeter
import mkProto
CHANNEL_NAMES = ["GyroYaw", "GyroRoll", "GyroNick", "Pressure", "Batt", "AccTop", "AccRoll", "AccNick"]
MOTOR_MAX = 16
FS = 11111
pi = 3.14
COLOR_YELLOW = wx.Colour(255, 240, 0)
COLOR_BACKGROUND = wx.Colour(0x80, 0x80, 0x80)
COLORS = [wx.RED, wx.GREEN, wx.BLUE, COLOR_YELLOW, COLOR_BACKGROUND, wx.BLACK,]*2
rootPath = ""
# Needs Numeric or numarray or NumPy
try:
import numpy.oldnumeric as _Numeric
except:
try:
import numarray as _Numeric #if numarray is used it is renamed Numeric
except:
try:
import Numeric as _Numeric
except:
msg= """
This module requires the Numeric/numarray or NumPy module,
which could not be imported. It probably is not installed
(it's not part of the standard Python distribution). See the
Numeric Python site (http://numpy.scipy.org) for information on
downloading source or binaries."""
raise ImportError, "Numeric,numarray or NumPy not found. \n" + msg
# begin wxGlade: extracode
# end wxGlade
# This creates a new Event class and a EVT binder function
(MeasStatusUpdateEvent, EVT_MEAS_STATUS_UPDATE) = wx.lib.newevent.NewEvent()
(MeasDataEvent, EVT_MEAS_DATA) = wx.lib.newevent.NewEvent()
class MeasureDialog(wx.Dialog):
def __init__(self, *args, **kwds):
# begin wxGlade: MeasureDialog.__init__
kwds["style"] = wx.CAPTION|wx.RESIZE_BORDER|wx.THICK_FRAME
wx.Dialog.__init__(self, *args, **kwds)
self.text_ctrl_1 = wx.TextCtrl(self, -1, "", style=wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL)
self.button = wx.Button(self, -1, "STOP")
self.voltageCtrl = speedmeter.SpeedMeter(self, extrastyle=speedmeter.SM_DRAW_HAND | speedmeter.SM_DRAW_PARTIAL_SECTORS | speedmeter.SM_DRAW_MIDDLE_ICON )
self.speedCtrl = speedmeter.SpeedMeter(self, extrastyle=speedmeter.SM_DRAW_HAND | speedmeter.SM_DRAW_PARTIAL_SECTORS | speedmeter.SM_DRAW_MIDDLE_TEXT | speedmeter.SM_DRAW_SECONDARY_TICKS)
self.__set_properties()
self.__do_layout()
self.Bind(wx.EVT_BUTTON, self.onButton, self.button)
# end wxGlade
self.button.SetFocus()
# Configure Voltage Ctrl
self.voltageCtrl.SetAngleRange(0,pi)
intervals = range(0, 5)
self.voltageCtrl.SetIntervals(intervals)
colours = [wx.RED, wx.GREEN, wx.GREEN, COLOR_YELLOW]
self.voltageCtrl.SetIntervalColours(colours)
ticks = ["", "", "", "", ""]
self.voltageCtrl.SetTicks(ticks)
self.voltageCtrl.SetTicksColour(wx.WHITE)
self.voltageCtrl.SetHandColour(COLOR_YELLOW)
icon = wx.Icon("%s/Resources/fuel.ico" % rootPath, wx.BITMAP_TYPE_ICO)
icon.SetWidth(24)
icon.SetHeight(24)
self.voltageCtrl.SetMiddleIcon(icon)
self.voltageCtrl.SetSpeedBackground(COLOR_BACKGROUND)
self.voltageCtrl.SetArcColour(wx.WHITE)
self.voltageCtrl.SetSpeedValue(2)
# Configure Speed Ctr;
self.speedCtrl.SetAngleRange(0,pi)
intervals = range(0, 261, 20)
self.speedCtrl.SetIntervals(intervals)
colours = [COLOR_BACKGROUND]*(len(intervals)-1)
for i in range(5,10):
colours[i] = wx.GREEN
self.speedCtrl.SetIntervalColours(colours)
ticks = [str(interval) for interval in intervals]
self.speedCtrl.SetTicks(ticks)
self.speedCtrl.SetTicksColour(wx.WHITE)
self.speedCtrl.SetNumberOfSecondaryTicks(1)
self.speedCtrl.SetTicksFont(wx.Font(7, wx.SWISS, wx.NORMAL, wx.NORMAL))
self.speedCtrl.SetMiddleText("Speed")
self.speedCtrl.SetMiddleTextColour(wx.WHITE)
self.speedCtrl.SetMiddleTextFont(wx.Font(8, wx.SWISS, wx.NORMAL, wx.BOLD))
self.speedCtrl.SetHandColour(COLOR_YELLOW)
self.speedCtrl.SetSpeedBackground(COLOR_BACKGROUND)
self.speedCtrl.SetArcColour(wx.WHITE)
self.speedCtrl.SetSpeedValue(0)
self.running = True
self.Bind(EVT_MEAS_STATUS_UPDATE, self.OnUpdate)
self.Bind(EVT_MEAS_DATA, self.OnData)
# The first argument that is passed to the constructor is the parent
self.app = args[0].app
self.error = False
self.firstVoltage = True
def __set_properties(self):
# begin wxGlade: MeasureDialog.__set_properties
self.SetTitle("Measuring Status")
self.text_ctrl_1.SetMinSize((400,300))
self.voltageCtrl.SetMinSize((50,-1))
self.speedCtrl.SetMinSize((50,-1))
# end wxGlade
def __do_layout(self):
# begin wxGlade: MeasureDialog.__do_layout
sizer_1 = wx.BoxSizer(wx.HORIZONTAL)
sizer_4 = wx.BoxSizer(wx.VERTICAL)
sizer_2 = wx.BoxSizer(wx.VERTICAL)
sizer_1.Add((20, 20), 0, 0, 0)
sizer_2.Add((20, 20), 0, 0, 0)
sizer_2.Add(self.text_ctrl_1, 1, wx.EXPAND, 0)
sizer_2.Add((20, 20), 0, 0, 0)
sizer_2.Add(self.button, 0, wx.ALIGN_CENTER_HORIZONTAL, 0)
sizer_2.Add((20, 20), 0, 0, 0)
sizer_1.Add(sizer_2, 1, wx.EXPAND, 0)
sizer_1.Add((20, 20), 0, 0, 0)
sizer_4.Add(self.voltageCtrl, 1, wx.EXPAND, 0)
sizer_4.Add(self.speedCtrl, 1, wx.EXPAND, 0)
sizer_1.Add(sizer_4, 1, wx.EXPAND, 0)
sizer_1.Add((20, 20), 0, 0, 0)
self.SetSizer(sizer_1)
sizer_1.Fit(self)
self.Layout()
# end wxGlade
def OnData(self, evt):
print "Received Data"
self.app.AddTest2(evt.vibTest)
def OnUpdate(self, evt):
print "Status update"
self.running = evt.running
if evt.error:
self.error = True;
self.text_ctrl_1.WriteText("ERROR: ")
self.text_ctrl_1.SetBackgroundColour("Red")
self.text_ctrl_1.WriteText("%s\n"%evt.msg)
if (not self.running):
if (not self.error):
self.text_ctrl_1.SetBackgroundColour("Green")
self.text_ctrl_1.write(" ") # so that the background is redrawn
self.button.SetLabel("Close")
if evt.speed != None:
self.speedCtrl.SetSpeedValue(evt.speed)
if evt.voltage != None:
vmin,vmax,v = evt.voltage
if self.firstVoltage:
ticks = ["", "%.1f V"%vmin, "", "%.1f V"%vmax, ""]
self.voltageCtrl.SetTicks(ticks)
self.firstVoltage = False
i = (v-vmin)/(vmax-vmin) # 0..1
i *= 2
i = i+1
i = min(max(i,0),4)
self.voltageCtrl.SetSpeedValue(i)
def onButton(self, event): # wxGlade: MeasureDialog.<event_handler>
if (not self.running):
self.Destroy()
else:
self.app.cancelMeasurement()
# end of class MeasureDialog
class SettingsDialog(wx.Dialog):
def __init__(self, *args, **kwds):
# begin wxGlade: SettingsDialog.__init__
kwds["style"] = wx.DEFAULT_DIALOG_STYLE
wx.Dialog.__init__(self, *args, **kwds)
self.button_5 = wx.Button(self, wx.ID_CANCEL, "")
self.button_6 = wx.Button(self, wx.ID_OK, "")
self.__set_properties()
self.__do_layout()
self.Bind(wx.EVT_BUTTON, self.onOK, self.button_6)
# end wxGlade
# The first argument that is passed to the constructor is the parent
self.settings = args[0].app.settings
# Add text-boxes for all settings
self.tb = []
self.grid_sizer_2.SetRows(len(self.settings))
for setting in self.settings.iteritems():
lb = wx.StaticText(self, -1, setting[1].descr, style=wx.ALIGN_RIGHT)
tb = wx.TextCtrl(self, -1, str(setting[1].value))
self.grid_sizer_2.Add(lb, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 0)
self.grid_sizer_2.Add(tb, 0, 0, 0)
self.tb.append(tb)
self.sizer_5.Fit(self)
self.Layout()
def __set_properties(self):
# begin wxGlade: SettingsDialog.__set_properties
self.SetTitle("Settings")
# end wxGlade
def __do_layout(self):
# begin wxGlade: SettingsDialog.__do_layout
sizer_5 = wx.BoxSizer(wx.VERTICAL)
grid_sizer_3 = wx.GridSizer(1, 2, 0, 0)
sizer_6 = wx.BoxSizer(wx.HORIZONTAL)
grid_sizer_2 = wx.GridSizer(1, 2, 4, 4)
sizer_5.Add((20, 20), 0, 0, 0)
sizer_6.Add((20, 20), 0, 0, 0)
sizer_6.Add(grid_sizer_2, 0, 0, 0)
sizer_6.Add((20, 20), 0, 0, 0)
sizer_5.Add(sizer_6, 1, wx.EXPAND, 0)
sizer_5.Add((20, 20), 0, 0, 0)
grid_sizer_3.Add(self.button_5, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, 0)
grid_sizer_3.Add(self.button_6, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, 0)
sizer_5.Add(grid_sizer_3, 0, wx.EXPAND, 0)
sizer_5.Add((20, 20), 0, 0, 0)
self.SetSizer(sizer_5)
sizer_5.Fit(self)
self.Layout()
# end wxGlade
# Store some of the items, we will need them later
self.grid_sizer_2 = grid_sizer_2
self.sizer_5 = sizer_5
def onOK(self, event): # wxGlade: SettingsDialog.<event_handler>
print "Updating parameters"
try:
i=0
for setting in self.settings.iteritems():
print setting[0], self.tb[i].GetValue()
setting[1].set(self.tb[i].GetValue())
i += 1
event.Skip()
except:
wx.MessageBox("Invalid format for \"%s\" setting." % setting[1].descr)
# end of class SettingsDialog
class MainFrame(wx.Frame):
def __init__(self, *args, **kwds):
# begin wxGlade: MainFrame.__init__
kwds["style"] = wx.DEFAULT_FRAME_STYLE
wx.Frame.__init__(self, *args, **kwds)
# Menu Bar
self.frame_1_menubar = wx.MenuBar()
wxglade_tmp_menu = wx.Menu()
wxglade_tmp_menu.Append(101, "Settings", "", wx.ITEM_NORMAL)
wxglade_tmp_menu.AppendSeparator()
wxglade_tmp_menu.Append(150, "Exit", "", wx.ITEM_NORMAL)
self.frame_1_menubar.Append(wxglade_tmp_menu, "&File")
wxglade_tmp_menu = wx.Menu()
wxglade_tmp_menu.Append(301, "Delete All\tAlt+D", "", wx.ITEM_NORMAL)
wxglade_tmp_menu.Append(302, "Delete Selected\tCtrl+D", "", wx.ITEM_NORMAL)
wxglade_tmp_menu.AppendSeparator()
wxglade_tmp_menu.Append(310, "Select All\tCtrl+A", "", wx.ITEM_NORMAL)
wxglade_tmp_menu.AppendSeparator()
wxglade_tmp_menu.Append(303, "Load\tCtrl+L", "", wx.ITEM_NORMAL)
wxglade_tmp_menu.Append(304, "Save\tCtrl+S", "", wx.ITEM_NORMAL)
self.frame_1_menubar.Append(wxglade_tmp_menu, "TestSet")
wxglade_tmp_menu = wx.Menu()
wxglade_tmp_menu.Append(401, "Flash VibTest FC software", "", wx.ITEM_NORMAL)
wxglade_tmp_menu.Append(402, "Restore original FC software", "", wx.ITEM_NORMAL)
self.frame_1_menubar.Append(wxglade_tmp_menu, "MK")
wxglade_tmp_menu = wx.Menu()
wxglade_tmp_menu.Append(1099, "About", "", wx.ITEM_NORMAL)
self.frame_1_menubar.Append(wxglade_tmp_menu, "Help")
self.SetMenuBar(self.frame_1_menubar)
# Menu Bar end
self.label_1 = wx.StaticText(self, -1, "Test Description :", style=wx.ALIGN_RIGHT)
self.descrCtrl = wx.TextCtrl(self, -1, "N/A")
self.label_2 = wx.StaticText(self, -1, "Channel(s) :", style=wx.ALIGN_RIGHT)
self.accTopCb = wx.CheckBox(self, -1, "ACC Top")
self.accRollCb = wx.CheckBox(self, -1, "ACC Roll")
self.accNickCb = wx.CheckBox(self, -1, "ACC Nick")
self.label_3 = wx.StaticText(self, -1, "Motor(s) :", style=wx.ALIGN_RIGHT)
self.motorsCtrl = wx.TextCtrl(self, -1, "1")
self.label_4 = wx.StaticText(self, -1, "Speed(s) :")
self.speedCtrl = wx.TextCtrl(self, -1, "100-200:10")
self.bitmap_button_1 = wx.BitmapButton(self, -1, wx.Bitmap("Resources\\Fairytale_player_play.png", wx.BITMAP_TYPE_ANY))
self.static_line_1 = wx.StaticLine(self, -1)
self.graphCtrl = wx.lib.plot.PlotCanvas(self, size=(800,300))
self.label_40 = wx.StaticText(self, -1, "Graph Type ")
self.graphTypeChoice = wx.Choice(self, -1, choices=["Raw Signal", "Filtered Signal", "Spectrum"])
self.label_41 = wx.StaticText(self, -1, "Y Axis Range ")
self.yAxisChoice = wx.Choice(self, -1, choices=["25", "50", "75", "100", "200"])
self.copyGraphButton = wx.Button(self, -1, "Copy Graph Data")
self.TestListCtrl = wx.ListCtrl(self, -1, style=wx.LC_REPORT|wx.SUNKEN_BORDER)
self.__set_properties()
self.__do_layout()
self.Bind(wx.EVT_MENU, self.OnSettings, id=101)
self.Bind(wx.EVT_MENU, self.onExit, id=150)
self.Bind(wx.EVT_MENU, self.onClear, id=301)
self.Bind(wx.EVT_MENU, self.onClearSelected, id=302)
self.Bind(wx.EVT_MENU, self.onSelectAll, id=310)
self.Bind(wx.EVT_MENU, self.OnImport, id=303)
self.Bind(wx.EVT_MENU, self.onExport, id=304)
self.Bind(wx.EVT_MENU, self.onAbout, id=1099)
self.Bind(wx.EVT_BUTTON, self.onStartMeasure, self.bitmap_button_1)
self.Bind(wx.EVT_CHOICE, self.onGraphTypeChange, self.graphTypeChoice)
self.Bind(wx.EVT_CHOICE, self.onYAxisChange, self.yAxisChoice)
self.Bind(wx.EVT_BUTTON, self.onCopyGraphData, self.copyGraphButton)
# end wxGlade
favicon = wx.Icon('%s/Resources/60px-Procman.ico' % rootPath, wx.BITMAP_TYPE_ICO, 32, 32)
wx.Frame.SetIcon(self, favicon)
def setApp(self, app):
self.app = app
def __set_properties(self):
# begin wxGlade: MainFrame.__set_properties
self.SetTitle("VibrationTest")
self.SetSize((850, 700))
self.label_1.SetMinSize((110, -1))
self.label_1.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
self.descrCtrl.SetMinSize((350, -1))
self.label_2.SetMinSize((110, -1))
self.label_2.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
self.accTopCb.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
self.accRollCb.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
self.accRollCb.SetValue(1)
self.accNickCb.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
self.label_3.SetMinSize((110, -1))
self.label_3.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
self.label_4.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
self.speedCtrl.SetToolTipString("e.g. \n 100 \n 100,150 \n 100-200:10 \n 50,100-200:10 \n 5*100,5*200")
self.bitmap_button_1.SetToolTipString("Start Measurement")
self.bitmap_button_1.SetSize(self.bitmap_button_1.GetBestSize())
self.static_line_1.SetMinSize((800,3))
self.graphCtrl.SetMinSize((800,300))
self.label_40.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
self.graphTypeChoice.SetSelection(0)
self.label_41.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
self.yAxisChoice.SetSelection(1)
self.copyGraphButton.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
self.TestListCtrl.SetMinSize((800,300))
self.TestListCtrl.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
# end wxGlade
def __do_layout(self):
# begin wxGlade: MainFrame.__do_layout
sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
sizer_8 = wx.BoxSizer(wx.VERTICAL)
sizer_11 = wx.BoxSizer(wx.VERTICAL)
sizer_12 = wx.BoxSizer(wx.HORIZONTAL)
sizer_17 = wx.BoxSizer(wx.VERTICAL)
sizer_9 = wx.BoxSizer(wx.HORIZONTAL)
sizer_7 = wx.BoxSizer(wx.HORIZONTAL)
sizer_13 = wx.BoxSizer(wx.VERTICAL)
sizer_16 = wx.BoxSizer(wx.HORIZONTAL)
sizer_15 = wx.BoxSizer(wx.HORIZONTAL)
sizer_14 = wx.BoxSizer(wx.HORIZONTAL)
sizer_3.Add((20, 20), 0, 0, 0)
sizer_8.Add((20, 20), 0, 0, 0)
sizer_14.Add(self.label_1, 0, wx.ALIGN_CENTER_VERTICAL, 0)
sizer_14.Add((20, 20), 0, 0, 0)
sizer_14.Add(self.descrCtrl, 0, wx.ALIGN_CENTER_VERTICAL, 0)
sizer_13.Add(sizer_14, 1, wx.EXPAND, 0)
sizer_13.Add((20, 5), 0, 0, 0)
sizer_15.Add(self.label_2, 0, wx.ALIGN_CENTER_VERTICAL, 0)
sizer_15.Add((20, 20), 0, 0, 0)
sizer_15.Add(self.accTopCb, 0, wx.ALIGN_CENTER_VERTICAL, 0)
sizer_15.Add((20, 20), 0, 0, 0)
sizer_15.Add(self.accRollCb, 0, wx.ALIGN_CENTER_VERTICAL, 0)
sizer_15.Add((20, 20), 0, 0, 0)
sizer_15.Add(self.accNickCb, 0, wx.ALIGN_CENTER_VERTICAL, 0)
sizer_13.Add(sizer_15, 1, wx.EXPAND, 0)
sizer_13.Add((20, 5), 0, 0, 0)
sizer_16.Add(self.label_3, 0, wx.ALIGN_CENTER_VERTICAL, 0)
sizer_16.Add((20, 20), 0, 0, 0)
sizer_16.Add(self.motorsCtrl, 0, wx.ALIGN_CENTER_VERTICAL, 0)
sizer_16.Add((50, 20), 0, 0, 0)
sizer_16.Add(self.label_4, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 0)
sizer_16.Add((20, 20), 0, 0, 0)
sizer_16.Add(self.speedCtrl, 0, wx.ALIGN_CENTER_VERTICAL, 0)
sizer_13.Add(sizer_16, 1, wx.EXPAND, 0)
sizer_7.Add(sizer_13, 1, wx.EXPAND, 0)
sizer_7.Add((20, 20), 0, 0, 0)
sizer_7.Add((20, 20), 0, 0, 0)
sizer_9.Add(sizer_7, 1, wx.EXPAND, 0)
sizer_9.Add(self.bitmap_button_1, 0, 0, 0)
sizer_8.Add(sizer_9, 0, 0, 0)
sizer_17.Add((20, 20), 0, 0, 0)
sizer_17.Add(self.static_line_1, 0, wx.EXPAND, 0)
sizer_17.Add((20, 20), 0, 0, 0)
sizer_8.Add(sizer_17, 0, wx.EXPAND, 0)
sizer_11.Add(self.graphCtrl, 1, wx.EXPAND, 0)
sizer_11.Add((20, 5), 0, 0, 0)
sizer_12.Add(self.label_40, 0, wx.ALIGN_CENTER_VERTICAL, 0)
sizer_12.Add(self.graphTypeChoice, 0, 0, 0)
sizer_12.Add((40, 20), 0, 0, 0)
sizer_12.Add(self.label_41, 0, wx.ALIGN_CENTER_VERTICAL, 0)
sizer_12.Add(self.yAxisChoice, 0, 0, 0)
sizer_12.Add((80, 20), 0, 0, 0)
sizer_12.Add(self.copyGraphButton, 0, 0, 0)
sizer_11.Add(sizer_12, 0, 0, 0)
sizer_8.Add(sizer_11, 0, 0, 0)
sizer_8.Add((20, 30), 0, 0, 0)
sizer_8.Add(self.TestListCtrl, 1, 0, 0)
sizer_8.Add((20, 20), 0, 0, 0)
sizer_3.Add(sizer_8, 1, wx.EXPAND, 0)
self.SetSizer(sizer_3)
self.Layout()
self.SetSize((850, 700))
# end wxGlade
# List events
self.TestListCtrl.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnTestSelected, self.TestListCtrl)
# Configure Graph
#self.graphCtrl = wx.lib.plot.PlotCanvas(self.GraphPanel, size=(800,300))
self.graphCtrl.SetPointLabelFunc(self.DrawPointLabel)
self.graphCtrl.SetFont(wx.Font(10,wx.SWISS,wx.NORMAL,wx.NORMAL))
self.graphCtrl.SetFontSizeAxis(10)
self.graphCtrl.SetFontSizeLegend(7)
self.graphCtrl.setLogScale((False,False))
# Configure TestListCtrl
self.TestListCtrl.InsertColumn(0, "Description")
self.TestListCtrl.InsertColumn(1, "Voltage")
self.TestListCtrl.InsertColumn(2, "Speed")
self.TestListCtrl.InsertColumn(3, "Channel")
self.TestListCtrl.InsertColumn(4, "Vibration Value")
self.TestListCtrl.SetColumnWidth(4, 500)
def DrawPointLabel(self, dc, mDataDict):
"""This is the fuction that defines how the pointLabels are plotted
dc - DC that will be passed
mDataDict - Dictionary of data that you want to use for the pointLabel
As an example I have decided I want a box at the curve point
with some text information about the curve plotted below.
Any wxDC method can be used.
"""
# ----------
dc.SetPen(wx.Pen(wx.BLACK))
dc.SetBrush(wx.Brush( wx.BLACK, wx.SOLID ) )
sx, sy = mDataDict["scaledXY"] #scaled x,y of closest point
dc.DrawRectangle( sx-5,sy-5, 10, 10) #10by10 square centered on point
px,py = mDataDict["pointXY"]
cNum = mDataDict["curveNum"]
pntIn = mDataDict["pIndex"]
legend = mDataDict["legend"]
#make a string to display
s = "Crv# %i, '%s', Pt. (%.2f,%.2f), PtInd %i" %(cNum, legend, px, py, pntIn)
dc.DrawText(s, sx , sy+1)
# -----------
def onNewTest(self, test):
index = self.TestListCtrl.InsertStringItem(sys.maxint, test.descr)
self._fillRowInTestList(index, test)
self.TestListCtrl.Select(index)
def _fillRowInTestList(self, index, test):
self.TestListCtrl.SetStringItem(index, 0, test.descr)
self.TestListCtrl.SetStringItem(index, 1, "%.1f V" %test.voltage)
self.TestListCtrl.SetStringItem(index, 2, str(test.speed))
self.TestListCtrl.SetStringItem(index, 3, test.channel)
vv = test.getVibValue()
vvs = "|%s| (%.1f)" % ("----------------------------------------------------------------------------------------------------"[0:min(int(vv+1)/2,100)], vv)
self.TestListCtrl.SetStringItem(index, 4, vvs)
def refreshData(self):
for idx in range(len(self.app.VibTests)):
self._fillRowInTestList(idx, self.app.getTest(idx))
self.drawGraph()
def OnTestSelected(self, event):
testId = event.m_itemIndex
print "Test Selected id=%d" % (testId)
self.activeTestId = testId
self.drawGraph()
def orderSelectedTests(self):
tests = []
idx = self.TestListCtrl.GetFirstSelected()
while idx != -1:
header = "%s %s"%(self.app.getTest(idx).descr,self.app.getTest(idx).channel)
found = False
for t in tests:
if t[0] == header:
t.append(idx)
found = True
break
if not found:
tests.append([header, idx])
idx = self.TestListCtrl.GetNextSelected(idx)
return tests
def drawGraph(self):
y = int(self.yAxisChoice.GetStringSelection())
nbSelected = self.TestListCtrl.SelectedItemCount
if nbSelected == 0:
self.graphCtrl.Clear()
elif nbSelected > 1:
self.graphTypeChoice.Disable()
self.copyGraphButton.Enable()
tests = self.orderSelectedTests()
lines = []
maxX = 0
cCnt = 0
for s in tests:
data = []
x=1
for t in s[1:]:
data.append([x,self.app.getTest(t).getVibValue()])
x += 1
lines.append(wx.lib.plot.PolyLine(data, legend= s[0], colour=COLORS[cCnt], width=2))
lines.append(wx.lib.plot.PolyMarker(data, legend= "", colour=COLORS[cCnt], marker='circle',size=2))
maxX = max(maxX, x)
cCnt += 1
title = "Comparing tests"
self.graphCtrl.setLogScale((False,False))
self.graphCtrl.Draw(wx.lib.plot.PlotGraphics(lines, title, "Test", "Vibration Value"), xAxis=(1,maxX), yAxis=(0,y))
self.graphCtrl.SetEnableGrid('Horizontal')
self.graphCtrl.SetEnableLegend(True)
else:
self.graphTypeChoice.Enable()
self.copyGraphButton.Disable()
vibTest = self.app.getTest(self.activeTestId)
nb = vibTest.getDataLen()
if self.graphTypeChoice.GetSelection() == 0:
xydata = _Numeric.linspace(0,0.09*nb,2*nb)
xydata.shape = (nb, 2)
xydata[:,1] = vibTest.getRawData()
line = wx.lib.plot.PolyLine(xydata, legend= 'Raw Data', colour='red', width=2)
title = "Raw Signal: %s %s %d" %(vibTest.descr, vibTest.channel, vibTest.speed)
self.graphCtrl.setLogScale((False,False))
self.graphCtrl.Draw(wx.lib.plot.PlotGraphics([line], title, "Time (ms)", "Acc"), yAxis= (-y/2,y/2))
self.graphCtrl.SetEnableGrid('Horizontal')
self.graphCtrl.SetEnableLegend(False)
if self.graphTypeChoice.GetSelection() == 1:
xydata = _Numeric.linspace(0,0.09*nb,2*nb)
xydata.shape = (nb, 2)
xydata[:,1] = vibTest.getFilteredData()
line = wx.lib.plot.PolyLine(xydata, legend= 'Raw Data', colour='red', width=2)
title = "Filtered Signal: %s %s %d" %(vibTest.descr, vibTest.channel, vibTest.speed)
self.graphCtrl.setLogScale((False,False))
self.graphCtrl.Draw(wx.lib.plot.PlotGraphics([line], title, "Time (ms)", "Acc"), yAxis= (-y/2,y/2))
self.graphCtrl.SetEnableGrid('Horizontal')
self.graphCtrl.SetEnableLegend(False)
elif self.graphTypeChoice.GetSelection() == 2:
xydata = _Numeric.linspace(0,FS/2,nb)
xydata.shape = (nb/2, 2)
xydata[:,1] = vibTest.getSpectrum()
#print xydata
line = wx.lib.plot.PolyLine(xydata, legend= 'Spectrum', colour='red')
markers = wx.lib.plot.PolyMarker(xydata, legend= '', colour='red', marker='circle',size=2)
fc = self.app.settings["hpf"].value
filterLine1 = wx.lib.plot.PolyLine(((fc,0),(fc,y)), legend='HP Filter', colour='Black', width=4)
fc = self.app.settings["lpf"].value
filterLine2 = wx.lib.plot.PolyLine(((fc,0),(fc,y)), legend='HP Filter', colour='Black', width=4)
title = "Spectrum: %s %s %d" %(vibTest.descr, vibTest.channel, vibTest.speed)
self.graphCtrl.setLogScale((True,False))
self.graphCtrl.Draw(wx.lib.plot.PlotGraphics([line,markers, filterLine1, filterLine2], title, "Freq (Hz)", "Acc"), xAxis=(20,500), yAxis= (0,y))
self.graphCtrl.SetEnableGrid(True)
self.graphCtrl.SetEnableLegend(False)
def OnImport(self, event): # wxGlade: MainFrame.<event_handler>
dlg = wx.FileDialog(
self, message="Choose a file",
defaultDir="%s/Data/" % os.getcwd(),
defaultFile=".",
wildcard="Text files (*.txt)|*.txt|All files (*.*)|*.*",
style=wx.OPEN | wx.CHANGE_DIR
)
if dlg.ShowModal() == wx.ID_OK:
paths = dlg.GetPaths();
self.app.loadTests(paths[0])
dlg.Destroy()
def onExport(self, event): # wxGlade: MainFrame.<event_handler>
dlg = wx.FileDialog(
self, message="Save file as ...",
defaultDir="%s/Data/" % os.getcwd(),
defaultFile=".",
wildcard="Text files (*.txt)|*.txt|All files (*.*)|*.*",
style=wx.SAVE
)
if dlg.ShowModal() == wx.ID_OK:
paths = dlg.GetPaths();
self.app.saveTests(paths[0])
dlg.Destroy()
def onYAxisChange(self, event): # wxGlade: MainFrame.<event_handler>
self.drawGraph()
def onGraphTypeChange(self, event): # wxGlade: MainFrame.<event_handler>
self.drawGraph()
def OnSettings(self, event): # wxGlade: MainFrame.<event_handler>
dlg = SettingsDialog(self, -1, "Sample Dialog", size=(350, 200),
#style=wx.CAPTION | wx.SYSTEM_MENU | wx.THICK_FRAME,
style=wx.DEFAULT_DIALOG_STYLE, # & ~wx.CLOSE_BOX
)
dlg.CenterOnScreen()
val = dlg.ShowModal() # this does not return until the dialog is closed.
dlg.Destroy()
self.app.onSettingsChanged(True)
def onStartMeasure(self, event): # wxGlade: MainFrame.<event_handler>
# Collect measure parameters
mp = MeasureParameters()
decoding = ""
try:
decoding = "Description"
mp.descr = self.descrCtrl.GetValue()
decoding = "Motor(s)"
mp.motors = map(int,self.motorsCtrl.GetValue().split(','))
for motor in mp.motors:
if (motor<1) or (motor>MOTOR_MAX):
raise Exception("Motor number should be between 1 and %d" % MOTOR_MAX)
decoding = "Channel(s)"
mp.channels = []
if self.accTopCb.IsChecked(): mp.channels.append(5)
if self.accRollCb.IsChecked(): mp.channels.append(6)
if self.accNickCb.IsChecked(): mp.channels.append(7)
decoding = "Speed(s)"
mp.speeds = []
for speedTxt in self.speedCtrl.GetValue().split(","):
if speedTxt.count("-") == 1:
# assume from-to:step format
speedTxt = speedTxt.split("-")
if len(speedTxt) != 2: raise Exception("Invalid format")
speedTxt[1] = speedTxt[1].split(":")
if len(speedTxt[1]) != 2: raise Exception("Invalid format")
mp.speeds = range(int(speedTxt[0]),int(speedTxt[1][0])+int(speedTxt[1][1]),int(speedTxt[1][1]))
else:
# assume s or s*n format
if speedTxt.count("*") == 1:
speedTxt = speedTxt.split("*")
for i in range(int(speedTxt[0])):
mp.speeds.append(int(speedTxt[1]))
else:
mp.speeds.append(int(speedTxt))
for speed in mp.speeds:
if (speed<0) or (speed>255):
raise Exception("Speed values should be between 0 and 255")
except Exception,e:
dial = wx.MessageDialog(None, 'Invalid paramter \"%s\"\n\n%s' % (decoding, str(e)), 'Error', wx.OK |
wx.ICON_ERROR)
dial.ShowModal()
raise e
print mp.descr
print mp.motors
print mp.channels
print mp.speeds
# create the dialog that will show the satus
dlg = MeasureDialog(self)
dlg.CenterOnScreen()
# Signal the application
self.app.startMeasure(mp, dlg)
# Show the dialog
val = dlg.ShowModal() # this does not return until the dialog is closed.
dlg.Destroy()
def _removeTest(self, idx):
print "Deleting test %d" % idx
self.app.removeTest(idx)
self.TestListCtrl.DeleteItem(idx)
def onClear(self, event): # wxGlade: MainFrame.<event_handler>
dial = wx.MessageDialog(None, 'Clear ALL tests?', 'Question',
wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
if dial.ShowModal() == wx.ID_YES:
print "Clear all tests"
for i in range(len(self.app.VibTests)-1, -1, -1):
self._removeTest(i)
self.drawGraph()
def onClearSelected(self, event): # wxGlade: MainFrame.<event_handler>
dial = wx.MessageDialog(None, 'Clear Selected tests?', 'Question',
wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
if dial.ShowModal() == wx.ID_YES:
while True:
idx = self.TestListCtrl.GetFirstSelected()
if idx == -1: break
self._removeTest(idx)
def onAbout(self, event): # wxGlade: MainFrame.<event_handler>
# First we create and fill the info object
print "about"
info = wx.AboutDialogInfo()
info.Name = "MK Vibration Test - "
info.Version = "v0.9 RC3 ($Rev: 653 $)".replace("$","")
info.Copyright = ""
info.Developers=["Frederic Goddeeris (Frederic@rc-flight.be)"]
info.Description = "Please consult the WIKI page for a complete description of the tool:"
info.WebSite = ("http://www.mikrokopter.de/ucwiki/en/VibrationTest", "VibrationTest WIKI page")
wx.AboutBox(info)
def onExit(self, event): # wxGlade: MainFrame.<event_handler>
self.Close(True)
def onSelectAll(self, event): # wxGlade: MainFrame.<event_handler>
for i in xrange(self.TestListCtrl.GetItemCount()):
self.TestListCtrl.Select(i)
def onCopyGraphData(self, event): # wxGlade: MainFrame.<event_handler>
clipdata = wx.TextDataObject()
txt = ""
idx = self.TestListCtrl.GetFirstSelected()
while idx != -1:
txt += ("%d\n" % self.app.getTest(idx).getVibValue())
idx = self.TestListCtrl.GetNextSelected(idx)
clipdata.SetText(txt)
wx.TheClipboard.Open()
wx.TheClipboard.SetData(clipdata)
wx.TheClipboard.Close()
# end of class MainFrame
class Setting:
def __init__(self, descr, defaultValue):
self.descr = descr
self.value = defaultValue
def set(self, newValue):
if isinstance(self.value, int):
self.value = int(newValue)
else:
self.value = str(newValue)
class MeasureParameters:
pass
class MeasureThread:
def __init__(self, measureParameters, evtConsumer):
self.mk = mkProto.MkComm()
self.param = measureParameters
self.evtConsumer = evtConsumer
self.cancel = False
self.running = False
def start(self):
thread.start_new_thread(self._run, ())
def stop(self):
self.cancel = True
def _testCancel(self):
if self.cancel:
raise Exception("Operation cancelled")
def _sendEvent(self, msg=None, error=False, parVoltage=None, speed=None):
evt = MeasStatusUpdateEvent(running=self.running, msg=msg, error=error, voltage=parVoltage, speed=speed)
wx.PostEvent(self.evtConsumer, evt)
def _setMotorSpeed(self, speed, settlingTime):
speeds = [0]*MOTOR_MAX
for motor in self.param.motors:
speeds[motor-1] = speed
for i in range(int(settlingTime*10)):
self._testCancel()
self.mk.setMotorTest(speeds)
time.sleep(.1)
self.currSpeed = speed
def _run(self):
self.running = True
self._sendEvent("Starting test \"%s\"" % self.param.descr)
self.currSpeed = 0
try:
self._sendEvent("Opening SerialPort \"%s\"" % self.param.serialPort)
self.mk.open(comPort=self.param.serialPort)
print "Sending FC->NC forwarding",
self.mk.sendNCRedirectUartFromFC()
print "Done"
msg = self.mk.getVersionMsg()
version = msg.getVersion()
self._sendEvent("Version: %d.%d" % version)
msg = self.mk.getDebugMsg()
voltage = msg.getVoltage()
if (voltage == 0):
# Board is probably fed by USB
minVoltage = 0
maxVoltage = 1
else:
# Determine the n umber of cells
if (voltage > 4.2*3):
nbCells = 4
else:
nbCells = 3
# Set minimum and maximum voltages
if self.param.minVoltage > 0:
minVoltage = self.param.minVoltage
else:
minVoltage = nbCells*3.5 # auto
if self.param.maxVoltage > 0:
maxVoltage = self.param.maxVoltage
else:
maxVoltage = nbCells*3.9
self._sendEvent("Voltage: %2.1fV" % voltage)
self._sendEvent("Min/Max Voltage: %2.1fV-%2.1fV" % (minVoltage, maxVoltage), parVoltage=(minVoltage, maxVoltage, voltage))
self._sendEvent("Starting motor(s) (speed=%d)... " % self.param.motorStartupSpeed, speed=self.param.motorStartupSpeed)
self._setMotorSpeed(self.param.motorStartupSpeed, self.param.motorStartupSettlingTime)
for speed in self.param.speeds:
if speed != self.currSpeed:
self._sendEvent("Changing motor speed to %d... " % speed, speed=speed)
self._setMotorSpeed(speed, 1)
for channel in self.param.channels:
self._setMotorSpeed(speed, .1)
msg = self.mk.getDebugMsg()
voltage = msg.getVoltage()
self._sendEvent("Getting data from channel %s" % CHANNEL_NAMES[channel], parVoltage=(minVoltage, maxVoltage, voltage))
data = self.mk.doVibrationTest(1000, channel)
vt = VibTest(self.param.descr, voltage, self.param.motors, speed, CHANNEL_NAMES[channel], data)
evt = MeasDataEvent(vibTest = vt)
wx.PostEvent(self.evtConsumer, evt)
if voltage<minVoltage:
raise Exception("Voltage too low")
self._setMotorSpeed(speed, .1)
time.sleep(1)
msg = self.mk.getDebugMsg()
voltage = msg.getVoltage()
self._sendEvent("Done !", parVoltage=(minVoltage, maxVoltage, voltage))
except Exception, e:
self._sendEvent("Exception \"%s\"" % e, error=True)
try:
self.mk.close()
except:
print "Failure closing MK serial port"
pass
self.running = False
self._sendEvent("", speed = 0)
class VibTest:
useRms = True
fc1 = None
fc2 = None
def __init__(self, descr, voltage, motor, speed, channel, rawData):
self.descr = descr
self.voltage = voltage
self.motor = motor
self.speed = speed
self.channel = channel
self.dataLen = len(rawData)
self.rawData = _Numeric.array(rawData)
self.dc = self.rawData.mean()
self.rawData -= self.dc
self.fft = _Numeric.fft.rfft(self.rawData)
self.spectrum = None
self.filteredData = None
self.vibValue = None
def getDescr(self):
return self.Descr
def getRawData(self):
return self.rawData
def getDataLen(self):
return self.dataLen
def getSpectrum(self):
if self.spectrum == None:
self.spectrum = _Numeric.absolute(self.fft[1:self.dataLen/2+1]) / (self.dataLen/2)
return self.spectrum
def refresh(self):
self.filteredData = None
self.vibValue = None
def getFilteredData(self):
if self.filteredData == None:
tmpfft = self.fft.copy()
fc = (float(self.fc1))/(FS/2)*len(tmpfft)
print "fc1=%d => fc=%f" % (self.fc1, fc)
for i in range(0,int(fc)+2):
tmpfft[i] = 0
fc = (float(self.fc2))/(FS/2)*len(tmpfft)
print "fc2=%d => fc=%f" % (self.fc2,fc)
for i in range(int(fc)+2, len(tmpfft)):
tmpfft[i] = 0
self.filteredData = _Numeric.fft.irfft(tmpfft)
return self.filteredData
def getVibValue(self):
if self.vibValue == None:
fd = self.getFilteredData()[100:-100];
if self.useRms:
print "RMS"
self.vibValue = math.sqrt(sum([x*x for x in fd])/len(fd))*2*math.sqrt(2)
else:
print "PP"
self.vibValue = max(fd)-min(fd)
return self.vibValue
class App(wx.App):
SETTINGSFILE = "settings.cfg"
def __init__(self, par):
self.VibTests = []
wx.App.__init__(self, par)
# Init settings
self.settings={}
self.settings["serialport"] = Setting("Serial Port", "COM1")
self.settings["startupspeed"] = Setting("Motor Startup Speed", 25)
self.settings["startupsettling"] = Setting("Motor Startup Setting time (s)", 3)
self.settings["serialport"] = Setting("Serial Port", "COM1")
self.settings["hpf"] = Setting("HP Filter cutoff (Hz)", 40)
self.settings["lpf"] = Setting("LP Filter cutoff (Hz)", 400)
self.settings["calcmethod"] = Setting("Calculation Method", "rms")
self.settings["minvoltage"] = Setting("Minimum Bettery Voltage (0=Automatic) (V) ", 0)
self.settings["maxvoltage"] = Setting("Maximum Bettery Voltage (0=Automatic) (V) ", 0)
self.readSettings()
if len(sys.argv)>1:
self.loadTests(sys.argv[1])
def readSettings(self):
print "Reading settings"
cp = ConfigParser.ConfigParser()
try:
cp.read("%s/%s" % (rootPath, App.SETTINGSFILE))
for setting in cp.items("DEFAULT"):
print " ",setting
try:
self.settings[setting[0]].set(setting[1])
except:
print "WARNING, unknown setting"
except:
print "ERROR reading settingsfile"
self.onSettingsChanged(False)
def storeSettings(self):
print "Storing settings"
cp = ConfigParser.ConfigParser()
for setting in self.settings.iteritems():
cp.set("", setting[0], setting[1].value)
file = open("%s/%s" % (rootPath, App.SETTINGSFILE), "w")
cp.write(file)
file.close()
def onSettingsChanged(self, store):
if store:
self.storeSettings()
if self.settings["calcmethod"].value == "rms":
VibTest.useRms = True
else:
VibTest.useRms = False
VibTest.fc1 = self.settings["hpf"].value
VibTest.fc2 = self.settings["lpf"].value
for test in self.VibTests:
test.refresh()
self.frame_1.refreshData()
def AddTest2(self, vibTest):
self.VibTests.append(vibTest)
self.frame_1.onNewTest(vibTest)
def AddTest(self, descr, voltage, motor, speed, channel, rawData):
test = VibTest(descr, voltage, motor, speed, channel, rawData)
self.AddTest2(test)
def removeTest(self, idx):
del(self.VibTests[idx])
def getTest(self, testId):
return self.VibTests[testId]
def OnInit(self):
wx.InitAllImageHandlers()
self.frame_1 = MainFrame(None, -1, "")
self.frame_1.setApp(self);
self.SetTopWindow(self.frame_1)
self.frame_1.CenterOnScreen()
self.frame_1.Show()
return 1
def saveTests(self, filePath):
try:
logfile = open(filePath, "r")
newFile = False
logfile.close()
except:
newFile = True
for test in self.VibTests:
if newFile:
logfile = open(filePath, "w")
print "Writing result to %s ..." % filePath,
logfile.write("%s %d %s\n" % (test.descr, test.speed, test.channel))
for value in test.rawData:
logfile.write("%d\n" % value)
logfile.close()
print "OK"
else:
print "Appending result to %s ..." % filePath,
logfile = open(filePath, "r")
prevData = []
for line in logfile:
prevData.append(line[:-1])
logfile.close()
logfile = open(filePath, "w")
logfile.write("%s,%s %d %s\n" % (prevData[0], test.descr, test.speed, test.channel))
i = 1
for value in test.rawData:
logfile.write("%s,%d\n" % (prevData[i], value))
i += 1
logfile.close()
print "OK"
newFile = False
def loadTests(self, filePath):
print "Importing file \"%s\"" % filePath
logfile = open(filePath, "r")
data = None
headers = (logfile.readline()[:-1]).split(',')
nbCols = len(headers)
print "NbCols =", nbCols
data = []
descr = []
speed = []
channel = []
for c in range(nbCols):
data.append([])
h = headers[c].split(' ')
descr.append(h[0]);
speed.append(h[1]);
channel.append(h[2]);
for line in logfile:
values = line.split(',')
for i in range(nbCols):
data[i].append(int(values[i]))
logfile.close()
for c in range(nbCols):
if (len(data[c]) % 2) != 0:
data[c].append(data[c][-1])
self.AddTest(descr[c], 0, 0, int(speed[c]), channel[c], data[c])
def startMeasure(self, measureParams, dialog):
print "Start measuring"
measureParams.serialPort = self.settings["serialport"].value
measureParams.motorStartupSpeed = self.settings["startupspeed"].value
measureParams.motorStartupSettlingTime = self.settings["startupsettling"].value
measureParams.minVoltage = self.settings["minvoltage"].value
measureParams.maxVoltage = self.settings["maxvoltage"].value
self.measureThread = MeasureThread(measureParams, dialog)
self.measureThread.start()
def cancelMeasurement(self):
print "Measuring CANCEL"
self.measureThread.stop()
# end of class App
if __name__ == "__main__":
rootPath = os.path.abspath(os.path.dirname(sys.argv[0]))
print rootPath
VibrationTestGui = App(0)
VibrationTestGui.MainLoop()