config interface

43
Quadcopter Configuration Interface

Upload: ryan-boland

Post on 07-Jan-2017

209 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Config interface

Quadcopter Configuration

Interface

Page 2: Config interface

void text_debug() {

// ...

serial_printf("rc_throttle: %8.3f", rc_get(RC_THROTTLE)); serial_printf("\t m1: %d", motor_level(M1)); serial_printf("\t m2: %d", motor_level(M2)); serial_printf("\t m3: %d", motor_level(M3)); serial_printf("\t m4: %d", motor_level(M4)); serial_printlnf("");

}

Debugging with the console

Page 3: Config interface

Demo

Page 4: Config interface

Going wireless

bluetooth10 meters Radio telemetry

500m ++

Page 5: Config interface

• Chrome Packaged App

• Python with PySide (Qt)

• Electron (NodeJS)

Options

Page 6: Config interface

Python with PySide (Qt)

Page 7: Config interface

Electron

https://github.com/sindresorhus/awesome-electron

Page 8: Config interface

Electron

Page 9: Config interface

Electron

Page 10: Config interface

So, we can use Node SerialPort!

var SerialPort = require(“serialport").SerialPort

var serialPort = new SerialPort("/dev/tty-usbserial1", { baudrate: 57600 });

const onDataReceived = function(data) { processData(data); }

Page 11: Config interface

Electron

https://github.com/sindresorhus/awesome-electron

Start with a boilerplate!

Page 12: Config interface

Storing and passing configuration data

Page 13: Config interface

On the C side:typedef struct {

uint16_t version; uint16_t motors_min; uint16_t motors_max;

} CONFIG_struct;

JavaScript:let config = { version: 1, motors_min: 0, motors_max: 2000 }

Page 14: Config interface

Config struct requirementstypedef struct {

uint16_t version; uint16_t motors_min; uint16_t motors_max;

} CONFIG_struct;

1. ability to access the config data from anywhere in the program ( e.g. CONFIG.motors_min )

2. Ability to serialize the struct to binary to pass in the packet

Page 15: Config interface

[version][motors_min][motors_max]

On the C side:typedef struct {

uint16_t version; uint16_t motors_min; uint16_t motors_max;

} CONFIG_struct;

in memory (each 16 bits):

Page 16: Config interface

[version][motors_min][motors_max]

typedef struct __attribute__((packed)) {

uint16_t version; uint16_t motors_min; uint16_t motors_max;

} CONFIG_struct;

mark the struct as “packed”, ensure that there is no padding between values

Page 17: Config interface

typedef struct __attribute__((packed)) { uint16_t version; uint16_t motor_min; uint16_t motor_max; } CONFIG_struct;

typedef union { CONFIG_struct data; uint8_t raw[sizeof(CONFIG_struct)]; } CONFIG_union;

extern CONFIG_union CONFIG;

Config data struct

// anywhere in the code

make_something_happen(CONFIG.data.max);

Page 18: Config interface

typedef struct __attribute__((packed)) { uint16_t version; uint16_t motor_min; uint16_t motor_max; } CONFIG_struct;

typedef union { CONFIG_struct data; uint8_t raw[sizeof(CONFIG_struct)]; } CONFIG_union;

extern CONFIG_union CONFIG;

Config data struct

// anywhere in the code

make_something_happen(CONFIG.data.max);

Page 19: Config interface

typedef struct __attribute__((packed)) { uint16_t version; uint16_t motor_min; uint16_t motor_max; } CONFIG_struct;

typedef union { CONFIG_struct data; uint8_t raw[sizeof(CONFIG_struct)]; } CONFIG_union;

extern CONFIG_union CONFIG;

Config data struct

// anywhere in the code

make_something_happen(CONFIG.data.max);

Page 20: Config interface

typedef struct __attribute__((packed)) { uint16_t version; uint16_t motor_min; uint16_t motor_max; } CONFIG_struct;

typedef union { CONFIG_struct data; uint8_t raw[sizeof(CONFIG_struct)]; } CONFIG_union;

extern CONFIG_union CONFIG;

Config data struct

// anywhere in the code

make_something_happen(CONFIG.data.max);

Page 21: Config interface

typedef union { CONFIG_struct data; uint8_t raw[sizeof(CONFIG_struct)]; } CONFIG_union;

Config data struct

void config_update_eeprom() { for (uint16_t i = 0; i < sizeof(CONFIG); i++) { EEPROM.update(i, CONFIG.raw[i]); } }

Page 22: Config interface

var buffer = new ArrayBuffer(6) fillInArrayBufferFromSerialPort(buffer)

var dataView = new DataView(buffer)

var version = dataview.getUint16(0) var motorMin = dataview.getUint16(2) var motorMax = dataview.getUint16(4)

Config data - JavaScriptArrayBuffer & DataView

typedef struct __attribute__((packed)) { uint16_t version; uint16_t motor_min; uint16_t motor_max; } CONFIG_struct;

Page 23: Config interface

var buffer = new ArrayBuffer(6) fillInArrayBufferFromSerialPort(buffer)

var dataView = new DataView(buffer)

var version = dataview.getUint16(0) var motorMin = dataview.getUint16(2) var motorMax = dataview.getUint16(4)

Config data - JavaScriptArrayBuffer & DataView

typedef struct __attribute__((packed)) { uint16_t version; uint16_t motor_min; uint16_t motor_max; } CONFIG_struct;

Page 24: Config interface

var buffer = new ArrayBuffer(6) fillInArrayBufferFromSerialPort(buffer)

var dataView = new DataView(buffer)

var version = dataview.getUint16(0) var motorMin = dataview.getUint16(2) var motorMax = dataview.getUint16(4)

Config data - JavaScriptArrayBuffer & DataView

typedef struct __attribute__((packed)) { uint16_t version; uint16_t motor_min; uint16_t motor_max; } CONFIG_struct;

Page 25: Config interface

On the C side:typedef struct {

uint16_t version; uint16_t motors_min; uint16_t motors_max;

} CONFIG_struct;

JavaScript:let config = { version: 1, motors_min: 0, motors_max: 2000 }

Page 26: Config interface

set_config 1.00 0 2000

Sending data both ways? (configuration)

Simple approach - print text:

(but difficult to parse text and no error checking)

Page 27: Config interface

[HEADER1][HEADER2][CODE][LENGTH_LSB][LENGTH_MSB][DATA][CRC]

Better approach: Binary packets

Page 28: Config interface

[HEADER1][HEADER2][CODE][LENGTH_LSB][LENGTH_MSB][DATA][CRC]

Binary packet example

• JavaScript app sends a packet with a code of REQUEST_CONFIG and no data

• The micro controller responds with a packet with a code of REQUEST_CONFIG that contains all of the configuration data

Page 29: Config interface

[HEADER1][HEADER2][CODE][LENGTH_LSB][LENGTH_MSB][DATA][CRC]

Binary packets

#define PACKET_HEADER1 0x02 #define PACKET_HEADER2 0xB5

Headers - indicate the start of a packet

Page 30: Config interface

[HEADER1][HEADER2][CODE][LENGTH_LSB][LENGTH_MSB][DATA][CRC]

Binary packets

#define REQUEST_CONFIG 1 #define REQUEST_GYRO_ACC 2 #define REQUEST_RC 3 #define REQUEST_MOTORS 4 #define REQUEST_RATE_PIDS 5

#define SET_CONFIG 101

#define INFO_SUCCESS 201 #define INFO_FAILURE 202 #define INFO_BAD_CRC 203

Code - explains what the packet is about

Page 31: Config interface

[HEADER1][HEADER2][CODE][LENGTH_LSB][LENGTH_MSB][DATA][CRC]

Binary packets

Length - how many bytes of data is being transmitted

Page 32: Config interface

[HEADER1][HEADER2][CODE][LENGTH_LSB][LENGTH_MSB][DATA][CRC]

Binary packets

Data - binary data

We keep reading this until we get to the number of bytes stated in the LENGTH section of the packet

Page 33: Config interface

[HEADER1][HEADER2][CODE][LENGTH_LSB][LENGTH_MSB][DATA][CRC]

Binary packets

CRC - cyclic redundancy check

This is a code that is calculated based on the data within the packet.

When the packet is received, the client calculates the CRC on their own, and ensure that it matches what is specified here

Page 34: Config interface

[HEADER1][HEADER2][CODE][LENGTH_LSB][LENGTH_MSB][DATA][CRC]

CRC Calculation

Calculated by XOR’ing the binary representation of all of the bytes of the packet body

Page 35: Config interface

Packet processing code: processCommand(data) { switch(this.state) { case 0: if (data === serialCodes.PACKET_HEADER1) { this.state++; } break; case 1: if (data === serialCodes.PACKET_HEADER2) { this.state++; } else { this.state = 0; } break; case 2: this.code = data; this.incomingCrc = data; this.state++; break;

[HEADER1][HEADER2][CODE][LENGTH_LSB][LENGTH_MSB][DATA][CRC]

Page 36: Config interface

Packet processing code: processCommand(data) { switch(this.state) { case 0: if (data === serialCodes.PACKET_HEADER1) { this.state++; } break; case 1: if (data === serialCodes.PACKET_HEADER2) { this.state++; } else { this.state = 0; } break; case 2: this.code = data; this.incomingCrc = data; this.state++; break;

[HEADER1][HEADER2][CODE][LENGTH_LSB][LENGTH_MSB][DATA][CRC]

Page 37: Config interface

Packet processing code: processCommand(data) { switch(this.state) { case 0: if (data === serialCodes.PACKET_HEADER1) { this.state++; } break; case 1: if (data === serialCodes.PACKET_HEADER2) { this.state++; } else { this.state = 0; } break; case 2: this.code = data; this.incomingCrc = data; this.state++; break;

[HEADER1][HEADER2][CODE][LENGTH_LSB][LENGTH_MSB][DATA][CRC]

Page 38: Config interface

Packet processing code: processCommand(data) { switch(this.state) { case 0: if (data === serialCodes.PACKET_HEADER1) { this.state++; } break; case 1: if (data === serialCodes.PACKET_HEADER2) { this.state++; } else { this.state = 0; } break; case 2: this.code = data; this.incomingCrc = data; this.state++; break;

[HEADER1][HEADER2][CODE][LENGTH_LSB][LENGTH_MSB][DATA][CRC]

Page 39: Config interface

Packet processing code: processCommand(data) { switch(this.state) { case 0: if (data === serialCodes.PACKET_HEADER1) { this.state++; } break; case 1: if (data === serialCodes.PACKET_HEADER2) { this.state++; } else { this.state = 0; } break; case 2: this.code = data; this.incomingCrc = data; this.state++; break;

[HEADER1][HEADER2][CODE][LENGTH_LSB][LENGTH_MSB][DATA][CRC]

Page 40: Config interface

Scenario - App requestingcurrent config data

• JavaScript app sends a packet with a code of REQUEST_CONFIG and no data

• The micro controller responds with a packet with a code of REQUEST_CONFIG that contains all of the configuration data

Page 41: Config interface

• JavaScript app sends a packet with a code of SET_CONFIG and config data

• The micro controller updates its config struct and responds with a packet with a code of INFO_SUCCESS

Scenario - App updatingconfig data

Page 42: Config interface

• JavaScript app sends a packet with a code of REQUEST_MOTORS and no data

• The micro controller responds with a packet with a code of REQUEST_MOTORS that contains the current motor speeds

Scenario - Displaying motor speed data

Page 43: Config interface

Questions?