diff --git a/conf/tools/nederdrone_status.xml b/conf/tools/nederdrone_status.xml new file mode 100644 index 00000000000..efc7b5567c7 --- /dev/null +++ b/conf/tools/nederdrone_status.xml @@ -0,0 +1,2 @@ + + diff --git a/sw/ground_segment/python/atc/atc.py b/sw/ground_segment/python/atc/atc.py index 71486469be6..f5412924e20 100755 --- a/sw/ground_segment/python/atc/atc.py +++ b/sw/ground_segment/python/atc/atc.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # Copyright (C) 2016 TUDelft # diff --git a/sw/ground_segment/python/atc/atc_frame.py b/sw/ground_segment/python/atc/atc_frame.py index 30aad7e1f65..ea7ce039f79 100644 --- a/sw/ground_segment/python/atc/atc_frame.py +++ b/sw/ground_segment/python/atc/atc_frame.py @@ -24,7 +24,7 @@ import threading import math import array -from cStringIO import StringIO +from io import StringIO PPRZ_HOME = os.getenv("PAPARAZZI_HOME", os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../../..'))) @@ -154,7 +154,7 @@ def __init__(self): if self.cfg.Exists('left'): self.x = int(self.cfg.Read('left')) self.y = int(self.cfg.Read('top')) - self.SetPosition(wx.Point(self.x,self.y), wx.SIZE_USE_EXISTING) + self.SetPosition(wx.Point(self.x,self.y)) def OnClose(self, event): self.interface.shutdown() diff --git a/sw/ground_segment/python/distance_counter/dist.py b/sw/ground_segment/python/distance_counter/dist.py index 67732b5bedf..8f8626c12e6 100755 --- a/sw/ground_segment/python/distance_counter/dist.py +++ b/sw/ground_segment/python/distance_counter/dist.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # Copyright (C) 2016 TUDelft # diff --git a/sw/ground_segment/python/distance_counter/distance_counter.py b/sw/ground_segment/python/distance_counter/distance_counter.py index da150038235..3ae81e42cc1 100644 --- a/sw/ground_segment/python/distance_counter/distance_counter.py +++ b/sw/ground_segment/python/distance_counter/distance_counter.py @@ -25,7 +25,7 @@ import threading import socket import array -from cStringIO import StringIO +from io import StringIO import wx import array from PIL import Image diff --git a/sw/ground_segment/python/energy_mon/energy_mon.py b/sw/ground_segment/python/energy_mon/energy_mon.py index eee387fe6f9..bc511037076 100755 --- a/sw/ground_segment/python/energy_mon/energy_mon.py +++ b/sw/ground_segment/python/energy_mon/energy_mon.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # Copyright (C) 2018 TUDelft # diff --git a/sw/ground_segment/python/energy_mon/energy_mon_viewer.py b/sw/ground_segment/python/energy_mon/energy_mon_viewer.py index 73d89f9416b..f3cc6cae7d0 100644 --- a/sw/ground_segment/python/energy_mon/energy_mon_viewer.py +++ b/sw/ground_segment/python/energy_mon/energy_mon_viewer.py @@ -291,7 +291,7 @@ def StatusBox(self, dc, nr, txt, percent, color): spacing = boxh+10 dc.SetPen(wx.Pen(wx.Colour(0,0,0))) - dc.SetBrush(wx.Brush(wx.Colour(220,220,220))) + dc.SetBrush(wx.Brush(wx.Colour(220,220,220))) dc.DrawRectangle(tdx, int(nr*spacing+tdx), int(boxw), boxh) dc.SetTextForeground(wx.Colour(0, 0, 0)) if color < 0.2: @@ -317,7 +317,7 @@ def plot(self, dc, i1, i2): def DischargePlot(self, dc): self.tdx = int(self.stat * 10.0 / 300.0) dc.SetPen(wx.Pen(wx.Colour(0,0,0),1)) - dc.SetBrush(wx.Brush(wx.Colour(250,250,250))) + dc.SetBrush(wx.Brush(wx.Colour(250,250,250))) dc.DrawRectangle(self.plot_x(0.0), self.plot_y(1.0), self.w-self.stat-2*self.tdx, self.h-2*self.tdx) for i in range(0,6): @@ -427,7 +427,7 @@ def __init__(self): if self.cfg.Exists('left'): self.x = int(self.cfg.Read('left')) self.y = int(self.cfg.Read('top')) - self.SetPosition(wx.Point(self.x,self.y), wx.SIZE_USE_EXISTING) + self.SetPosition(wx.Point(self.x,self.y)) self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_SIZE, self.OnSize) diff --git a/sw/ground_segment/python/fuelcell/fuel_cell.py b/sw/ground_segment/python/fuelcell/fuel_cell.py new file mode 100755 index 00000000000..a200312a1c6 --- /dev/null +++ b/sw/ground_segment/python/fuelcell/fuel_cell.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2018 TUDelft +# +# This file is part of paparazzi. +# +# paparazzi is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# paparazzi is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with paparazzi. If not, see . +# + +import wx +import fuel_cell_viewer + +class FuelCellApp(wx.App): + def OnInit(self): + self.main = fuel_cell_viewer.FuelCellFrame() + self.main.Show() + self.SetTopWindow(self.main) + return True + +def main(): + application = FuelCellApp(0) + application.MainLoop() + +if __name__ == '__main__': + main() diff --git a/sw/ground_segment/python/fuelcell/fuel_cell_viewer.py b/sw/ground_segment/python/fuelcell/fuel_cell_viewer.py new file mode 100644 index 00000000000..575f19d975b --- /dev/null +++ b/sw/ground_segment/python/fuelcell/fuel_cell_viewer.py @@ -0,0 +1,548 @@ +# +# Copyright (C) 2018 TUDelft +# +# This file is part of paparazzi. +# +# paparazzi is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# paparazzi is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with paparazzi. If not, see . +# + +import wx + +import sys +import os +import math +import datetime + + +PPRZ_HOME = os.getenv("PAPARAZZI_HOME", os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), + '../../../..'))) + +PPRZ_SRC = os.getenv("PAPARAZZI_SRC", os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), + '../../../..'))) + +sys.path.append(PPRZ_HOME + "/var/lib/python") + +from pprzlink.ivy import IvyMessagesInterface + +WIDTH = 600 +BARH = 140 + + +def get_text_from_seconds(secs): + m, s = divmod(int(secs), int(60)) + return "{:02d}:{:02d}".format(m, s) + +class AirDataMessage(object): + def __init__(self, msg): + self.airspeed = float(msg['airspeed']) + +class EnergyMessage(object): + def __init__(self, msg): + self.volt = float(msg['voltage']) + self.current = float(msg['current']) + self.power = float(msg['power']) + self.energy = float(msg['energy']) + +class TempMessage(object): + def __init__(self, msg): + self.motor = float(msg['temp1']) + self.battery = float(msg['temp2']) + +class EscMessage(object): + def __init__(self, msg): + self.id = int(msg['motor_id']) + self.amp = float(msg['amps']) + self.rpm = float(msg['rpm']) + self.volt_b = float(msg['bat_volts']) + self.volt_m = float(msg['motor_volts']) + self.temperature = float(msg['power']) - 273.15 + self.energy = float(msg['energy']) + + def get_current(self): + return str(round(self.amp ,1)) + "A" + def get_current_perc(self): + return self.amp / 30 + + def get_rpm(self): + return str(round(self.rpm ,0)) + " rpm" + def get_rpm_perc(self): + return self.rpm / 4000 + def get_rpm_color(self): + if self.rpm < 2500: + return 1 + return 0.5 + + + def get_volt(self): + if (self.id in [6,7,8,9,16,17,18,19]): + return "Servo " + str(self.id) + " " +str(round(self.volt_m ,0)) + "V" + else: + return "Mot " + str(self.id) + " " +str(round(self.volt_m ,0)) + "V" + def get_volt_perc(self): + return self.volt_b / (6*4.2) + + def get_temp(self): + if self.temperature < -200: + return "xxx" + return str(round(self.temperature ,1)) + "C" + def get_temp_perc(self): + return self.temperature / 120.0 + + def get_temp_color(self): + if self.temperature < 0: + return 0 + elif self.temperature < 60: + return 1 + else: + return 0.5 + +class MotorList(object): + def __init__(self): + self.mot = [] + + def fill_from_esc_msg(self, esc): + added = False + for i in range(len(self.mot)): + if self.mot[i].id == esc.id: + self.mot[i] = esc + added = True + break + if not added: + self.mot.append(esc) + + +class BatteryCell(object): + def __init__(self): + self.voltage = 0 + self.current = 0 + self.power = 0 + self.energy = 0 + self.model = 0 + self.temperature = 0 + def fill_from_energy_msg(self, energy): + self.voltage = energy.volt + self.current = energy.current + self.power = energy.power + self.energy = energy.energy + self.model = 0 + def fill_from_temp_msg(self, temp): + self.temperature = temp.battery + + def get_volt(self): + return "Volt = "+str(round(self.voltage,2)) + " V" + + def get_current(self): + return "Amps = "+str(round(self.current,2)) + " A" + def get_energy(self): + return "Cell mAh = "+str(round(self.energy/1000.0 ,2)) + " Ah" + def get_temp(self): + return "Cell Temp = "+str(round(self.temperature ,2)) + def get_power_text(self): + return "Battery Power: {:.0f}W".format(self.get_power()) + def get_power2_text(self): + return "Battery Power: {:.0f}W".format(self.get_power2()) + def get_volt_perc(self): + return self.get_volt_percent(self.voltage) + def get_volt_percent(self,volt): + return (volt/6 - 2.5) / (4.3 - 2.5) + + def get_power(self): + return self.power + def get_power2(self): + return self.voltage * self.current + + def get_temp_perc(self): + return (self.temperature / 60) + def get_current_perc(self): + return (self.current / 200) + def get_energy_perc(self): + return (self.energy / 4* 4500 + 30000) + + def get_power_perc(self): + return (self.get_power()) / (2500) + + def get_volt_color(self): + if self.voltage < 3.2: + return 0.1 + elif self.voltage < 3.6: + return 0.5 + return 1 + + def get_current_color(self): + if self.current < 150: + return 1 + elif self.current > 200: + return 0.1 + return 0.5 + + def get_energy_color(self): + if self.energy > 3000: + return 0.1 + elif self.energy < 2000: + return 1 + return 0.5 + + def get_temp_color(self): + if (self.temperature > 20) & (self.temperature < 40): + return 1 + elif (self.temperature > 10) & (self.temperature < 55): + return 0.5 + return 0.1 + + def get_power_color(self): + if self.power < 800: + return 1 + return 0.5 + + +class PayloadMessage(object): + def __init__(self, msg): + self.values = ''.join(chr(int(x)) for x in msg['values']) + + + +class FuelCellStatus(object): + def _init_(self): + self.blink = 0 + + def update(self,msg): + self.msg = msg + if hasattr(self, 'blink'): + self.blink = 1 - self.blink + else: + self.blink = 0 + elements = self.msg.strip('<').strip('>').split(',') + if (len(elements) == 4): + self.tank = float(elements[0]) + self.battery = float(elements[1]) + self.status = elements[2] + self.error = elements[3] + + self.errors = [] + hex = '0000' + if (len(self.error) >= 4): + hex = self.error[2:6] + #array of 16 error codes + self.error_bin = bin(int(hex, 16))[2:].zfill(16) + + #else: + # print('ERROR: ' + msg) + + def get_raw(self): + return self.msg + def get_raw_color(self): + if self.blink == 0: + return 0 + return 1.0 + + def get_tank(self): + bar = round(5 + self.tank / 100 * 295,1) + return 'Cylinder ' + str(bar) + ' Bar' + def get_tank_perc(self): + return (self.tank) / 100.0 + def get_tank_color(self): + if (self.tank) < 10: + return 0.1 + elif int(self.tank) < 20: + return 0.5 + else: + return 1 + + def get_battery(self): + volt = round( self.battery / 100.0 * (24.0-19.6) + 19.6, 2) + return str(volt) + ' V' + def get_battery_perc(self): + return (self.battery) / 100.0 + def get_battery_color(self): + if (self.battery) < 10: + return 0.1 + elif (self.battery) < 20: + return 0.5 + else: + return 1 + + + def get_status(self): + if int(self.status) == 0: + return 'Starting' + elif int(self.status) == 1: + return 'Ready (wait for button press)' + elif int(self.status) == 2: + return 'Running' + elif int(self.status) == 3: + return 'Fault' + elif int(self.status) == 4: + return 'Battery only' + else: + return self.status + def get_status_perc(self): + return 0.0 + def get_status_color(self): + if int(self.status) < 1: + return 0.1 + elif int(self.status) == 1: + return 0.5 + else: + return 0.5 + + + def get_error(self): + return self.error + + def get_error_perc(self): + return 1.0 + def get_error_color(self): + if self.error[2:6] == '0000': + return 1.0 + return 0.1 + + + def get_error_nr(self, nr): + err = ["Stack1 OverTemp", "Stack2 OverTemp", "AuxBat UnderVolt", "AuxBat Overtemp", "No Fan", "", "Stack1 OverTemp", "Stack2 OverTemp", + "AuxBat UnderVolt", "AuxBat OverTemp", "Mast Timeout Start", "Master Timeout Stop", "Start Under Pressue", "Tank UnderPress", "Tank LowPress", "SafFlag bf Mastr En.", ""] + return self.error_bin[nr] + ' ' + err[nr] + def get_error_nr_color(self, nr): + if self.error_bin[nr] == '1': + return 0.1 + return 1 + + + + +class FuelCellFrame(wx.Frame): + def message_recv(self, ac_id, msg): + if msg.name == "ENERGY": + self.bat = EnergyMessage(msg) + self.cell.fill_from_energy_msg(self.bat) + + wx.CallAfter(self.update) + elif msg.name == "TEMP_ADC": + self.temp = TempMessage(msg) + self.cell.fill_from_temp_msg(self.temp) + wx.CallAfter(self.update) + + elif msg.name == "AIR_DATA": + self.air_data = AirDataMessage(msg) + wx.CallAfter(self.update) + + elif msg.name == "ESC": + self.esc = EscMessage(msg) + self.motors.fill_from_esc_msg(self.esc) + wx.CallAfter(self.update) + + elif msg.name == "PAYLOAD": + self.payload = PayloadMessage(msg) + self.fuelcell.update(self.payload.values) + #print("Payload: " + self.payload.values) + + + def update(self): + self.Refresh() + + def OnSize(self, event): + self.w = event.GetSize().x + self.h = event.GetSize().y + self.cfg.Write("width", str(self.w)); + self.cfg.Write("height", str(self.h)); + self.Refresh() + + def OnMove(self, event): + self.x = event.GetPosition().x + self.y = event.GetPosition().y + self.cfg.Write("left", str(self.x)); + self.cfg.Write("top", str(self.y)); + + + def StatusBox(self, dc, dx, dy, row, col, txt, percent, color): + if percent < 0: + percent = 0 + if percent > 1: + percent = 1 + boxw = self.stat + tdx = int(boxw * 10.0 / 300.0) + tdy = int(boxw * 6.0 / 300.0) + boxh = int(boxw * 40.0 / 300.0) + boxw = self.stat - 2*tdx + spacing = boxh+10 + + dc.SetPen(wx.Pen(wx.Colour(0,0,0))) + dc.SetBrush(wx.Brush(wx.Colour(220,220,220))) + dc.DrawRectangle(tdx + col * 200 + dx, int(row*spacing+tdx) +dy, int(boxw), boxh) + dc.SetTextForeground(wx.Colour(0, 0, 0)) + if color < 0.2: + dc.SetTextForeground(wx.Colour(255, 255, 255)) + dc.SetBrush(wx.Brush(wx.Colour(250,0,0))) + elif color < 0.6: + dc.SetBrush(wx.Brush(wx.Colour(250,180,0))) + else: + dc.SetBrush(wx.Brush(wx.Colour(0,250,0))) +# dc.DrawLine(200,50,350,50) + dc.DrawRectangle(tdx + col * 200 + dx, int(row*spacing+tdx+dy), int(boxw * percent), boxh) + dc.DrawText(txt,18 + col * 200 + dx,int(row*spacing+tdy+tdx+dy)) + + def plot_x(self, x): + return int(self.stat+self.tdx + x * (self.w-self.stat-2*self.tdx)) + + def plot_y(self, y): + return int(self.tdx + (1-y) * (self.h-self.tdx-self.tdx)) + + def plot(self, dc, i1, i2): + dc.DrawLine(self.plot_x(i1[1]/3500), self.plot_y((i1[0]-2.5)/(4.2-2.5)), self.plot_x(i2[1]/3500), self.plot_y((i2[0]-2.5)/(4.2-2.5))) + + + + def OnPaint(self, e): + # Automatic Scaling + w = self.w + h = self.h - 25 + + dc = wx.PaintDC(self) + brush = wx.Brush("white") + dc.SetBackground(brush) + dc.Clear() + + # Background + dc.SetBrush(wx.Brush(wx.Colour(0, 0, 0), wx.TRANSPARENT)) + + fontscale = int(w * 11.0 / 1500.0) + if fontscale < 6: + fontscale = 6 + font = wx.Font(fontscale, wx.FONTFAMILY_ROMAN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD) + dc.SetFont(font) + + # Draw Drone + dc.SetPen(wx.Pen(wx.Colour(0,0,0))) + dc.SetBrush(wx.Brush(wx.Colour(240,240,220))) + # Fuselage + dc.DrawRoundedRectangle(int(0.37*w), int(0.05*h),int(0.26*w), int(0.9*h), int(0.1*w)) + # Front Wing + dc.DrawRectangle(int(0.05*w), int(0.25*h),int(0.9*w), int(0.15*h)) + # Back Wing + dc.DrawRectangle(int(0.01*w), int(0.65*h),int(0.98*w), int(0.15*h)) + + # Fuel Cell + dc.SetBrush(wx.Brush(wx.Colour(100,100,100))) + dc.DrawRoundedRectangle(int(0.39*w), int(0.07*h),int(0.22*w), int(0.35*h), int(0.08*w)) + + self.stat = int(0.14*w) + + dx = int(0.43*w) + dy = int(0.43*h) + self.StatusBox(dc, dx, dy, 0, 0, self.cell.get_volt(), self.cell.get_volt_perc(), self.cell.get_volt_color()) + self.StatusBox(dc, dx, dy, 1, 0, self.cell.get_current(), self.cell.get_current_perc(), self.cell.get_current_color() ) + self.StatusBox(dc, dx, dy, 2, 0, self.cell.get_power_text(), self.cell.get_power_perc(), self.cell.get_power_color()) + self.StatusBox(dc, dx, dy, 3, 0, self.cell.get_energy(), self.cell.get_energy_perc(), self.cell.get_energy_color() ) + + dx = int(0.43*w) + dy = int(0.15*h) + self.StatusBox(dc, dx, dy, 0, 0, self.fuelcell.get_raw(), 0, self.fuelcell.get_raw_color()) + self.StatusBox(dc, dx, dy, 1, 0, self.fuelcell.get_tank(), self.fuelcell.get_tank_perc(), self.fuelcell.get_tank_color()) + self.StatusBox(dc, dx, dy, 2, 0, self.fuelcell.get_battery(), self.fuelcell.get_battery_perc(), self.fuelcell.get_battery_color()) + self.StatusBox(dc, dx, dy, 3, 0, self.fuelcell.get_status(), self.fuelcell.get_status_perc(), self.fuelcell.get_status_color()) + self.StatusBox(dc, dx, dy, 4, 0, self.fuelcell.get_error(), self.fuelcell.get_error_perc(), self.fuelcell.get_error_color()) + + # Warnings + self.stat = int(0.14*w) + dc.SetBrush(wx.Brush(wx.Colour(70,70,40))) + dc.DrawRectangle(int(0.36*w), int(0.63*h),int(0.28*w), int(0.35*h)) + dx = int(0.36*w) + dy = int(0.63*h) + for i in range(0,8,1): + self.StatusBox(dc, dx, dy,i, 0, self.fuelcell.get_error_nr(i*2), 1, self.fuelcell.get_error_nr_color(i*2)) + self.StatusBox(dc, int(0.5*w), dy,i, 0, self.fuelcell.get_error_nr(i*2+1), 1, self.fuelcell.get_error_nr_color(i*2+1)) + + # Motors + self.stat = int(0.10*w) + + dc.SetBrush(wx.Brush(wx.Colour(200,200,100))) + w1 = 0.20 + w2 = 0.60 + dw = 0.11 + mw = 0.1 + mm = [(0.03,w1), (0.03+dw,w1), (0.03+2*dw,w1), (0.97-mw-2*dw,w1), (0.97-mw-dw,w1), (0.97-mw,w1), (0.03,w1+0.17), (0.03+dw,w1+0.17), (0.97-mw-dw,w1+0.17), (0.97-mw,w1+0.17), + (0.03,w2), (0.03+dw,w2), (0.03+2*dw,w2), (0.97-mw-2*dw,w2), (0.97-mw-dw,w2), (0.97-mw,w2), (0.03,w2+0.17), (0.03+dw,w2+0.17), (0.97-mw-dw,w2+0.17), (0.97-mw,w2+0.17)] + for m in mm: + dc.DrawRectangle(int(m[0]*w), int(m[1]*h),int(mw*w), int(0.15*h)) + + for m in self.motors.mot: + mo_co = mm[m.id] + #print(m.id, mo_co) + dx = int(mo_co[0]*w) + dy = int(mo_co[1]*h) + self.StatusBox(dc, dx, dy, 0, 0, m.get_volt(), m.get_volt_perc(), 1) + self.StatusBox(dc, dx, dy, 1, 0, m.get_current(), m.get_current_perc(), 1) + self.StatusBox(dc, dx, dy, 2, 0, m.get_rpm(), m.get_rpm_perc(), m.get_rpm_color) + self.StatusBox(dc, dx, dy, 3, 0, m.get_temp(), m.get_temp_perc(), m.get_temp_color()) + + + + def __init__(self): + + self.w = WIDTH + self.h = WIDTH + BARH + + self.cfg = wx.Config('fuel_cell_conf') + if self.cfg.Exists('width'): + self.w = int(self.cfg.Read('width')) + self.h = int(self.cfg.Read('height')) + + wx.Frame.__init__(self, id=-1, parent=None, name=u'FuelCellFrame', + size=wx.Size(self.w, self.h), title=u'Fuel Cell Monitoring') + + if self.cfg.Exists('left'): + self.x = int(self.cfg.Read('left')) + self.y = int(self.cfg.Read('top')) + self.SetPosition(wx.Point(self.x,self.y)) + + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.Bind(wx.EVT_SIZE, self.OnSize) + self.Bind(wx.EVT_MOVE, self.OnMove) + self.Bind(wx.EVT_CLOSE, self.OnClose) + + ico = wx.Icon(PPRZ_SRC + "/sw/ground_segment/python/energy_mon/energy_mon.ico", wx.BITMAP_TYPE_ICO) + self.SetIcon(ico) + + self.bat = {} + self.temp = {} + self.cell = BatteryCell() + self.motors = MotorList() + self.fuelcell = FuelCellStatus() + self.fuelcell.update('<0,0,0,0x08020000>') + + self.interface = IvyMessagesInterface("fuelcellframe") + self.interface.subscribe(self.message_recv) + + def OnClose(self, event): + self.interface.shutdown() + self.Destroy() + +if __name__ == '__main__': + energy_message = EnergyMessage({"bat": 22, "amp": 18, "power": 22 * 18, "energy": 10000}) + air_data_message = AirDataMessage({"airspeed": 21}) + esc_message = Esc({}) + cell = BatteryCell() + cell.fill_from_energy_msg(energy_message) + + import matplotlib.pyplot as plt + import numpy as np + energies = np.arange(0, 3200*6, 10) + seconds_left = np.zeros(energies.shape) + + # for i, energy in enumerate(energies): + # cell.fill_from_energy_msg(EnergyMessage({"bat": 22, "amp": 18, "power": 22 * 18, "energy": energy})) + # seconds_left[i] = energy_prediction.get_hover_seconds_left() + # + # + # plt.plot(energies, seconds_left) + # plt.show() diff --git a/sw/ground_segment/python/payload_forward/jpeg100_decoder.py b/sw/ground_segment/python/payload_forward/jpeg100_decoder.py index d1cb3c6f84a..5f6d1f861d4 100644 --- a/sw/ground_segment/python/payload_forward/jpeg100_decoder.py +++ b/sw/ground_segment/python/payload_forward/jpeg100_decoder.py @@ -19,8 +19,8 @@ import wx import array -import Image -from cStringIO import StringIO +from PIL import Image +from io import StringIO jpegheader = b'\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49\x46\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00\x43\x00\x20\x16\x18\x1c\x18\x14\x20\x1c\x1a\x1c\x24\x22\x20\x26\x30\x50\x34\x30\x2c\x2c\x30\x62\x46\x4a\x3a\x50\x74\x66\x7a\x78\x72\x66\x70\x6e\x80\x90\xb8\x9c\x80\x88\xae\x8a\x6e\x70\xa0\xda\xa2\xae\xbe\xc4\xce\xd0\xce\x7c\x9a\xe2\xf2\xe0\xc8\xf0\xb8\xca\xce\xc6\xff\xdb\x00\x43\x01\x22\x24\x24\x30\x2a\x30\x5e\x34\x34\x5e\xc6\x84\x70\x84\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xff\xc0\x00\x11\x08\x00\x64\x00\x64\x03\x01\x22\x00\x02\x11\x01\x03\x11\x01\xff\xc4\x00\x1f\x00\x00\x01\x05\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\xff\xc4\x00\xb5\x10\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05\x04\x04\x00\x00\x01\x7d\x01\x02\x03\x00\x04\x11\x05\x12\x21\x31\x41\x06\x13\x51\x61\x07\x22\x71\x14\x32\x81\x91\xa1\x08\x23\x42\xb1\xc1\x15\x52\xd1\xf0\x24\x33\x62\x72\x82\x09\x0a\x16\x17\x18\x19\x1a\x25\x26\x27\x28\x29\x2a\x34\x35\x36\x37\x38\x39\x3a\x43\x44\x45\x46\x47\x48\x49\x4a\x53\x54\x55\x56\x57\x58\x59\x5a\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74\x75\x76\x77\x78\x79\x7a\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xff\xc4\x00\x1f\x01\x00\x03\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\xff\xc4\x00\xb5\x11\x00\x02\x01\x02\x04\x04\x03\x04\x07\x05\x04\x04\x00\x01\x02\x77\x00\x01\x02\x03\x11\x04\x05\x21\x31\x06\x12\x41\x51\x07\x61\x71\x13\x22\x32\x81\x08\x14\x42\x91\xa1\xb1\xc1\x09\x23\x33\x52\xf0\x15\x62\x72\xd1\x0a\x16\x24\x34\xe1\x25\xf1\x17\x18\x19\x1a\x26\x27\x28\x29\x2a\x35\x36\x37\x38\x39\x3a\x43\x44\x45\x46\x47\x48\x49\x4a\x53\x54\x55\x56\x57\x58\x59\x5a\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74\x75\x76\x77\x78\x79\x7a\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xff\xda\x00\x0c\x03\x01\x00\x02\x11\x03\x11\x00\x3f\x00' diff --git a/sw/ground_segment/python/payload_forward/payload_forward.py b/sw/ground_segment/python/payload_forward/payload_forward.py index 7ae9296ea0c..0969092645c 100644 --- a/sw/ground_segment/python/payload_forward/payload_forward.py +++ b/sw/ground_segment/python/payload_forward/payload_forward.py @@ -24,7 +24,7 @@ import socket import array import jpeg100_decoder -from cStringIO import StringIO +from io import StringIO PPRZ_HOME = os.getenv("PAPARAZZI_HOME", os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../../..'))) @@ -85,7 +85,8 @@ def OnPaint(self, e): # Background dc.SetBrush(wx.Brush(wx.Colour(0,0,0), wx.TRANSPARENT)) - font = wx.Font(11, wx.ROMAN, wx.BOLD, wx.NORMAL) + font = wx.Font(11, wx.FONTFAMILY_ROMAN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD) + dc.SetFont(font) dc.DrawText("UDP: " + self.settings.ip + ":" + str(self.settings.port),2,2) dc.DrawText("Data: " + str(self.data['packets']) + " packets, " + str(round(float(self.data['bytes'])/1024.0,2)) + "kb)",2,22) @@ -104,7 +105,7 @@ def __init__(self, _settings): self.data = { 'packets': 0, 'bytes': 0} # Decoder - if (self.settings.decoder is 'jpeg100'): + if (self.settings.decoder == 'jpeg100'): self.decoder = jpeg100_decoder.ThumbNailFromPayload() else: self.decoder = MinimalDecoder() diff --git a/sw/ground_segment/python/svinfo/svinfoviewer.py b/sw/ground_segment/python/svinfo/svinfoviewer.py index 558dc763b60..ca31f643213 100644 --- a/sw/ground_segment/python/svinfo/svinfoviewer.py +++ b/sw/ground_segment/python/svinfo/svinfoviewer.py @@ -157,7 +157,7 @@ def __init__(self): if self.cfg.Exists('left'): self.x = int(self.cfg.Read('left')) self.y = int(self.cfg.Read('top')) - self.SetPosition(wx.Point(self.x,self.y), wx.SIZE_USE_EXISTING) + self.SetPosition(wx.Point(self.x,self.y)) self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_SIZE, self.OnSize) diff --git a/sw/ground_segment/python/wind/wind_frame.py b/sw/ground_segment/python/wind/wind_frame.py index 1d1fbf302f2..3a538823a57 100644 --- a/sw/ground_segment/python/wind/wind_frame.py +++ b/sw/ground_segment/python/wind/wind_frame.py @@ -189,7 +189,7 @@ def __init__(self): if self.cfg.Exists('left'): self.x = int(self.cfg.Read('left')) self.y = int(self.cfg.Read('top')) - self.SetPosition(wx.Point(self.x,self.y), wx.SIZE_USE_EXISTING) + self.SetPosition(wx.Point(self.x,self.y)) self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_SIZE, self.OnSize)