2 changed files with 752 additions and 0 deletions
@ -0,0 +1,148 @@ |
|||||||
|
#!/usr/bin/env python |
||||||
|
''' |
||||||
|
A tool to view MSP telemetry, simulating a DJI FPV display |
||||||
|
This is used for testing changes to the ArduPilot implementation of MSP telemetry for FPV |
||||||
|
|
||||||
|
Originally started by Alex Apostoli |
||||||
|
based on https://github.com/hkm95/python-multiwii |
||||||
|
''' |
||||||
|
|
||||||
|
import pygame |
||||||
|
import threading |
||||||
|
import time |
||||||
|
import sys |
||||||
|
import pymsp |
||||||
|
import argparse |
||||||
|
import socket |
||||||
|
import serial |
||||||
|
import errno |
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description='ArduPilot MSP FPV viewer') |
||||||
|
parser.add_argument('--port', default="tcp:localhost:5763", help="port to listen on, can be serial port or tcp:IP:port") |
||||||
|
|
||||||
|
args = parser.parse_args() |
||||||
|
|
||||||
|
def connect(port): |
||||||
|
'''connect to port, returning a receive function''' |
||||||
|
try: |
||||||
|
if port.startswith("tcp:"): |
||||||
|
print("Connecting to TCP socket %s" % port) |
||||||
|
a = port[4:].split(':') |
||||||
|
port = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
||||||
|
port.connect((a[0],int(a[1]))) |
||||||
|
port.setblocking(0) |
||||||
|
return port.recv |
||||||
|
print("Connecting to serial port %s" % port) |
||||||
|
port = serial.Serial(args.port, 115200, timeout=0.01) |
||||||
|
return port.read |
||||||
|
except Exception as ex: |
||||||
|
return None |
||||||
|
|
||||||
|
|
||||||
|
recv_func = None |
||||||
|
last_read_s = time.time() |
||||||
|
|
||||||
|
msp = pymsp.PyMSP() |
||||||
|
|
||||||
|
pygame.init() |
||||||
|
|
||||||
|
# define the RGB value for white, |
||||||
|
# green, blue colour . |
||||||
|
white = (255, 255, 255) |
||||||
|
green = (0, 255, 0) |
||||||
|
blue = (0, 0, 128) |
||||||
|
black = (0, 0 ,0) |
||||||
|
|
||||||
|
# window size |
||||||
|
FontWidth = 25 |
||||||
|
FontHeight = 25 |
||||||
|
|
||||||
|
WindowWidth = 32 * FontWidth |
||||||
|
WindowHeight = 16 * FontHeight |
||||||
|
|
||||||
|
# create the display surface object |
||||||
|
# of specific dimension..e(X, Y). |
||||||
|
display_surface = pygame.display.set_mode((WindowWidth,WindowHeight)) |
||||||
|
|
||||||
|
# set the pygame window name |
||||||
|
pygame.display.set_caption('MSP Display') |
||||||
|
|
||||||
|
def item_to_pos(item): |
||||||
|
'''map MSP item to a X,Y tuple or None''' |
||||||
|
if item >= msp.msp_osd_config['osd_item_count']: |
||||||
|
return None |
||||||
|
pos = msp.msp_osd_config['osd_items'][item] |
||||||
|
if pos < 2048: |
||||||
|
return None |
||||||
|
pos_y = (pos-2048) // 32 |
||||||
|
pos_x = (pos-2048) % 32 |
||||||
|
return (pos_x, pos_y) |
||||||
|
|
||||||
|
|
||||||
|
def display_text(item, message): |
||||||
|
'''display a string message for an item''' |
||||||
|
XY = item_to_pos(item) |
||||||
|
if XY is None: |
||||||
|
return |
||||||
|
(X,Y) = XY |
||||||
|
text = font.render(message, True, white, black) |
||||||
|
textRect = text.get_rect() |
||||||
|
|
||||||
|
slen = len(message) |
||||||
|
px = X * FontWidth |
||||||
|
py = Y * FontHeight |
||||||
|
textRect.center = (px+textRect.width/2, py+textRect.height/2) |
||||||
|
display_surface.blit(text, textRect) |
||||||
|
|
||||||
|
def display_all(): |
||||||
|
'''display all items''' |
||||||
|
display_text(msp.OSD_CURRENT_DRAW, "%.2fA" % (msp.msp_battery_state['current']*0.001)) |
||||||
|
display_text(msp.OSD_MAIN_BATT_VOLTAGE, "%.2fV" % (msp.msp_battery_state['voltage']*0.001)) |
||||||
|
display_text(msp.OSD_GPS_SPEED, "%.1fm/s" % (msp.msp_raw_gps['GPS_speed']*0.01)) |
||||||
|
display_text(msp.OSD_GPS_SATS, "%uS" % (msp.msp_raw_gps['GPS_numSat'])) |
||||||
|
display_text(msp.OSD_ALTITUDE, "%.1fm" % (msp.msp_altitude['alt']*0.01)) |
||||||
|
display_text(msp.OSD_ROLL_ANGLE, "Roll:%.1f" % (msp.msp_attitude['roll']*0.1)) |
||||||
|
display_text(msp.OSD_PITCH_ANGLE, "Pitch:%.1f" % (msp.msp_attitude['pitch']*0.1)) |
||||||
|
display_text(msp.OSD_CRAFT_NAME, "%s" % (msp.msp_name['name'])) |
||||||
|
|
||||||
|
def receive_data(): |
||||||
|
'''receive any data from socket''' |
||||||
|
global recv_func, last_read_s |
||||||
|
while recv_func is None: |
||||||
|
time.sleep(0.5) |
||||||
|
recv_func = connect(args.port) |
||||||
|
try: |
||||||
|
buf = recv_func(100) |
||||||
|
if not buf: |
||||||
|
if time.time() - last_read_s > 1: |
||||||
|
recv_func = None |
||||||
|
return |
||||||
|
last_read_s = time.time() |
||||||
|
except IOError as e: |
||||||
|
if e.errno == errno.EWOULDBLOCK: |
||||||
|
return |
||||||
|
recv_func = None |
||||||
|
return |
||||||
|
msp.parseMspData(buf) |
||||||
|
|
||||||
|
font = pygame.font.Font('freesansbold.ttf', 12) |
||||||
|
|
||||||
|
last_display_t = time.time() |
||||||
|
|
||||||
|
# infinite loop |
||||||
|
while True: |
||||||
|
receive_data() |
||||||
|
now = time.time() |
||||||
|
|
||||||
|
if now - last_display_t > 0.1: |
||||||
|
# display at 10Hz |
||||||
|
last_display_t = now |
||||||
|
display_surface.fill(black) |
||||||
|
display_all() |
||||||
|
pygame.display.update() |
||||||
|
time.sleep(0.01) |
||||||
|
|
||||||
|
for event in pygame.event.get(): |
||||||
|
if event.type == pygame.QUIT : |
||||||
|
pygame.quit() |
||||||
|
quit() |
@ -0,0 +1,604 @@ |
|||||||
|
#!/usr/bin/env python |
||||||
|
|
||||||
|
""" |
||||||
|
author: Alex Apostoli |
||||||
|
based on https://github.com/hkm95/python-multiwii |
||||||
|
which is under GPLv3 |
||||||
|
""" |
||||||
|
|
||||||
|
import struct |
||||||
|
import time |
||||||
|
|
||||||
|
class PyMSP: |
||||||
|
""" Multiwii Serial Protocol """ |
||||||
|
OSD_RSSI_VALUE = 0 |
||||||
|
OSD_MAIN_BATT_VOLTAGE = 1 |
||||||
|
OSD_CROSSHAIRS = 2 |
||||||
|
OSD_ARTIFICIAL_HORIZON = 3 |
||||||
|
OSD_HORIZON_SIDEBARS = 4 |
||||||
|
OSD_ITEM_TIMER_1 = 5 |
||||||
|
OSD_ITEM_TIMER_2 = 6 |
||||||
|
OSD_FLYMODE = 7 |
||||||
|
OSD_CRAFT_NAME = 8 |
||||||
|
OSD_THROTTLE_POS = 9 |
||||||
|
OSD_VTX_CHANNEL = 10 |
||||||
|
OSD_CURRENT_DRAW = 11 |
||||||
|
OSD_MAH_DRAWN = 12 |
||||||
|
OSD_GPS_SPEED = 13 |
||||||
|
OSD_GPS_SATS = 14 |
||||||
|
OSD_ALTITUDE = 15 |
||||||
|
OSD_ROLL_PIDS = 16 |
||||||
|
OSD_PITCH_PIDS = 17 |
||||||
|
OSD_YAW_PIDS = 18 |
||||||
|
OSD_POWER = 19 |
||||||
|
OSD_PIDRATE_PROFILE = 20 |
||||||
|
OSD_WARNINGS = 21 |
||||||
|
OSD_AVG_CELL_VOLTAGE = 22 |
||||||
|
OSD_GPS_LON = 23 |
||||||
|
OSD_GPS_LAT = 24 |
||||||
|
OSD_DEBUG = 25 |
||||||
|
OSD_PITCH_ANGLE = 26 |
||||||
|
OSD_ROLL_ANGLE = 27 |
||||||
|
OSD_MAIN_BATT_USAGE = 28 |
||||||
|
OSD_DISARMED = 29 |
||||||
|
OSD_HOME_DIR = 30 |
||||||
|
OSD_HOME_DIST = 31 |
||||||
|
OSD_NUMERICAL_HEADING = 32 |
||||||
|
OSD_NUMERICAL_VARIO = 33 |
||||||
|
OSD_COMPASS_BAR = 34 |
||||||
|
OSD_ESC_TMP = 35 |
||||||
|
OSD_ESC_RPM = 36 |
||||||
|
OSD_REMAINING_TIME_ESTIMATE = 37 |
||||||
|
OSD_RTC_DATETIME = 38 |
||||||
|
OSD_ADJUSTMENT_RANGE = 39 |
||||||
|
OSD_CORE_TEMPERATURE = 40 |
||||||
|
OSD_ANTI_GRAVITY = 41 |
||||||
|
OSD_G_FORCE = 42 |
||||||
|
OSD_MOTOR_DIAG = 43 |
||||||
|
OSD_LOG_STATUS = 44 |
||||||
|
OSD_FLIP_ARROW = 45 |
||||||
|
OSD_LINK_QUALITY = 46 |
||||||
|
OSD_FLIGHT_DIST = 47 |
||||||
|
OSD_STICK_OVERLAY_LEFT = 48 |
||||||
|
OSD_STICK_OVERLAY_RIGHT = 49 |
||||||
|
OSD_DISPLAY_NAME = 50 |
||||||
|
OSD_ESC_RPM_FREQ = 51 |
||||||
|
OSD_RATE_PROFILE_NAME = 52 |
||||||
|
OSD_PID_PROFILE_NAME = 53 |
||||||
|
OSD_PROFILE_NAME = 54 |
||||||
|
OSD_RSSI_DBM_VALUE = 55 |
||||||
|
OSD_RC_CHANNELS = 56 |
||||||
|
OSD_CAMERA_FRAME = 57 |
||||||
|
|
||||||
|
MSP_NAME =10 |
||||||
|
MSP_OSD_CONFIG =84 |
||||||
|
MSP_IDENT =100 |
||||||
|
MSP_STATUS =101 |
||||||
|
MSP_RAW_IMU =102 |
||||||
|
MSP_SERVO =103 |
||||||
|
MSP_MOTOR =104 |
||||||
|
MSP_RC =105 |
||||||
|
MSP_RAW_GPS =106 |
||||||
|
MSP_COMP_GPS =107 |
||||||
|
MSP_ATTITUDE =108 |
||||||
|
MSP_ALTITUDE =109 |
||||||
|
MSP_ANALOG =110 |
||||||
|
MSP_RC_TUNING =111 |
||||||
|
MSP_PID =112 |
||||||
|
MSP_BOX =113 |
||||||
|
MSP_MISC =114 |
||||||
|
MSP_MOTOR_PINS =115 |
||||||
|
MSP_BOXNAMES =116 |
||||||
|
MSP_PIDNAMES =117 |
||||||
|
MSP_SERVO_CONF =120 |
||||||
|
MSP_BATTERY_STATE =130 |
||||||
|
|
||||||
|
MSP_SET_RAW_RC =200 |
||||||
|
MSP_SET_RAW_GPS =201 |
||||||
|
MSP_SET_PID =202 |
||||||
|
MSP_SET_BOX =203 |
||||||
|
MSP_SET_RC_TUNING =204 |
||||||
|
MSP_ACC_CALIBRATION =205 |
||||||
|
MSP_MAG_CALIBRATION =206 |
||||||
|
MSP_SET_MISC =207 |
||||||
|
MSP_RESET_CONF =208 |
||||||
|
MSP_SELECT_SETTING =210 |
||||||
|
MSP_SET_HEAD =211 |
||||||
|
MSP_SET_SERVO_CONF =212 |
||||||
|
MSP_SET_MOTOR =214 |
||||||
|
|
||||||
|
|
||||||
|
MSP_BIND =241 |
||||||
|
|
||||||
|
MSP_EEPROM_WRITE =250 |
||||||
|
|
||||||
|
MSP_DEBUGMSG =253 |
||||||
|
MSP_DEBUG =254 |
||||||
|
|
||||||
|
|
||||||
|
IDLE = 0 |
||||||
|
HEADER_START = 1 |
||||||
|
HEADER_M = 2 |
||||||
|
HEADER_ARROW = 3 |
||||||
|
HEADER_SIZE = 4 |
||||||
|
HEADER_CMD = 5 |
||||||
|
HEADER_ERR = 6 |
||||||
|
|
||||||
|
PIDITEMS = 10 |
||||||
|
|
||||||
|
|
||||||
|
def __init__(self): |
||||||
|
|
||||||
|
self.msp_name = { |
||||||
|
'name':None |
||||||
|
} |
||||||
|
self.msp_ident = { |
||||||
|
'version':None, |
||||||
|
'multiType':None, |
||||||
|
'multiCapability':None |
||||||
|
} |
||||||
|
self.msp_status = { |
||||||
|
'cycleTime':None, |
||||||
|
'i2cError':None, |
||||||
|
'present':None, |
||||||
|
'mode':None |
||||||
|
} |
||||||
|
self.msp_raw_imu = { |
||||||
|
'size':0, |
||||||
|
'accx':0.0, |
||||||
|
'accy':0.0, |
||||||
|
'accz':0.0, |
||||||
|
'gyrx':0.0, |
||||||
|
'gyry':0.0, |
||||||
|
'gyrz':0.0 |
||||||
|
} |
||||||
|
self.msp_set_rc = { |
||||||
|
'roll':0, |
||||||
|
'pitch':0, |
||||||
|
'yaw':0, |
||||||
|
'throttle':0, |
||||||
|
'aux1':0, |
||||||
|
'aux2':0, |
||||||
|
'aux3':0, |
||||||
|
'aux4':0 |
||||||
|
} |
||||||
|
self.msp_raw_gps = { |
||||||
|
'GPS_fix':0, |
||||||
|
'GPS_numSat':0, |
||||||
|
'GPS_latitude':0, |
||||||
|
'GPS_longitude':0, |
||||||
|
'GPS_altitude':0, |
||||||
|
'GPS_speed':0 |
||||||
|
} |
||||||
|
self.msp_comp_gps = { |
||||||
|
'GPS_distanceToHome':0, |
||||||
|
'GPS_directionToHome':0, |
||||||
|
'GPS_update':0 |
||||||
|
} |
||||||
|
self.msp_attitude = { |
||||||
|
'roll':0, |
||||||
|
'pitch':0, |
||||||
|
'yaw':0 |
||||||
|
} |
||||||
|
self.msp_altitude = { |
||||||
|
'alt':0, |
||||||
|
'vspeed':0 |
||||||
|
} |
||||||
|
self.msp_rc_tuning = { |
||||||
|
'byteRC_RATE':0, |
||||||
|
'byteRC_EXPO':0, |
||||||
|
'byteRollPitchRate':0, |
||||||
|
'byteYawRate':0, |
||||||
|
'byteDynThrPID':0, |
||||||
|
'byteThrottle_MID':0, |
||||||
|
'byteThrottle_EXPO':0 |
||||||
|
} |
||||||
|
self.msp_misc = { |
||||||
|
'intPowerTrigger': 0 |
||||||
|
} |
||||||
|
self.msp_osd_config = { |
||||||
|
'feature':None, # 8 |
||||||
|
'video_system':None, # 8 |
||||||
|
'units':None, # 8 |
||||||
|
'rssi_alarm':None, # 8 |
||||||
|
'cap_alarm':None, # 16 |
||||||
|
'unusaed_1':None, # 8 |
||||||
|
'osd_item_count':None, # 8 |
||||||
|
'alt_alarm':None, # 16 |
||||||
|
'osd_items': [None] * 60, # x16 |
||||||
|
'stats_item_count':None, # 8 |
||||||
|
'stats_items': [None] * 30, # x16 |
||||||
|
'timer_count':None, # 8 |
||||||
|
'timer_items': [None] * 10, # 16 |
||||||
|
'legacy_warnings':None, # 16 |
||||||
|
'warnings_count':None, # 8 |
||||||
|
'enabled_warnings':None, # 32 |
||||||
|
'profiles':None, # 8 |
||||||
|
'selected_profile':None, # 8 |
||||||
|
'osd_overlay':None, # 8 |
||||||
|
} |
||||||
|
self.msp_battery_state = { |
||||||
|
'cellCount':0, |
||||||
|
'capacity':0, |
||||||
|
'voltage':0, |
||||||
|
'mah':0, |
||||||
|
'current':0 |
||||||
|
} |
||||||
|
|
||||||
|
self.inBuf = bytearray([0] * 255) |
||||||
|
self.p = 0 |
||||||
|
self.c_state = self.IDLE |
||||||
|
self.err_rcvd = False |
||||||
|
self.checksum = 0 |
||||||
|
self.cmd = 0 |
||||||
|
self.offset=0 |
||||||
|
self.dataSize=0 |
||||||
|
self.servo = [] |
||||||
|
self.mot = [] |
||||||
|
self.RCChan = [] |
||||||
|
self.byteP = [] |
||||||
|
self.byteI = [] |
||||||
|
self.byteD = [] |
||||||
|
self.confINF = [] |
||||||
|
self.byteMP = [] |
||||||
|
|
||||||
|
self.confP = [] |
||||||
|
self.confI = [] |
||||||
|
self.confD = [] |
||||||
|
|
||||||
|
|
||||||
|
def read32(self): |
||||||
|
'''signed 32 bit number''' |
||||||
|
value, = struct.unpack("<i", self.inBuf[self.p:self.p+4]) |
||||||
|
self.p += 4 |
||||||
|
return value |
||||||
|
|
||||||
|
def read32u(self): |
||||||
|
'''unsigned 32 bit number''' |
||||||
|
value, = struct.unpack("<I", self.inBuf[self.p:self.p+4]) |
||||||
|
self.p += 4 |
||||||
|
return value |
||||||
|
|
||||||
|
def read16(self): |
||||||
|
'''signed 16 bit number''' |
||||||
|
value, = struct.unpack("<h", str(self.inBuf[self.p:self.p+2])) |
||||||
|
self.p += 2 |
||||||
|
return value |
||||||
|
|
||||||
|
def read16u(self): |
||||||
|
'''unsigned 16 bit number''' |
||||||
|
value, = struct.unpack("<H", str(self.inBuf[self.p:self.p+2])) |
||||||
|
self.p += 2 |
||||||
|
return value |
||||||
|
|
||||||
|
def read8(self): |
||||||
|
'''unsigned 8 bit number''' |
||||||
|
value, = struct.unpack("<B", str(self.inBuf[self.p:self.p+1])) |
||||||
|
self.p += 1 |
||||||
|
return value |
||||||
|
|
||||||
|
def requestMSP (self, msp, payload = [], payloadinbytes = False): |
||||||
|
|
||||||
|
if msp < 0: |
||||||
|
return 0 |
||||||
|
checksum = 0 |
||||||
|
bf = ['$', 'M', '<'] |
||||||
|
|
||||||
|
pl_size = 2 * ((len(payload)) & 0xFF) |
||||||
|
bf.append(pl_size) |
||||||
|
checksum ^= (pl_size&0xFF) |
||||||
|
|
||||||
|
bf.append(msp&0xFF) |
||||||
|
checksum ^= (msp&0xFF) |
||||||
|
if payload > 0: |
||||||
|
if (payloadinbytes == False): |
||||||
|
for c in struct.pack('<%dh' % ((pl_size) / 2), *payload): |
||||||
|
checksum ^= (ord(c) & 0xFF) |
||||||
|
else: |
||||||
|
for c in struct.pack('<%Bh' % ((pl_size) / 2), *payload): |
||||||
|
checksum ^= (ord(c) & 0xFF) |
||||||
|
bf = bf + payload |
||||||
|
bf.append(checksum) |
||||||
|
#print "here in requesrMSP" |
||||||
|
#print bf |
||||||
|
return bf |
||||||
|
|
||||||
|
|
||||||
|
def evaluateCommand(self, cmd, dataSize): |
||||||
|
if cmd == self.MSP_NAME: |
||||||
|
s = '' |
||||||
|
for i in range(0,dataSize,1): |
||||||
|
b = self.read8() |
||||||
|
if b == 0: |
||||||
|
break |
||||||
|
s += chr(b) |
||||||
|
self.msp_name['name'] = s |
||||||
|
elif cmd == self.MSP_IDENT: |
||||||
|
self.msp_ident['version'] = self.read8() |
||||||
|
self.msp_ident['multiType'] = self.read8() |
||||||
|
self.read8() # MSP version |
||||||
|
self.msp_ident['multiCapability'] = self.read32u() |
||||||
|
|
||||||
|
elif cmd == self.MSP_STATUS: |
||||||
|
self.msp_status['cycleTime'] = self.read16u() |
||||||
|
self.msp_status['i2cError'] = self.read16u() |
||||||
|
self.msp_status['present'] = self.read16u() |
||||||
|
self.msp_status['mode'] = self.read32u() |
||||||
|
|
||||||
|
elif cmd == self.MSP_RAW_IMU: |
||||||
|
self.msp_raw_imu['accx'] = float(self.read16()) |
||||||
|
self.msp_raw_imu['accy'] = float(self.read16()) |
||||||
|
self.msp_raw_imu['accz'] = float(self.read16()) |
||||||
|
self.msp_raw_imu['gyrx'] = float(self.read16()) |
||||||
|
self.msp_raw_imu['gyry'] = float(self.read16()) |
||||||
|
self.msp_raw_imu['gyrz'] = float(self.read16()) |
||||||
|
self.msp_raw_imu['magx'] = float(self.read16()) |
||||||
|
self.msp_raw_imu['magy'] = float(self.read16()) |
||||||
|
self.msp_raw_imu['magz'] = float(self.read16()) |
||||||
|
self.msp_raw_imu['size'] = dataSize |
||||||
|
|
||||||
|
elif cmd == self.MSP_SERVO: |
||||||
|
for i in range(0,8,1): |
||||||
|
self.servo.append(self.read16()) |
||||||
|
|
||||||
|
elif cmd == self.MSP_MOTOR: |
||||||
|
for i in range(0, 8, 1): |
||||||
|
self.mot.append(self.read16()) |
||||||
|
|
||||||
|
elif cmd == self.MSP_RC: |
||||||
|
for i in range(0, 8, 1): |
||||||
|
self.RCChan.append(self.read16()) |
||||||
|
|
||||||
|
elif cmd == self.MSP_RAW_GPS: |
||||||
|
self.msp_raw_gps['GPS_fix'] = self.read8() |
||||||
|
self.msp_raw_gps['GPS_numSat'] = self.read8() |
||||||
|
self.msp_raw_gps['GPS_latitude'] = self.read32() |
||||||
|
self.msp_raw_gps['GPS_longitude'] = self.read32() |
||||||
|
self.msp_raw_gps['GPS_altitude'] = self.read16() |
||||||
|
self.msp_raw_gps['GPS_speed'] = self.read16() |
||||||
|
|
||||||
|
elif cmd == self.MSP_COMP_GPS: |
||||||
|
self.msp_comp_gps['GPS_distanceToHome'] = self.read16() |
||||||
|
self.msp_comp_gps['GPS_directionToHome'] = self.read16() |
||||||
|
self.msp_comp_gps['GPS_update'] = self.read8() |
||||||
|
|
||||||
|
elif cmd == self.MSP_ATTITUDE: |
||||||
|
self.msp_attitude['roll'] = self.read16() |
||||||
|
self.msp_attitude['pitch'] = self.read16() |
||||||
|
self.msp_attitude['yaw'] = self.read16() |
||||||
|
|
||||||
|
elif cmd == self.MSP_ALTITUDE: |
||||||
|
self.msp_altitude['alt'] = self.read32() |
||||||
|
self.msp_altitude['vspeed'] = self.read16() |
||||||
|
|
||||||
|
elif cmd == self.MSP_ANALOG: |
||||||
|
x = None |
||||||
|
|
||||||
|
elif cmd == self.MSP_RC_TUNING: |
||||||
|
self.msp_rc_tuning['byteRC_RATE'] = self.read8() |
||||||
|
self.msp_rc_tuning['byteRC_EXPO'] = self.read8() |
||||||
|
self.msp_rc_tuning['byteRollPitchRate'] = self.read8() |
||||||
|
self.msp_rc_tuning['byteYawRate'] = self.read8() |
||||||
|
self.msp_rc_tuning['byteDynThrPID'] = self.read8() |
||||||
|
self.msp_rc_tuning['byteThrottle_MID'] = self.read8() |
||||||
|
self.msp_rc_tuning['byteThrottle_EXPO'] = self.read8() |
||||||
|
|
||||||
|
elif cmd == self.MSP_ACC_CALIBRATION: |
||||||
|
x = None |
||||||
|
|
||||||
|
elif cmd == self.MSP_MAG_CALIBRATION: |
||||||
|
x = None |
||||||
|
|
||||||
|
elif cmd == self.MSP_PID: |
||||||
|
for i in range(0, 8, 1): |
||||||
|
self.byteP[i] = (self.read8()) |
||||||
|
self.byteI[i] = (self.read8()) |
||||||
|
self.byteD[i] = (self.read8()) |
||||||
|
if (i != 4) and (i != 5) and (i != 6): |
||||||
|
self.confP[i] = (float(self.byteP[i])/10.0) |
||||||
|
self.confI[i] = (float(self.byteI[i])/1000.0) |
||||||
|
self.confD[i] = (float(self.byteD[i])) |
||||||
|
self.confP[4] = (float(self.byteP[4]) / 100.0) |
||||||
|
self.confI[4] = (float(self.byteI[4]) / 100.0) |
||||||
|
self.confD[4] = (float(self.byteD[4]) / 1000.0) |
||||||
|
self.confP[5] = (float(self.byteP[5]) / 10.0) |
||||||
|
self.confI[5] = (float(self.byteI[5]) / 100.0) |
||||||
|
self.confD[5] = (float(self.byteD[5]) / 1000.0) |
||||||
|
self.confP[6] = (float(self.byteP[6]) / 10.0) |
||||||
|
self.confI[6] = (float(self.byteI[6]) / 100.0) |
||||||
|
self.confD[6] = (float(self.byteD[6]) / 1000.0) |
||||||
|
elif cmd == self.MSP_BOX: |
||||||
|
x = None |
||||||
|
|
||||||
|
elif cmd == self.MSP_BOXNAMES: |
||||||
|
x = None |
||||||
|
|
||||||
|
elif cmd == self.MSP_PIDNAMES: |
||||||
|
x = None |
||||||
|
|
||||||
|
elif cmd == self.MSP_SERVO_CONF: |
||||||
|
x = None |
||||||
|
|
||||||
|
elif cmd == self.MSP_MISC: |
||||||
|
self.msp_misc['intPowerTrigger'] = self.read16u() |
||||||
|
for i in range(0,4,1): |
||||||
|
self.MConf[i] = self.read16u() |
||||||
|
self.MConf[4] = self.read32u() |
||||||
|
self.MConf[5] = self.read32u() |
||||||
|
|
||||||
|
elif cmd == self.MSP_MOTOR_PINS: |
||||||
|
for i in range(0, 8, 1): |
||||||
|
self.byteMP.append(self.read16()) |
||||||
|
|
||||||
|
elif cmd == self.MSP_DEBUGMSG: |
||||||
|
x = None |
||||||
|
elif cmd == self.MSP_DEBUG: |
||||||
|
x = None |
||||||
|
elif cmd == self.MSP_OSD_CONFIG: |
||||||
|
self.msp_osd_config['feature'] = int(self.read8()) # 8 |
||||||
|
self.msp_osd_config['video_system'] = self.read8() # 8 |
||||||
|
self.msp_osd_config['units'] = self.read8() # 8 |
||||||
|
self.msp_osd_config['rssi_alarm'] = self.read8() # 8 |
||||||
|
self.msp_osd_config['cap_alarm'] = self.read16() # 16 |
||||||
|
self.msp_osd_config['unusaed_1'] = self.read8() # 8 |
||||||
|
self.msp_osd_config['osd_item_count'] = self.read8() # 8 |
||||||
|
self.msp_osd_config['alt_alarm'] = self.read16() # 16 |
||||||
|
for i in range(0, self.msp_osd_config['osd_item_count'], 1): |
||||||
|
self.msp_osd_config['osd_items'][i] = self.read16u() # x 16 |
||||||
|
self.msp_osd_config['stats_item_count'] = self.read8() # 8 |
||||||
|
for i in range(0, self.msp_osd_config['stats_item_count'], 1): |
||||||
|
self.msp_osd_config['stats_items'][i] = self.read16u() # x 16 |
||||||
|
self.msp_osd_config['timer_count'] = self.read8() # 8 |
||||||
|
for i in range(0, self.msp_osd_config['timer_count'], 1): |
||||||
|
self.msp_osd_config['timer_items'][i] = self.read16u() # x 16 |
||||||
|
self.msp_osd_config['legacy_warnings'] = self.read16u() # 16 |
||||||
|
self.msp_osd_config['warnings_count'] = self.read8() # 8 |
||||||
|
self.msp_osd_config['enabled_warnings'] = self.read32u() # 32 |
||||||
|
self.msp_osd_config['profiles'] = self.read8() # 8 |
||||||
|
self.msp_osd_config['selected_profile'] = self.read8() # 8 |
||||||
|
self.msp_osd_config['osd_overlay'] = self.read8() |
||||||
|
# 8 |
||||||
|
elif cmd == self.MSP_BATTERY_STATE: |
||||||
|
self.msp_battery_state['cellCount'] = self.read8() |
||||||
|
self.msp_battery_state['capacity'] = self.read16u() |
||||||
|
self.msp_battery_state['voltage'] = self.read8() |
||||||
|
self.msp_battery_state['mah'] = self.read16u() |
||||||
|
self.msp_battery_state['current'] = self.read16() |
||||||
|
|
||||||
|
def parseMspData(self, buf): |
||||||
|
for c in buf: |
||||||
|
self.parseMspByte(c) |
||||||
|
|
||||||
|
def parseMspByte(self, c): |
||||||
|
if self.c_state == self.IDLE: |
||||||
|
if c == '$': |
||||||
|
self.c_state = self.HEADER_START |
||||||
|
else: |
||||||
|
self.c_state = self.IDLE |
||||||
|
elif self.c_state == self.HEADER_START: |
||||||
|
if c == 'M': |
||||||
|
self.c_state = self.HEADER_M |
||||||
|
else: |
||||||
|
self.c_state = self.IDLE |
||||||
|
elif self.c_state == self.HEADER_M: |
||||||
|
if c == '>': |
||||||
|
self.c_state = self.HEADER_ARROW |
||||||
|
elif c == '!': |
||||||
|
self.c_state = self.HEADER_ERR |
||||||
|
else: |
||||||
|
self.c_state = self.IDLE |
||||||
|
|
||||||
|
elif self.c_state == self.HEADER_ARROW or self.c_state == self.HEADER_ERR: |
||||||
|
self.err_rcvd = (self.c_state == self.HEADER_ERR) |
||||||
|
#print (struct.unpack('<B',c)[0]) |
||||||
|
self.dataSize = ((struct.unpack('<B',c)[0])&0xFF) |
||||||
|
# reset index variables |
||||||
|
self.p = 0 |
||||||
|
self.offset = 0 |
||||||
|
self.checksum = 0 |
||||||
|
self.checksum ^= ((struct.unpack('<B',c)[0])&0xFF) |
||||||
|
# the command is to follow |
||||||
|
self.c_state = self.HEADER_SIZE |
||||||
|
elif self.c_state == self.HEADER_SIZE: |
||||||
|
#print (struct.unpack('<B',c)[0]) |
||||||
|
self.cmd = ((struct.unpack('<B',c)[0])&0xFF) |
||||||
|
self.checksum ^= ((struct.unpack('<B',c)[0])&0xFF) |
||||||
|
self.c_state = self.HEADER_CMD |
||||||
|
elif self.c_state == self.HEADER_CMD and self.offset < self.dataSize: |
||||||
|
#print (struct.unpack('<B',c)[0]) |
||||||
|
self.checksum ^= ((struct.unpack('<B',c)[0])&0xFF) |
||||||
|
self.inBuf[self.offset] = c |
||||||
|
self.offset += 1 |
||||||
|
elif self.c_state == self.HEADER_CMD and self.offset >= self.dataSize: |
||||||
|
# compare calculated and transferred checksum |
||||||
|
#print "Final step..." |
||||||
|
if ((self.checksum&0xFF) == ((struct.unpack('<B',c)[0])&0xFF)): |
||||||
|
if self.err_rcvd: |
||||||
|
print "Copter didn't understand the request type" |
||||||
|
else: |
||||||
|
self.evaluateCommand(self.cmd, self.dataSize) |
||||||
|
else: |
||||||
|
print '"invalid checksum for command "+((int)(cmd&0xFF))+": "+(checksum&0xFF)+" expected, got "+(int)(c&0xFF))' |
||||||
|
|
||||||
|
self.c_state = self.IDLE |
||||||
|
|
||||||
|
def setPID(self): |
||||||
|
self.sendRequestMSP(self.requestMSP(self.MSP_PID)) |
||||||
|
self.receiveData(self.MSP_PID) |
||||||
|
time.sleep(0.04) |
||||||
|
payload = [] |
||||||
|
for i in range(0, self.PIDITEMS, 1): |
||||||
|
self.byteP[i] = int((round(self.confP[i] * 10))) |
||||||
|
self.byteI[i] = int((round(self.confI[i] * 1000))) |
||||||
|
self.byteD[i] = int((round(self.confD[i]))) |
||||||
|
|
||||||
|
|
||||||
|
# POS - 4 POSR - 5 NAVR - 6 |
||||||
|
|
||||||
|
self.byteP[4] = int((round(self.confP[4] * 100.0))) |
||||||
|
self.byteI[4] = int((round(self.confI[4] * 100.0))) |
||||||
|
self.byteP[5] = int((round(self.confP[5] * 10.0))) |
||||||
|
self.byteI[5] = int((round(self.confI[5] * 100.0))) |
||||||
|
self.byteD[5] = int((round(self.confD[5] * 10000.0))) / 10 |
||||||
|
|
||||||
|
self.byteP[6] = int((round(self.confP[6] * 10.0))) |
||||||
|
self.byteI[6] = int((round(self.confI[6] * 100.0))) |
||||||
|
self.byteD[6] = int((round(self.confD[6] * 10000.0))) / 10 |
||||||
|
|
||||||
|
for i in range(0, self.PIDITEMS, 1): |
||||||
|
payload.append(self.byteP[i]) |
||||||
|
payload.append(self.byteI[i]) |
||||||
|
payload.append(self.byteD[i]) |
||||||
|
print "Payload:..." |
||||||
|
print payload |
||||||
|
self.sendRequestMSP(self.requestMSP(self.MSP_SET_PID, payload, True), True) |
||||||
|
|
||||||
|
|
||||||
|
def arm(self): |
||||||
|
timer = 0 |
||||||
|
start = time.time() |
||||||
|
while timer < 0.5: |
||||||
|
data = [1500,1500,2000,1000] |
||||||
|
self.sendRequestMSP(self.requestMSP(self.MSP_SET_RAW_RC,data)) |
||||||
|
time.sleep(0.05) |
||||||
|
timer = timer + (time.time() - start) |
||||||
|
start = time.time() |
||||||
|
|
||||||
|
def disarm(self): |
||||||
|
timer = 0 |
||||||
|
start = time.time() |
||||||
|
while timer < 0.5: |
||||||
|
data = [1500,1500,1000,1000] |
||||||
|
self.sendRequestMSP(self.requestMSP(self.MSP_SET_RAW_RC,data)) |
||||||
|
time.sleep(0.05) |
||||||
|
timer = timer + (time.time() - start) |
||||||
|
start = time.time() |
||||||
|
|
||||||
|
|
||||||
|
def receiveIMU(self, duration): |
||||||
|
timer = 0 |
||||||
|
start = time.time() |
||||||
|
while timer < duration: |
||||||
|
self.sendRequestMSP(self.requestMSP(self.MSP_RAW_IMU)) |
||||||
|
self.receiveData(self.MSP_RAW_IMU) |
||||||
|
if self.msp_raw_imu['accx'] > 32768: # 2^15 ...to check if negative number is received |
||||||
|
self.msp_raw_imu['accx'] -= 65536 # 2^16 ...converting into 2's complement |
||||||
|
if self.msp_raw_imu['accy'] > 32768: |
||||||
|
self.msp_raw_imu['accy'] -= 65536 |
||||||
|
if self.msp_raw_imu['accz'] > 32768: |
||||||
|
self.msp_raw_imu['accz'] -= 65536 |
||||||
|
if self.msp_raw_imu['gyrx'] > 32768: |
||||||
|
self.msp_raw_imu['gyrx'] -= 65536 |
||||||
|
if self.msp_raw_imu['gyry'] > 32768: |
||||||
|
self.msp_raw_imu['gyry'] -= 65536 |
||||||
|
if self.msp_raw_imu['gyrz'] > 32768: |
||||||
|
self.msp_raw_imu['gyrz'] -= 65536 |
||||||
|
print "size: %d, accx: %f, accy: %f, accz: %f, gyrx: %f, gyry: %f, gyrz: %f " %(self.msp_raw_imu['size'], self.msp_raw_imu['accx'], self.msp_raw_imu['accy'], self.msp_raw_imu['accz'], self.msp_raw_imu['gyrx'], self.msp_raw_imu['gyry'], self.msp_raw_imu['gyrz']) |
||||||
|
time.sleep(0.04) |
||||||
|
timer = timer + (time.time() - start) |
||||||
|
start = time.time() |
||||||
|
|
||||||
|
|
||||||
|
def calibrateIMU(self): |
||||||
|
self.sendRequestMSP(self.requestMSP(self.MSP_ACC_CALIBRATION)) |
||||||
|
time.sleep(0.01) |
Loading…
Reference in new issue