diff --git a/conf/airframes/AG/rot_wing_v3c_oneloop_optitrack_ext_pose_AG.xml b/conf/airframes/AG/rot_wing_v3c_oneloop_optitrack_ext_pose_AG.xml index 3adef118be..1dcedc37ed 100644 --- a/conf/airframes/AG/rot_wing_v3c_oneloop_optitrack_ext_pose_AG.xml +++ b/conf/airframes/AG/rot_wing_v3c_oneloop_optitrack_ext_pose_AG.xml @@ -41,6 +41,8 @@ + + @@ -243,7 +245,6 @@ -
diff --git a/conf/airframes/tudelft/bebop_one_indi_generated_ekf2.xml b/conf/airframes/tudelft/bebop_one_indi_generated_ekf2.xml deleted file mode 100644 index c3f61d4e59..0000000000 --- a/conf/airframes/tudelft/bebop_one_indi_generated_ekf2.xml +++ /dev/null @@ -1,212 +0,0 @@ - - - - bebop with a oneloop ANDI and backup INDI controller and EKF2 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - -
- -
- - - -
- -
- - - - - -
- -
- -
-
- - - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
- - - - - -
- -
- - - - - -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - -
- -
- - - - -
- -
- - - - -
- -
- - - - - -
- -
diff --git a/conf/airframes/tudelft/rotwing5.xml b/conf/airframes/tudelft/rotwing5.xml index 1fec38d2d1..a47b5932a0 100644 --- a/conf/airframes/tudelft/rotwing5.xml +++ b/conf/airframes/tudelft/rotwing5.xml @@ -129,6 +129,9 @@ + + + diff --git a/conf/airframes/tudelft/rotwing6.xml b/conf/airframes/tudelft/rotwing6.xml index 63d4dda8cf..2ce68c9b6a 100644 --- a/conf/airframes/tudelft/rotwing6.xml +++ b/conf/airframes/tudelft/rotwing6.xml @@ -129,6 +129,9 @@ + + + diff --git a/conf/airframes/tudelft/rotwing_7kg_common.xml b/conf/airframes/tudelft/rotwing_7kg_common.xml index 598d9c533e..3968859215 100644 --- a/conf/airframes/tudelft/rotwing_7kg_common.xml +++ b/conf/airframes/tudelft/rotwing_7kg_common.xml @@ -45,8 +45,6 @@ - - @@ -261,6 +259,21 @@
+ +
+ + + + + + + + + + + +
+
diff --git a/conf/airframes/tudelft/rotwing_v3c_oneloop_optitrack.xml b/conf/airframes/tudelft/rotwing_v3c_oneloop_optitrack.xml index 6ffb6f9957..b134d5db68 100644 --- a/conf/airframes/tudelft/rotwing_v3c_oneloop_optitrack.xml +++ b/conf/airframes/tudelft/rotwing_v3c_oneloop_optitrack.xml @@ -49,6 +49,8 @@ + + @@ -96,7 +98,6 @@ - diff --git a/conf/conf_tests.xml b/conf/conf_tests.xml index a4f405f8bf..eab59262d4 100644 --- a/conf/conf_tests.xml +++ b/conf/conf_tests.xml @@ -55,14 +55,14 @@ gui_color="blue" /> - - - + + +# +# +# +# +# + + +class PowerList(object): + def __init__(self): + self.power = {} + + +class POWERDEVICEMessage(object): + def __init__(self, msg): + self.node_id = int(msg['node_id']) + self.circuit = int(msg['circuit']) + self.current = float(msg['current']) + self.voltage = float(msg['voltage']) + + + +class FUELCELLMessage(object): + def __init__(self, msg): + self.pressure = msg['pressure'] + self.press_reg = float(msg['press_reg']) + self.volt_bat = float(msg['volt_bat']) + self.power_out = float(msg['power_out']) + self.power_cell = float(msg['power_cell']) + self.power_batt = float(msg['power_batt']) + self.state = int(msg['state']) + self.error = int(msg['error']) + self.suberror = int(msg['suberror']) + states = ['FCPM off', 'Starting', 'Running', 'Stopping', 'Go to sleep'] + self.state_str = '?' + if self.state < len(states): + self.state_str = states[self.state] + if self.error == 0: + self.error_str = 'No error' + elif self.error == 1: + self.error_str = 'Minor internal' + elif self.error == 4: + self.error_str = 'Reconditioning needed' + elif self.error == 6: + self.error_str = 'Auto recondition active' + elif self.error == 7: + self.error_str = 'Reconditioning active' + elif self.error == 8: + self.error_str = 'Recovery mode active' + elif self.error == 12: + self.error_str = 'Tank pressure low' + elif self.error == 14: + self.error_str = 'Battery voltage low' + elif self.error == 20: + self.error_str = 'Reduced power' + elif self.error == 25: + self.error_str = 'SPM lost' + elif self.error == 30: + self.error_str = 'Tank empty' + elif self.error == 32: + self.error_str = 'Start denied' + elif self.error == 34: + self.error_str = 'FC off - recovery required' + elif self.error == 36: + self.error_str = 'FC off - system error' + elif self.error == 40: + self.error_str = 'Battery critical' + else: + self.error_str = 'Unknown error' + + if self.suberror == 0: + self.suberror_str = 'No context' + elif self.suberror == 1: + self.suberror_str = 'SPM1' + elif self.suberror == 2: + self.suberror_str = 'SPM2' + elif self.suberror == 3: + self.suberror_str = 'SPM1 AND SPM2' + elif self.suberror == 4: + self.suberror_str = 'ALL SPM LOST' + elif self.suberror == 5: + self.suberror_str = 'Inlet pressure low' + elif self.suberror == 6: + self.suberror_str = 'Inlet pressure high' + elif self.suberror == 7: + self.suberror_str = 'Tank pressure low' + elif self.suberror == 8: + self.suberror_str = 'Tank pressure high' + elif self.suberror == 9: + self.suberror_str = 'Stack voltage low' + elif self.suberror == 10: + self.suberror_str = 'Internal tests (INT ERR)' + elif self.suberror == 11: + self.suberror_str = 'Stack temperature high (STK HT)' + elif self.suberror == 12: + self.suberror_str = 'Stack temperature low (STK LT)' + elif self.suberror == 13: + self.suberror_str = 'Reconditioning active' + elif self.suberror == 14: + self.suberror_str = 'Reconditioning complete' + elif self.suberror == 15: + self.suberror_str = 'Thermal management' + elif self.suberror == 16: + self.suberror_str = 'Start faults' + elif self.suberror == 17: + self.suberror_str = 'LPI missing' + elif self.suberror == 254: + self.suberror_str = 'Complete flight - contact support' + elif self.suberror == 255: + self.suberror_str = 'Stop using unit - contact support' + else: + self.suberror_str = 'Unknown suberror' + +class PowerList(object): + def __init__(self): + self.power = [] + + def fill_from_power_msg(self, power): + added = False + for i in range(len(self.power)): + if self.power[i].node_id == power.node_id and self.power[i].circuit == power.circuit: + self.power[i] = power + added = True + break + if not added: + self.power.append(power) + + def get_frontbat(self): + for i in range(len(self.power)): + if self.power[i].node_id == 14 and self.power[i].circuit == 0: + return self.power[i] + return None + + def get_backbat(self): + for i in range(len(self.power)): + if self.power[i].node_id == 6 and self.power[i].circuit == 0: + return self.power[i] + return None + + def get_backmot(self): + for i in range(len(self.power)): + if self.power[i].node_id == 6 and self.power[i].circuit == 1: + return self.power[i] + return None + class MotorList(object): def __init__(self): self.mot = [] @@ -154,6 +353,27 @@ class RotWingFrame(wx.Frame): if msg.name == "STAB_ATTITUDE": self.indi = INDIMessage(msg) wx.CallAfter(self.update) + + if msg.name =="ROTATING_WING_STATE": + self.rw_status = RWStatusMessage(msg) + wx.CallAfter(self.update) + + if msg.name == "AIR_DATA": + self.air_data = AIRDATAMessage(msg) + wx.CallAfter(self.update) + + if msg.name == "IMU_HEATER": + self.imu_heater = IMUHEATERMessage(msg) + wx.CallAfter(self.update) + + if msg.name == "FUELCELL": + self.fuelcell = FUELCELLMessage(msg) + wx.CallAfter(self.update) + + if msg.name == "POWER_DEVICE": + self.powermessage = POWERDEVICEMessage(msg) + self.powers.fill_from_power_msg(self.powermessage) + wx.CallAfter(self.update) def update(self): self.Refresh() @@ -228,8 +448,107 @@ class RotWingFrame(wx.Frame): # Back Wing dc.DrawRectangle(int(0.25*w), int(0.65*h),int(0.5*w), int(0.1*h)) - # Motors + # Draw rotwing status self.stat = int(0.10*w) + if hasattr(self, 'rw_status'): + line = int(20.0 / 800.0 * h) + dc.SetBrush(wx.Brush(wx.Colour(200,200,100))) + dc.DrawRectangle(int(5), int(5),int(0.29*w), int(0.20*h)) + dc.DrawText("State: " + self.rw_status.get_state() + " [NAV: " + self.rw_status.get_nav_state() +"]", 10, int(0.5*line)) + if self.rw_status.skew_angle_valid: + if abs(self.rw_status.meas_skew_angle - self.rw_status.sp_skew_angle) < 10: + dc.SetTextForeground(wx.Colour(0, 0, 0)) + else: + dc.SetTextForeground(wx.Colour(139, 64, 0)) + dc.DrawText("Rotation: " + str(round(self.rw_status.meas_skew_angle, 1)) + " (SP: " + str(round(self.rw_status.sp_skew_angle, 1)) + ")", 10, int(1.5*line)) + else: + dc.SetTextForeground(wx.Colour(255, 0, 0)) + dc.DrawText("Rotation: " + str(round(self.rw_status.meas_skew_angle, 1)) + " (SP: " + str(round(self.rw_status.sp_skew_angle, 1)) + ")", 10, int(1.5*line)) + + dc.SetTextForeground(wx.Colour(0, 0, 0)) + dc.DrawText("Hover motors: ", 10, int(2.5*line)) + lbw = dc.GetTextExtent("Hover Motors: ").width + if self.rw_status.hover_motors_running: + dc.SetTextForeground(wx.Colour(0, 0, 0)) + dc.DrawText("running ", 10 + lbw, int(2.5*line)) + lbw += dc.GetTextExtent("running ").width + else: + dc.SetTextForeground(wx.Colour(255, 0, 0)) + dc.DrawText("stopped ", 10 + lbw, int(2.5*line)) + lbw += dc.GetTextExtent("stopped ").width + + if self.rw_status.hover_motors_idle: + dc.SetTextForeground(wx.Colour(0, 0, 0)) + dc.DrawText("idle ", 10 + lbw, int(2.5*line)) + lbw += dc.GetTextExtent("idle ").width + + if self.rw_status.hover_motors_enabled: + dc.SetTextForeground(wx.Colour(0, 0, 0)) + dc.DrawText("(Enabled)", 10 + lbw, int(2.5*line)) + else: + dc.SetTextForeground(wx.Colour(255, 0, 0)) + dc.DrawText("(Disabled)", 10 + lbw, int(2.5*line)) + + dc.SetTextForeground(wx.Colour(0, 0, 0)) + dc.DrawText("Pusher motor: ", 10, int(3.5*line)) + lbw = dc.GetTextExtent("Pusher motor: ").width + if self.rw_status.pusher_motor_running: + dc.SetTextForeground(wx.Colour(0, 0, 0)) + dc.DrawText("running", 10 + lbw, int(3.5*line)) + else: + dc.SetTextForeground(wx.Colour(255, 0, 0)) + dc.DrawText("stopped", 10 + lbw, int(3.5*line)) + + dc.SetTextForeground(wx.Colour(0, 0, 0)) + dc.DrawText("Nav airspeed: " + str(round(self.rw_status.nav_airspeed,1 )) + " [min: " + str(round(self.rw_status.min_airspeed,1 )) + ", max:" + str(round(self.rw_status.max_airspeed,1 )) + "]", 10, int(4.5*line)) + if hasattr(self, 'air_data'): + dc.DrawText("Meas airspeed: " + str(round(self.air_data.airspeed,1 )) + " (TAS: " + str(round(self.air_data.tas,1 )) + ")", 10, int(5.5*line)) + #self.StatusBox(dc, 5, 5, 0, 0, self.rw_status.get_state(), 1, 1) + dc.SetTextForeground(wx.Colour(0, 0, 0)) + dc.DrawText("Force Skew: ", 10, int(6.5*line)) + lbw = dc.GetTextExtent("Force Skew: ").width + if self.rw_status.skew_forced: + dc.SetTextForeground(wx.Colour(255, 0, 0)) + dc.DrawText("(Enabled)", 10 + lbw, int(6.5*line)) + else: + dc.SetTextForeground(wx.Colour(0, 0, 0)) + dc.DrawText("(Disabled)", 10 + lbw, int(6.5*line)) + + if hasattr(self, 'imu_heater'): + imu_temp = float(self.imu_heater.meas_temp) + if imu_temp < 65.0: + dc.SetTextForeground(wx.Colour(0, 0, 0)) + dc.DrawText("Meas IMU temp: " + str(round(imu_temp, 0)), 10, int(7.5*line)) + elif imu_temp < 85.0: + dc.SetTextForeground(wx.Colour(139, 64, 0)) + dc.DrawText("Meas IMU temp: " + str(round(imu_temp, 0)), 10, int(7.5*line)) + else: + dc.SetTextForeground(wx.Colour(255, 0, 0)) + dc.DrawText("Meas IMU temp: " + str(round(imu_temp, 0)), 10, int(7.5*line)) + + if self.powers.get_backbat() != None: + dc.DrawText("Back Bat: " + str(round(self.powers.get_backbat().current*self.powers.get_backbat().voltage, 1)) + "W (" + str(round(self.powers.get_backbat().voltage, 1)) + "V, " + str(round(self.powers.get_backbat().current, 1)) + "A)", 10, int(8.5*line)) + if self.powers.get_frontbat() != None: + dc.DrawText("Front Bat: " + str(round(self.powers.get_frontbat().current*self.powers.get_frontbat().voltage, 1)) + "W (" + str(round(self.powers.get_frontbat().voltage, 1)) + "V, " + str(round(self.powers.get_frontbat().current, 1)) + "A)", 10, int(9.5*line)) + if self.powers.get_backmot() != None: + dc.DrawText("Back Mot: " + str(round(self.powers.get_backmot().current*self.powers.get_backmot().voltage, 1)) + "W (" + str(round(self.powers.get_backmot().voltage, 1)) + "V, " + str(round(self.powers.get_backmot().current, 1)) + "A)", 10, int(10.5*line)) + + if hasattr(self, 'fuelcell'): + dc.SetBrush(wx.Brush(wx.Colour(200,200,200))) + line = int(20.0 / 800.0 * h) + dc.SetTextForeground(wx.Colour(0, 0, 0)) + dc.DrawRoundedRectangle(int(0.7*w), int(5),int(0.29*w), int(0.18*h), int(0.05*h)) + dc.DrawText("FuelCell state: ["+str(self.fuelcell.state)+"] " + self.fuelcell.state_str, int(0.75*w+5), int(0.5*line)) + dc.DrawText("Cylinder press: " + str(self.fuelcell.pressure) + "% Reg="+str(self.fuelcell.press_reg)+"Bar", int(0.75*w+5), int(1.5*line)) + dc.DrawText("Output: " + str(self.fuelcell.power_out) + " Watt", int(0.75*w+5), int(2.5*line)) + dc.DrawText("SPM: " + str(self.fuelcell.power_cell) + " Watt, p=" + str(round(float(self.fuelcell.pressure)*3.630,1)) + " Bar", int(0.75*w+5), int(3.5*line)) + dc.DrawText("Battery: " + str(self.fuelcell.power_batt) + " Watt, " + str(self.fuelcell.volt_bat) + " Volt", int(0.75*w+5), int(4.5*line)) + dc.DrawText("Error: ["+str(self.fuelcell.error)+"] " + self.fuelcell.error_str, int(0.75*w+5), int(5.5*line)) + dc.DrawText("Sub-error: ["+str(self.fuelcell.suberror)+"] " + self.fuelcell.suberror_str, int(0.75*w+5), int(6.5*line)) + + + + # Motors w1 = 0.03 w2 = 0.18 w3 = 0.31 @@ -238,10 +557,10 @@ class RotWingFrame(wx.Frame): mw = 0.1 mh = 0.2 - mm = [(0.5-0.5*mw-0.05,w1), (0.5+dw-0.05+0.1,w2), (0.5-0.5*mw-0.05,w3), (0.5-dw-mw-0.05-0.1,w2), # hover CAN1: front right back left + mm = [(0.5-0.5*mw-0.05,w1), (0.5+dw+0.05+0.1,w2), (0.5-0.5*mw-0.05,w3), (0.5-dw-mw+0.05-0.1,w2), # hover CAN1: front right back left (0.5-0.5*mw-0.05,w4), # pusher CAN1 (0.5-dw-mw-0.05,w4+0.05), (0.5+dw-0.05,w4+0.05), # tail CAN1 - (0.5-0.5*mw+0.05,w1), (0.5+dw+0.05+0.1,w2), (0.5-0.5*mw+0.05,w3), (0.5-dw-mw+0.05-0.1,w2), # hover CAN2 + (0.5-0.5*mw+0.05,w1), (0.5+dw-0.05+0.1,w2), (0.5-0.5*mw+0.05,w3), (0.5-dw-mw-0.05-0.1,w2), # hover CAN2 (0.5-0.5*mw+0.05,w4), # pusher CAN2 (0.5-dw-mw+0.05,w4+0.05), (0.5+dw+0.05,w4+0.05), # Tail CAN2 (0.0, 0.75), (0.1, 0.75), (0.2, 0.75), (0.3, 0.75), (0.4, 0.75), # extra @@ -318,6 +637,7 @@ class RotWingFrame(wx.Frame): #self.SetIcon(ico) self.motors = MotorList() + self.powers = PowerList() self.interface = IvyMessagesInterface("rotwingframe") self.interface.subscribe(self.message_recv)