1 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
6 from Cura.util import machineCom
8 class debuggerWindow(wx.Frame):
9 def __init__(self, parent):
10 super(debuggerWindow, self).__init__(parent, title=_('Cura - PID Debugger'))
12 self.machineCom = None
13 self.machineCom = machineCom.MachineCom(callbackObject=self)
14 self.coolButton = wx.Button(self, -1, '0C')
15 self.heatupButton = wx.Button(self, -1, '200C')
16 self.heatupButton2 = wx.Button(self, -1, '260C')
17 self.heatupButton3 = wx.Button(self, -1, '300C')
18 self.fanOn = wx.Button(self, -1, 'Fan ON')
19 self.fanOn50 = wx.Button(self, -1, 'Fan ON 50%')
20 self.fanOff = wx.Button(self, -1, 'Fan OFF')
21 self.graph = temperatureGraph(self)
23 self.pValue = wx.TextCtrl(self, -1, '0')
24 self.iValue = wx.TextCtrl(self, -1, '0')
25 self.dValue = wx.TextCtrl(self, -1, '0')
27 self.sizer = wx.GridBagSizer(0, 0)
28 self.SetSizer(self.sizer)
29 self.sizer.Add(self.graph, pos=(0, 0), span=(1, 8), flag=wx.EXPAND)
30 self.sizer.Add(self.coolButton, pos=(1, 0), flag=wx.EXPAND)
31 self.sizer.Add(self.heatupButton, pos=(1, 1), flag=wx.EXPAND)
32 self.sizer.Add(self.heatupButton2, pos=(1, 2), flag=wx.EXPAND)
33 self.sizer.Add(self.heatupButton3, pos=(1, 3), flag=wx.EXPAND)
34 self.sizer.Add(self.fanOn, pos=(1, 4), flag=wx.EXPAND)
35 self.sizer.Add(self.fanOn50, pos=(1, 5), flag=wx.EXPAND)
36 self.sizer.Add(self.fanOff, pos=(1, 6), flag=wx.EXPAND)
37 self.sizer.Add(self.pValue, pos=(2, 0), flag=wx.EXPAND)
38 self.sizer.Add(self.iValue, pos=(2, 1), flag=wx.EXPAND)
39 self.sizer.Add(self.dValue, pos=(2, 2), flag=wx.EXPAND)
40 self.sizer.AddGrowableCol(7)
41 self.sizer.AddGrowableRow(0)
43 wx.EVT_CLOSE(self, self.OnClose)
44 self.Bind(wx.EVT_BUTTON, lambda e: self.setTemp(0), self.coolButton)
45 self.Bind(wx.EVT_BUTTON, lambda e: self.setTemp(200), self.heatupButton)
46 self.Bind(wx.EVT_BUTTON, lambda e: self.setTemp(260), self.heatupButton2)
47 self.Bind(wx.EVT_BUTTON, lambda e: self.setTemp(300), self.heatupButton3)
48 self.Bind(wx.EVT_BUTTON, lambda e: self.machineCom.sendCommand('M106'), self.fanOn)
49 self.Bind(wx.EVT_BUTTON, lambda e: self.machineCom.sendCommand('M106 S128'), self.fanOn50)
50 self.Bind(wx.EVT_BUTTON, lambda e: self.machineCom.sendCommand('M107'), self.fanOff)
51 self.Bind(wx.EVT_TEXT, self.updatePID, self.pValue)
52 self.Bind(wx.EVT_TEXT, self.updatePID, self.iValue)
53 self.Bind(wx.EVT_TEXT, self.updatePID, self.dValue)
58 def updatePID(self, e):
60 p = float(self.pValue.GetValue())
61 i = float(self.iValue.GetValue())
62 d = float(self.dValue.GetValue())
65 self.machineCom.sendCommand("M301 P%f I%f D%f" % (p, i, d))
67 def setTemp(self, temp):
68 self.targetTemp = temp
69 self.machineCom.sendCommand("M104 S%d" % (temp))
72 self.machineCom.close()
75 def mcLog(self, message):
78 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
81 def mcStateChange(self, state):
82 if self.machineCom is not None and self.machineCom.isOperational():
83 self.machineCom.sendCommand("M503\n")
84 self.machineCom.sendCommand("M503\n")
86 def mcMessage(self, message):
87 if 'PIDDEBUG' in message:
88 #echo: PIDDEBUG 0: Input 40.31 Output 0.00 pTerm 0.00 iTerm 0.00 dTerm 0.00
89 message = message.strip().split()
90 temperature = float(message[message.index("Input")+1])
91 heater_output = float(message[message.index("Output")+1])
92 pTerm = float(message[message.index("pTerm")+1])
93 iTerm = float(message[message.index("iTerm")+1])
94 dTerm = float(message[message.index("dTerm")+1])
96 self.graph.addPoint(temperature, heater_output, pTerm, iTerm, dTerm, self.targetTemp)
97 elif 'M301' in message:
98 for m in message.strip().split():
100 wx.CallAfter(self.pValue.SetValue, m[1:])
102 wx.CallAfter(self.iValue.SetValue, m[1:])
104 wx.CallAfter(self.dValue.SetValue, m[1:])
106 def mcProgress(self, lineNr):
109 def mcZChange(self, newZ):
112 class temperatureGraph(wx.Panel):
113 def __init__(self, parent):
114 super(temperatureGraph, self).__init__(parent)
116 self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
117 self.Bind(wx.EVT_SIZE, self.OnSize)
118 self.Bind(wx.EVT_PAINT, self.OnDraw)
120 self.lastDraw = time.time() - 1.0
122 self.backBuffer = None
123 self.SetMinSize((320, 200))
124 self.addPoint(0,0,0,0,0,0)
126 def OnEraseBackground(self, e):
130 if self.backBuffer is None or self.GetSize() != self.backBuffer.GetSize():
131 self.backBuffer = wx.EmptyBitmap(*self.GetSizeTuple())
132 self.UpdateDrawing(True)
135 dc = wx.BufferedPaintDC(self, self.backBuffer)
137 def _drawBackgroundForLine(self, dc, color, f):
138 w, h = self.GetSizeTuple()
139 color = wx.Pen(color)
143 for p in self.points:
144 x1 = int(w - (self.now - p[0]) * self.timeScale)
146 for x in xrange(x0, x1 + 1):
147 v = float(x - x0) / float(x1 - x0 + 1) * (value - v0) + v0
148 dc.DrawLine(x, h, x, h - (v * h / 300))
152 def _drawLine(self, dc, color, f):
153 w, h = self.GetSizeTuple()
154 color = wx.Pen(color)
158 for p in self.points:
159 x1 = int(w - (self.now - p[0]) * self.timeScale)
161 dc.DrawLine(x0, h - (v0 * h / 300), x1, h - (value * h / 300), )
162 dc.DrawPoint(x1, h - (value * h / 300), )
166 def UpdateDrawing(self, force=False):
170 if not force and now - self.lastDraw < 0.1:
173 dc.SelectObject(self.backBuffer)
175 dc.SetFont(wx.SystemSettings.GetFont(wx.SYS_SYSTEM_FONT))
176 w, h = self.GetSizeTuple()
177 bgLinePen = wx.Pen('#A0A0A0')
179 #Draw the background up to the current temperatures.
180 self._drawBackgroundForLine(dc, '#FFD0D0', lambda p: p[1])#temp
181 self._drawBackgroundForLine(dc, '#D0D0FF', lambda p: p[3])#pTerm
182 self._drawBackgroundForLine(dc, '#D0FFD0', lambda p: abs(p[5]))#dTerm
185 for x in xrange(w, 0, -5 * self.timeScale):
187 dc.DrawLine(x, 0, x, h)
189 for y in xrange(h - 1, 0, -h * 50 / 300):
191 dc.DrawLine(0, y, w, y)
192 dc.DrawText(str(tmpNr), 0, y - dc.GetFont().GetPixelSize().GetHeight())
194 dc.DrawLine(0, 0, w, 0)
195 dc.DrawLine(0, 0, 0, h)
196 if len(self.points) > 10:
199 for n in xrange(0, 10):
200 tempAvg += self.points[-n-1][1]
201 heaterAvg += self.points[-n-1][2]
202 dc.DrawText(_("Temp: %d Heater: %d") % (tempAvg / 10, heaterAvg * 100 / 255 / 10), 0, 0)
205 self._drawLine(dc, '#404040', lambda p: p[6])#target
206 self._drawLine(dc, '#40FFFF', lambda p: p[3])#pTerm
207 self._drawLine(dc, '#FF40FF', lambda p: p[4])#iTerm
208 self._drawLine(dc, '#FFFF40', lambda p: p[5])#dTerm
209 self._drawLine(dc, '#4040FF', lambda p: -p[5])#dTerm
210 self._drawLine(dc, '#FF4040', lambda p: p[1])#temp
211 self._drawLine(dc, '#40FF40', lambda p: p[2])#heater
213 self.lastDraw = time.time()
216 self.Refresh(eraseBackground=False)
219 while len(self.points) > 0 and (time.time() - self.points[0][0]) > (w + 20) / self.timeScale:
222 def addPoint(self, temperature, heater_output, pTerm, iTerm, dTerm, targetTemp):
223 self.points.append([time.time(), temperature, heater_output, pTerm, iTerm, dTerm, targetTemp])
224 wx.CallAfter(self.UpdateDrawing)