From fc82ed0c693635ccfaeee4f060b93b1a1c083acb Mon Sep 17 00:00:00 2001 From: Simon Wilks Date: Wed, 20 Mar 2013 13:21:00 +0100 Subject: [PATCH 01/84] Skeleton code. --- apps/drivers/ets/Makefile | 42 ++ apps/drivers/ets/ets_airspeed.cpp | 784 ++++++++++++++++++++++++++++++ 2 files changed, 826 insertions(+) create mode 100644 apps/drivers/ets/Makefile create mode 100644 apps/drivers/ets/ets_airspeed.cpp diff --git a/apps/drivers/ets/Makefile b/apps/drivers/ets/Makefile new file mode 100644 index 0000000000..9089d97af2 --- /dev/null +++ b/apps/drivers/ets/Makefile @@ -0,0 +1,42 @@ +############################################################################ +# +# Copyright (C) 2013 PX4 Development Team. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name PX4 nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +# +# Makefile to build the Eagle Tree Airspeed V3 driver. +# + +APPNAME = ets_airspeed +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 2048 + +include $(APPDIR)/mk/app.mk diff --git a/apps/drivers/ets/ets_airspeed.cpp b/apps/drivers/ets/ets_airspeed.cpp new file mode 100644 index 0000000000..4ac707c3cb --- /dev/null +++ b/apps/drivers/ets/ets_airspeed.cpp @@ -0,0 +1,784 @@ +/**************************************************************************** + * + * Copyright (C) 2013 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/** + * @file airspeed.cpp + * @author Simon Wilks + * + * Driver for the Eagle Tree Airspeed V3 connected via I2C. + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include + +#include +#include + + +/* Configuration Constants */ +#define ETS_BUS PX4_I2C_BUS_EXPANSION +#define ETS_BASEADDR 0x70 /* 7-bit address. 8-bit address is 0xEA */ + +/* ETS Registers addresses */ + +#define ETS_READ_CMD 0x07 /* Read the data */ + +#define ETS_CONVERSION_INTERVAL 60000 /* 60ms */ + +/* oddly, ERROR is not defined for c++ */ +#ifdef ERROR +# undef ERROR +#endif +static const int ERROR = -1; + +#ifndef CONFIG_SCHED_WORKQUEUE +# error This requires CONFIG_SCHED_WORKQUEUE. +#endif + +class ETS : public device::I2C +{ +public: + ETS(int bus = ETS_BUS, int address = ETS_BASEADDR); + virtual ~ETS(); + + virtual int init(); + + virtual ssize_t read(struct file *filp, char *buffer, size_t buflen); + virtual int ioctl(struct file *filp, int cmd, unsigned long arg); + + /** + * Diagnostics - print some basic information about the driver. + */ + void print_info(); + +protected: + virtual int probe(); + +private: + work_s _work; + unsigned _num_reports; + volatile unsigned _next_report; + volatile unsigned _oldest_report; + range_finder_report *_reports; + bool _sensor_ok; + int _measure_ticks; + bool _collect_phase; + + orb_advert_t _differential_pressure_topic; + + perf_counter_t _sample_perf; + perf_counter_t _comms_errors; + perf_counter_t _buffer_overflows; + + /** + * Test whether the device supported by the driver is present at a + * specific address. + * + * @param address The I2C bus address to probe. + * @return True if the device is present. + */ + int probe_address(uint8_t address); + + /** + * Initialise the automatic measurement state machine and start it. + * + * @note This function is called at open and error time. It might make sense + * to make it more aggressive about resetting the bus in case of errors. + */ + void start(); + + /** + * Stop the automatic measurement state machine. + */ + void stop(); + + /** + * Perform a poll cycle; collect from the previous measurement + * and start a new one. + */ + void cycle(); + int measure(); + int collect(); + /** + * Static trampoline from the workq context; because we don't have a + * generic workq wrapper yet. + * + * @param arg Instance pointer for the driver that is polling. + */ + static void cycle_trampoline(void *arg); + + +}; + +/* helper macro for handling report buffer indices */ +#define INCREMENT(_x, _lim) do { _x++; if (_x >= _lim) _x = 0; } while(0) + +/* + * Driver 'main' command. + */ +extern "C" __EXPORT int ETS_main(int argc, char *argv[]); + +ETS::ETS(int bus, int address) : + I2C("ETS", AIRSPEED_SENSOR_DEVICE_PATH, bus, address, 100000), + _num_reports(0), + _next_report(0), + _oldest_report(0), + _reports(nullptr), + _sensor_ok(false), + _measure_ticks(0), + _collect_phase(false), + _differential_pressure_topic(-1), + _sample_perf(perf_alloc(PC_ELAPSED, "ETS_read")), + _comms_errors(perf_alloc(PC_COUNT, "ETS_comms_errors")), + _buffer_overflows(perf_alloc(PC_COUNT, "ETS_buffer_overflows")) +{ + // enable debug() calls + _debug_enabled = true; + + // work_cancel in the dtor will explode if we don't do this... + memset(&_work, 0, sizeof(_work)); +} + +ETS::~ETS() +{ + /* make sure we are truly inactive */ + stop(); + + /* free any existing reports */ + if (_reports != nullptr) + delete[] _reports; +} + +int +ETS::init() +{ + int ret = ERROR; + + /* do I2C init (and probe) first */ + if (I2C::init() != OK) + goto out; + + /* allocate basic report buffers */ + _num_reports = 2; + _reports = new struct range_finder_report[_num_reports]; + + if (_reports == nullptr) + goto out; + + _oldest_report = _next_report = 0; + + /* get a publish handle on the airspeed topic */ + memset(&_reports[0], 0, sizeof(_reports[0])); + _differential_pressure_topic = orb_advertise(ORB_ID(_differential_pressure), &_reports[0]); + + if (_differential_pressure_topic < 0) + debug("failed to create airspeed sensor object. Did you start uOrb?"); + + ret = OK; + /* sensor is ok, but we don't really know if it is within range */ + _sensor_ok = true; +out: + return ret; +} + +int +ETS::probe() +{ + return measure(); +} + +int +ETS::ioctl(struct file *filp, int cmd, unsigned long arg) +{ + switch (cmd) { + + case SENSORIOCSPOLLRATE: { + switch (arg) { + + /* switching to manual polling */ + case SENSOR_POLLRATE_MANUAL: + stop(); + _measure_ticks = 0; + return OK; + + /* external signalling (DRDY) not supported */ + case SENSOR_POLLRATE_EXTERNAL: + + /* zero would be bad */ + case 0: + return -EINVAL; + + /* set default/max polling rate */ + case SENSOR_POLLRATE_MAX: + case SENSOR_POLLRATE_DEFAULT: { + /* do we need to start internal polling? */ + bool want_start = (_measure_ticks == 0); + + /* set interval for next measurement to minimum legal value */ + _measure_ticks = USEC2TICK(ETS_CONVERSION_INTERVAL); + + /* if we need to start the poll state machine, do it */ + if (want_start) + start(); + + return OK; + } + + /* adjust to a legal polling interval in Hz */ + default: { + /* do we need to start internal polling? */ + bool want_start = (_measure_ticks == 0); + + /* convert hz to tick interval via microseconds */ + unsigned ticks = USEC2TICK(1000000 / arg); + + /* check against maximum rate */ + if (ticks < USEC2TICK(ETS_CONVERSION_INTERVAL)) + return -EINVAL; + + /* update interval for next measurement */ + _measure_ticks = ticks; + + /* if we need to start the poll state machine, do it */ + if (want_start) + start(); + + return OK; + } + } + } + + case SENSORIOCGPOLLRATE: + if (_measure_ticks == 0) + return SENSOR_POLLRATE_MANUAL; + + return (1000 / _measure_ticks); + + case SENSORIOCSQUEUEDEPTH: { + /* add one to account for the sentinel in the ring */ + arg++; + + /* lower bound is mandatory, upper bound is a sanity check */ + if ((arg < 2) || (arg > 100)) + return -EINVAL; + + /* allocate new buffer */ + struct range_finder_report *buf = new struct range_finder_report[arg]; + + if (nullptr == buf) + return -ENOMEM; + + /* reset the measurement state machine with the new buffer, free the old */ + stop(); + delete[] _reports; + _num_reports = arg; + _reports = buf; + start(); + + return OK; + } + + case SENSORIOCGQUEUEDEPTH: + return _num_reports - 1; + + case SENSORIOCRESET: + /* XXX implement this */ + return -EINVAL; + + default: + /* give it to the superclass */ + return I2C::ioctl(filp, cmd, arg); + } +} + +ssize_t +ETS::read(struct file *filp, char *buffer, size_t buflen) +{ + unsigned count = buflen / sizeof(struct range_finder_report); + int ret = 0; + + /* buffer must be large enough */ + if (count < 1) + return -ENOSPC; + + /* if automatic measurement is enabled */ + if (_measure_ticks > 0) { + + /* + * While there is space in the caller's buffer, and reports, copy them. + * Note that we may be pre-empted by the workq thread while we are doing this; + * we are careful to avoid racing with them. + */ + while (count--) { + if (_oldest_report != _next_report) { + memcpy(buffer, _reports + _oldest_report, sizeof(*_reports)); + ret += sizeof(_reports[0]); + INCREMENT(_oldest_report, _num_reports); + } + } + + /* if there was no data, warn the caller */ + return ret ? ret : -EAGAIN; + } + + /* manual measurement - run one conversion */ + /* XXX really it'd be nice to lock against other readers here */ + do { + _oldest_report = _next_report = 0; + + /* trigger a measurement */ + if (OK != measure()) { + ret = -EIO; + break; + } + + /* wait for it to complete */ + usleep(ETS_CONVERSION_INTERVAL); + + /* run the collection phase */ + if (OK != collect()) { + ret = -EIO; + break; + } + + /* state machine will have generated a report, copy it out */ + memcpy(buffer, _reports, sizeof(*_reports)); + ret = sizeof(*_reports); + + } while (0); + + return ret; +} + +int +ETS::measure() +{ + int ret; + + /* + * Send the command to begin a measurement. + */ + uint8_t cmd = ETS_READ_CMD; + ret = transfer(&cmd, 1, nullptr, 0); + + if (OK != ret) + { + perf_count(_comms_errors); + log("i2c::transfer returned %d", ret); + return ret; + } + ret = OK; + + return ret; +} + +int +ETS::collect() +{ + int ret = -EIO; + + /* read from the sensor */ + uint8_t val[2] = {0, 0}; + + perf_begin(_sample_perf); + + ret = transfer(nullptr, 0, &val[0], 2); + + if (ret < 0) + { + log("error reading from sensor: %d", ret); + return ret; + } + + uint16_t distance = val[0] << 8 | val[1]; + float si_units = (distance * 1.0f)/ 100.0f; /* cm to m */ + /* this should be fairly close to the end of the measurement, so the best approximation of the time */ + _reports[_next_report].timestamp = hrt_absolute_time(); + _reports[_next_report].distance = si_units; + _reports[_next_report].valid = si_units > get_minimum_distance() && si_units < get_maximum_distance() ? 1 : 0; + + /* publish it */ + orb_publish(ORB_ID(_differential_pressure), _differential_pressure_topic, &_reports[_next_report]); + + /* post a report to the ring - note, not locked */ + INCREMENT(_next_report, _num_reports); + + /* if we are running up against the oldest report, toss it */ + if (_next_report == _oldest_report) { + perf_count(_buffer_overflows); + INCREMENT(_oldest_report, _num_reports); + } + + /* notify anyone waiting for data */ + poll_notify(POLLIN); + + ret = OK; + +out: + perf_end(_sample_perf); + return ret; + + return ret; +} + +void +ETS::start() +{ + /* reset the report ring and state machine */ + _collect_phase = false; + _oldest_report = _next_report = 0; + + /* schedule a cycle to start things */ + work_queue(HPWORK, &_work, (worker_t)&ETS::cycle_trampoline, this, 1); + + /* notify about state change */ + struct subsystem_info_s info = { + true, + true, + true, + SUBSYSTEM_TYPE_DIFFPRESSURE}; + static orb_advert_t pub = -1; + + if (pub > 0) { + orb_publish(ORB_ID(subsystem_info), pub, &info); + } else { + pub = orb_advertise(ORB_ID(subsystem_info), &info); + } +} + +void +ETS::stop() +{ + work_cancel(HPWORK, &_work); +} + +void +ETS::cycle_trampoline(void *arg) +{ + ETS *dev = (ETS *)arg; + + dev->cycle(); +} + +void +ETS::cycle() +{ + /* collection phase? */ + if (_collect_phase) { + + /* perform collection */ + if (OK != collect()) { + log("collection error"); + /* restart the measurement state machine */ + start(); + return; + } + + /* next phase is measurement */ + _collect_phase = false; + + /* + * Is there a collect->measure gap? + */ + if (_measure_ticks > USEC2TICK(ETS_CONVERSION_INTERVAL)) { + + /* schedule a fresh cycle call when we are ready to measure again */ + work_queue(HPWORK, + &_work, + (worker_t)&ETS::cycle_trampoline, + this, + _measure_ticks - USEC2TICK(ETS_CONVERSION_INTERVAL)); + + return; + } + } + + /* measurement phase */ + if (OK != measure()) + log("measure error"); + + /* next phase is collection */ + _collect_phase = true; + + /* schedule a fresh cycle call when the measurement is done */ + work_queue(HPWORK, + &_work, + (worker_t)&ETS::cycle_trampoline, + this, + USEC2TICK(ETS_CONVERSION_INTERVAL)); +} + +void +ETS::print_info() +{ + perf_print_counter(_sample_perf); + perf_print_counter(_comms_errors); + perf_print_counter(_buffer_overflows); + printf("poll interval: %u ticks\n", _measure_ticks); + printf("report queue: %u (%u/%u @ %p)\n", + _num_reports, _oldest_report, _next_report, _reports); +} + +/** + * Local functions in support of the shell command. + */ +namespace ETS +{ + +/* oddly, ERROR is not defined for c++ */ +#ifdef ERROR +# undef ERROR +#endif +const int ERROR = -1; + +ETS *g_dev; + +void start(); +void stop(); +void test(); +void reset(); +void info(); + +/** + * Start the driver. + */ +void +start() +{ + int fd; + + if (g_dev != nullptr) + errx(1, "already started"); + + /* create the driver */ + g_dev = new ETS(ETS_BUS); + + if (g_dev == nullptr) + goto fail; + + if (OK != g_dev->init()) + goto fail; + + /* set the poll rate to default, starts automatic data collection */ + fd = open(AIRSPEED_SENSOR_DEVICE_PATH, O_RDONLY); + + if (fd < 0) + goto fail; + + if (ioctl(fd, SENSORIOCSPOLLRATE, SENSOR_POLLRATE_DEFAULT) < 0) + goto fail; + + exit(0); + +fail: + + if (g_dev != nullptr) + { + delete g_dev; + g_dev = nullptr; + } + + errx(1, "driver start failed"); +} + +/** + * Stop the driver + */ +void stop() +{ + if (g_dev != nullptr) + { + delete g_dev; + g_dev = nullptr; + } + else + { + errx(1, "driver not running"); + } + exit(0); +} + +/** + * Perform some basic functional tests on the driver; + * make sure we can collect data from the sensor in polled + * and automatic modes. + */ +void +test() +{ + struct range_finder_report report; + ssize_t sz; + int ret; + + int fd = open(RANGE_FINDER_DEVICE_PATH, O_RDONLY); + + if (fd < 0) + err(1, "%s open failed (try 'ETS start' if the driver is not running", RANGE_FINDER_DEVICE_PATH); + + /* do a simple demand read */ + sz = read(fd, &report, sizeof(report)); + + if (sz != sizeof(report)) + err(1, "immediate read failed"); + + warnx("single read"); + warnx("measurement: %0.2f m", (double)report.distance); + warnx("time: %lld", report.timestamp); + + /* start the sensor polling at 2Hz */ + if (OK != ioctl(fd, SENSORIOCSPOLLRATE, 2)) + errx(1, "failed to set 2Hz poll rate"); + + /* read the sensor 5x and report each value */ + for (unsigned i = 0; i < 5; i++) { + struct pollfd fds; + + /* wait for data to be ready */ + fds.fd = fd; + fds.events = POLLIN; + ret = poll(&fds, 1, 2000); + + if (ret != 1) + errx(1, "timed out waiting for sensor data"); + + /* now go get it */ + sz = read(fd, &report, sizeof(report)); + + if (sz != sizeof(report)) + err(1, "periodic read failed"); + + warnx("periodic read %u", i); + warnx("measurement: %0.3f", (double)report.distance); + warnx("time: %lld", report.timestamp); + } + + errx(0, "PASS"); +} + +/** + * Reset the driver. + */ +void +reset() +{ + int fd = open(RANGE_FINDER_DEVICE_PATH, O_RDONLY); + + if (fd < 0) + err(1, "failed "); + + if (ioctl(fd, SENSORIOCRESET, 0) < 0) + err(1, "driver reset failed"); + + if (ioctl(fd, SENSORIOCSPOLLRATE, SENSOR_POLLRATE_DEFAULT) < 0) + err(1, "driver poll restart failed"); + + exit(0); +} + +/** + * Print a little info about the driver. + */ +void +info() +{ + if (g_dev == nullptr) + errx(1, "driver not running"); + + printf("state @ %p\n", g_dev); + g_dev->print_info(); + + exit(0); +} + +} // namespace + +int +ETS_main(int argc, char *argv[]) +{ + /* + * Start/load the driver. + */ + if (!strcmp(argv[1], "start")) + ETS::start(); + + /* + * Stop the driver + */ + if (!strcmp(argv[1], "stop")) + ETS::stop(); + + /* + * Test the driver/device. + */ + if (!strcmp(argv[1], "test")) + ETS::test(); + + /* + * Reset the driver. + */ + if (!strcmp(argv[1], "reset")) + ETS::reset(); + + /* + * Print driver information. + */ + if (!strcmp(argv[1], "info") || !strcmp(argv[1], "status")) + ETS::info(); + + errx(1, "unrecognized command, try 'start', 'test', 'reset' or 'info'"); +} From 4f99200b0ff102c01f415a57e9f173a863483d2a Mon Sep 17 00:00:00 2001 From: Simon Wilks Date: Thu, 11 Apr 2013 08:36:54 +0200 Subject: [PATCH 02/84] Initial implementation that can read values from the ETS. --- apps/drivers/{ets => ets_airspeed}/Makefile | 0 .../{ets => ets_airspeed}/ets_airspeed.cpp | 123 +++++++++--------- apps/px4io/controls.c | 2 +- apps/uORB/objects_common.cpp | 3 + nuttx/configs/px4fmu/nsh/appconfig | 1 + 5 files changed, 67 insertions(+), 62 deletions(-) rename apps/drivers/{ets => ets_airspeed}/Makefile (100%) rename apps/drivers/{ets => ets_airspeed}/ets_airspeed.cpp (82%) diff --git a/apps/drivers/ets/Makefile b/apps/drivers/ets_airspeed/Makefile similarity index 100% rename from apps/drivers/ets/Makefile rename to apps/drivers/ets_airspeed/Makefile diff --git a/apps/drivers/ets/ets_airspeed.cpp b/apps/drivers/ets_airspeed/ets_airspeed.cpp similarity index 82% rename from apps/drivers/ets/ets_airspeed.cpp rename to apps/drivers/ets_airspeed/ets_airspeed.cpp index 4ac707c3cb..790e949e0f 100644 --- a/apps/drivers/ets/ets_airspeed.cpp +++ b/apps/drivers/ets_airspeed/ets_airspeed.cpp @@ -65,20 +65,22 @@ #include #include +#include #include #include /* Configuration Constants */ -#define ETS_BUS PX4_I2C_BUS_EXPANSION -#define ETS_BASEADDR 0x70 /* 7-bit address. 8-bit address is 0xEA */ +#define ETS_AIRSPEED_BUS PX4_I2C_BUS_ESC +#define ETS_AIRSPEED_ADDRESS 0x75 -/* ETS Registers addresses */ +/* ETS_AIRSPEED Registers addresses */ -#define ETS_READ_CMD 0x07 /* Read the data */ +#define ETS_AIRSPEED_READ_CMD 0x07 /* Read the data */ -#define ETS_CONVERSION_INTERVAL 60000 /* 60ms */ +/* Max measurement rate is 100Hz */ +#define ETS_AIRSPEED_CONVERSION_INTERVAL (1000000 / 100) /* microseconds */ /* oddly, ERROR is not defined for c++ */ #ifdef ERROR @@ -90,11 +92,11 @@ static const int ERROR = -1; # error This requires CONFIG_SCHED_WORKQUEUE. #endif -class ETS : public device::I2C +class ETS_AIRSPEED : public device::I2C { public: - ETS(int bus = ETS_BUS, int address = ETS_BASEADDR); - virtual ~ETS(); + ETS_AIRSPEED(int bus = ETS_AIRSPEED_BUS, int address = ETS_AIRSPEED_ADDRESS); + virtual ~ETS_AIRSPEED(); virtual int init(); @@ -114,7 +116,7 @@ private: unsigned _num_reports; volatile unsigned _next_report; volatile unsigned _oldest_report; - range_finder_report *_reports; + airspeed_report *_reports; bool _sensor_ok; int _measure_ticks; bool _collect_phase; @@ -171,10 +173,10 @@ private: /* * Driver 'main' command. */ -extern "C" __EXPORT int ETS_main(int argc, char *argv[]); +extern "C" __EXPORT int ets_airspeed_main(int argc, char *argv[]); -ETS::ETS(int bus, int address) : - I2C("ETS", AIRSPEED_SENSOR_DEVICE_PATH, bus, address, 100000), +ETS_AIRSPEED::ETS_AIRSPEED(int bus, int address) : + I2C("ETS_AIRSPEED", AIRSPEED_DEVICE_PATH, bus, address, 100000), _num_reports(0), _next_report(0), _oldest_report(0), @@ -183,9 +185,9 @@ ETS::ETS(int bus, int address) : _measure_ticks(0), _collect_phase(false), _differential_pressure_topic(-1), - _sample_perf(perf_alloc(PC_ELAPSED, "ETS_read")), - _comms_errors(perf_alloc(PC_COUNT, "ETS_comms_errors")), - _buffer_overflows(perf_alloc(PC_COUNT, "ETS_buffer_overflows")) + _sample_perf(perf_alloc(PC_ELAPSED, "ETS_AIRSPEED_read")), + _comms_errors(perf_alloc(PC_COUNT, "ETS_AIRSPEED_comms_errors")), + _buffer_overflows(perf_alloc(PC_COUNT, "ETS_AIRSPEED_buffer_overflows")) { // enable debug() calls _debug_enabled = true; @@ -194,7 +196,7 @@ ETS::ETS(int bus, int address) : memset(&_work, 0, sizeof(_work)); } -ETS::~ETS() +ETS_AIRSPEED::~ETS_AIRSPEED() { /* make sure we are truly inactive */ stop(); @@ -205,7 +207,7 @@ ETS::~ETS() } int -ETS::init() +ETS_AIRSPEED::init() { int ret = ERROR; @@ -215,7 +217,7 @@ ETS::init() /* allocate basic report buffers */ _num_reports = 2; - _reports = new struct range_finder_report[_num_reports]; + _reports = new struct airspeed_report[_num_reports]; if (_reports == nullptr) goto out; @@ -224,7 +226,7 @@ ETS::init() /* get a publish handle on the airspeed topic */ memset(&_reports[0], 0, sizeof(_reports[0])); - _differential_pressure_topic = orb_advertise(ORB_ID(_differential_pressure), &_reports[0]); + _differential_pressure_topic = orb_advertise(ORB_ID(sensor_differential_pressure), &_reports[0]); if (_differential_pressure_topic < 0) debug("failed to create airspeed sensor object. Did you start uOrb?"); @@ -237,13 +239,13 @@ out: } int -ETS::probe() +ETS_AIRSPEED::probe() { return measure(); } int -ETS::ioctl(struct file *filp, int cmd, unsigned long arg) +ETS_AIRSPEED::ioctl(struct file *filp, int cmd, unsigned long arg) { switch (cmd) { @@ -270,7 +272,7 @@ ETS::ioctl(struct file *filp, int cmd, unsigned long arg) bool want_start = (_measure_ticks == 0); /* set interval for next measurement to minimum legal value */ - _measure_ticks = USEC2TICK(ETS_CONVERSION_INTERVAL); + _measure_ticks = USEC2TICK(ETS_AIRSPEED_CONVERSION_INTERVAL); /* if we need to start the poll state machine, do it */ if (want_start) @@ -288,7 +290,7 @@ ETS::ioctl(struct file *filp, int cmd, unsigned long arg) unsigned ticks = USEC2TICK(1000000 / arg); /* check against maximum rate */ - if (ticks < USEC2TICK(ETS_CONVERSION_INTERVAL)) + if (ticks < USEC2TICK(ETS_AIRSPEED_CONVERSION_INTERVAL)) return -EINVAL; /* update interval for next measurement */ @@ -318,7 +320,7 @@ ETS::ioctl(struct file *filp, int cmd, unsigned long arg) return -EINVAL; /* allocate new buffer */ - struct range_finder_report *buf = new struct range_finder_report[arg]; + struct airspeed_report *buf = new struct airspeed_report[arg]; if (nullptr == buf) return -ENOMEM; @@ -347,9 +349,9 @@ ETS::ioctl(struct file *filp, int cmd, unsigned long arg) } ssize_t -ETS::read(struct file *filp, char *buffer, size_t buflen) +ETS_AIRSPEED::read(struct file *filp, char *buffer, size_t buflen) { - unsigned count = buflen / sizeof(struct range_finder_report); + unsigned count = buflen / sizeof(struct airspeed_report); int ret = 0; /* buffer must be large enough */ @@ -388,7 +390,7 @@ ETS::read(struct file *filp, char *buffer, size_t buflen) } /* wait for it to complete */ - usleep(ETS_CONVERSION_INTERVAL); + usleep(ETS_AIRSPEED_CONVERSION_INTERVAL); /* run the collection phase */ if (OK != collect()) { @@ -406,14 +408,14 @@ ETS::read(struct file *filp, char *buffer, size_t buflen) } int -ETS::measure() +ETS_AIRSPEED::measure() { int ret; /* * Send the command to begin a measurement. */ - uint8_t cmd = ETS_READ_CMD; + uint8_t cmd = ETS_AIRSPEED_READ_CMD; ret = transfer(&cmd, 1, nullptr, 0); if (OK != ret) @@ -428,7 +430,7 @@ ETS::measure() } int -ETS::collect() +ETS_AIRSPEED::collect() { int ret = -EIO; @@ -449,11 +451,10 @@ ETS::collect() float si_units = (distance * 1.0f)/ 100.0f; /* cm to m */ /* this should be fairly close to the end of the measurement, so the best approximation of the time */ _reports[_next_report].timestamp = hrt_absolute_time(); - _reports[_next_report].distance = si_units; - _reports[_next_report].valid = si_units > get_minimum_distance() && si_units < get_maximum_distance() ? 1 : 0; + _reports[_next_report].speed = si_units; /* publish it */ - orb_publish(ORB_ID(_differential_pressure), _differential_pressure_topic, &_reports[_next_report]); + orb_publish(ORB_ID(sensor_differential_pressure), _differential_pressure_topic, &_reports[_next_report]); /* post a report to the ring - note, not locked */ INCREMENT(_next_report, _num_reports); @@ -477,14 +478,14 @@ out: } void -ETS::start() +ETS_AIRSPEED::start() { /* reset the report ring and state machine */ _collect_phase = false; _oldest_report = _next_report = 0; /* schedule a cycle to start things */ - work_queue(HPWORK, &_work, (worker_t)&ETS::cycle_trampoline, this, 1); + work_queue(HPWORK, &_work, (worker_t)&ETS_AIRSPEED::cycle_trampoline, this, 1); /* notify about state change */ struct subsystem_info_s info = { @@ -502,21 +503,21 @@ ETS::start() } void -ETS::stop() +ETS_AIRSPEED::stop() { work_cancel(HPWORK, &_work); } void -ETS::cycle_trampoline(void *arg) +ETS_AIRSPEED::cycle_trampoline(void *arg) { - ETS *dev = (ETS *)arg; + ETS_AIRSPEED *dev = (ETS_AIRSPEED *)arg; dev->cycle(); } void -ETS::cycle() +ETS_AIRSPEED::cycle() { /* collection phase? */ if (_collect_phase) { @@ -535,14 +536,14 @@ ETS::cycle() /* * Is there a collect->measure gap? */ - if (_measure_ticks > USEC2TICK(ETS_CONVERSION_INTERVAL)) { + if (_measure_ticks > USEC2TICK(ETS_AIRSPEED_CONVERSION_INTERVAL)) { /* schedule a fresh cycle call when we are ready to measure again */ work_queue(HPWORK, &_work, - (worker_t)&ETS::cycle_trampoline, + (worker_t)&ETS_AIRSPEED::cycle_trampoline, this, - _measure_ticks - USEC2TICK(ETS_CONVERSION_INTERVAL)); + _measure_ticks - USEC2TICK(ETS_AIRSPEED_CONVERSION_INTERVAL)); return; } @@ -558,13 +559,13 @@ ETS::cycle() /* schedule a fresh cycle call when the measurement is done */ work_queue(HPWORK, &_work, - (worker_t)&ETS::cycle_trampoline, + (worker_t)&ETS_AIRSPEED::cycle_trampoline, this, - USEC2TICK(ETS_CONVERSION_INTERVAL)); + USEC2TICK(ETS_AIRSPEED_CONVERSION_INTERVAL)); } void -ETS::print_info() +ETS_AIRSPEED::print_info() { perf_print_counter(_sample_perf); perf_print_counter(_comms_errors); @@ -577,7 +578,7 @@ ETS::print_info() /** * Local functions in support of the shell command. */ -namespace ETS +namespace ets_airspeed { /* oddly, ERROR is not defined for c++ */ @@ -586,7 +587,7 @@ namespace ETS #endif const int ERROR = -1; -ETS *g_dev; +ETS_AIRSPEED *g_dev; void start(); void stop(); @@ -606,7 +607,7 @@ start() errx(1, "already started"); /* create the driver */ - g_dev = new ETS(ETS_BUS); + g_dev = new ETS_AIRSPEED(ETS_AIRSPEED_BUS); if (g_dev == nullptr) goto fail; @@ -615,7 +616,7 @@ start() goto fail; /* set the poll rate to default, starts automatic data collection */ - fd = open(AIRSPEED_SENSOR_DEVICE_PATH, O_RDONLY); + fd = open(AIRSPEED_DEVICE_PATH, O_RDONLY); if (fd < 0) goto fail; @@ -661,14 +662,14 @@ void stop() void test() { - struct range_finder_report report; + struct airspeed_report report; ssize_t sz; int ret; - int fd = open(RANGE_FINDER_DEVICE_PATH, O_RDONLY); + int fd = open(AIRSPEED_DEVICE_PATH, O_RDONLY); if (fd < 0) - err(1, "%s open failed (try 'ETS start' if the driver is not running", RANGE_FINDER_DEVICE_PATH); + err(1, "%s open failed (try 'ets_airspeed start' if the driver is not running", AIRSPEED_DEVICE_PATH); /* do a simple demand read */ sz = read(fd, &report, sizeof(report)); @@ -677,7 +678,7 @@ test() err(1, "immediate read failed"); warnx("single read"); - warnx("measurement: %0.2f m", (double)report.distance); + warnx("measurement: %0.2f m", (double)report.speed); warnx("time: %lld", report.timestamp); /* start the sensor polling at 2Hz */ @@ -703,7 +704,7 @@ test() err(1, "periodic read failed"); warnx("periodic read %u", i); - warnx("measurement: %0.3f", (double)report.distance); + warnx("measurement: %0.3f", (double)report.speed); warnx("time: %lld", report.timestamp); } @@ -716,7 +717,7 @@ test() void reset() { - int fd = open(RANGE_FINDER_DEVICE_PATH, O_RDONLY); + int fd = open(AIRSPEED_DEVICE_PATH, O_RDONLY); if (fd < 0) err(1, "failed "); @@ -748,37 +749,37 @@ info() } // namespace int -ETS_main(int argc, char *argv[]) +ets_airspeed_main(int argc, char *argv[]) { /* * Start/load the driver. */ if (!strcmp(argv[1], "start")) - ETS::start(); + ets_airspeed::start(); /* * Stop the driver */ if (!strcmp(argv[1], "stop")) - ETS::stop(); + ets_airspeed::stop(); /* * Test the driver/device. */ if (!strcmp(argv[1], "test")) - ETS::test(); + ets_airspeed::test(); /* * Reset the driver. */ if (!strcmp(argv[1], "reset")) - ETS::reset(); + ets_airspeed::reset(); /* * Print driver information. */ if (!strcmp(argv[1], "info") || !strcmp(argv[1], "status")) - ETS::info(); + ets_airspeed::info(); errx(1, "unrecognized command, try 'start', 'test', 'reset' or 'info'"); } diff --git a/apps/px4io/controls.c b/apps/px4io/controls.c index e80a41f15c..9a0f0e5c1b 100644 --- a/apps/px4io/controls.c +++ b/apps/px4io/controls.c @@ -70,7 +70,7 @@ controls_init(void) unsigned base = PX4IO_P_RC_CONFIG_STRIDE * i; r_page_rc_input_config[base + PX4IO_P_RC_CONFIG_OPTIONS] = 0; - r_page_rc_input_config[base + PX4IO_P_RC_CONFIG_MIN] = 1000; + r_page_rc_input_config[base + PX4IO_P_RC_CONFIG_MIN] = 950; r_page_rc_input_config[base + PX4IO_P_RC_CONFIG_CENTER] = 1500; r_page_rc_input_config[base + PX4IO_P_RC_CONFIG_MAX] = 2000; r_page_rc_input_config[base + PX4IO_P_RC_CONFIG_DEADZONE] = 30; diff --git a/apps/uORB/objects_common.cpp b/apps/uORB/objects_common.cpp index 1363751401..cd21d556c5 100644 --- a/apps/uORB/objects_common.cpp +++ b/apps/uORB/objects_common.cpp @@ -56,6 +56,9 @@ ORB_DEFINE(sensor_baro, struct baro_report); #include ORB_DEFINE(sensor_range_finder, struct range_finder_report); +#include +ORB_DEFINE(sensor_differential_pressure, struct airspeed_report); + #include ORB_DEFINE(output_pwm, struct pwm_output_values); diff --git a/nuttx/configs/px4fmu/nsh/appconfig b/nuttx/configs/px4fmu/nsh/appconfig index 80cf6f312c..b5f35f5140 100644 --- a/nuttx/configs/px4fmu/nsh/appconfig +++ b/nuttx/configs/px4fmu/nsh/appconfig @@ -127,6 +127,7 @@ CONFIGURED_APPS += drivers/px4fmu CONFIGURED_APPS += drivers/hil CONFIGURED_APPS += drivers/gps CONFIGURED_APPS += drivers/mb12xx +CONFIGURED_APPS += drivers/ets_airspeed # Testing stuff CONFIGURED_APPS += px4/sensors_bringup From c8ac1d0b0a97f5fc926a48e64e0e116387453dcd Mon Sep 17 00:00:00 2001 From: Simon Wilks Date: Thu, 11 Apr 2013 08:37:25 +0200 Subject: [PATCH 03/84] Add in the missing header. --- apps/drivers/drv_airspeed.h | 74 +++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 apps/drivers/drv_airspeed.h diff --git a/apps/drivers/drv_airspeed.h b/apps/drivers/drv_airspeed.h new file mode 100644 index 0000000000..a98f568070 --- /dev/null +++ b/apps/drivers/drv_airspeed.h @@ -0,0 +1,74 @@ +/**************************************************************************** + * + * Copyright (C) 2013 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/** + * @file Airspeed driver interface. + */ + +#ifndef _DRV_AIRSPEED_H +#define _DRV_AIRSPEED_H + +#include +#include + +#include "drv_sensor.h" +#include "drv_orb_dev.h" + +#define AIRSPEED_DEVICE_PATH "/dev/airspeed" + +/** + * Airspeed report structure. Reads from the device must be in multiples of this + * structure. + */ +struct airspeed_report { + uint64_t timestamp; + uint8_t speed; /** in meters/sec */ +}; + +/* + * ObjDev tag for raw range finder data. + */ +ORB_DECLARE(sensor_differential_pressure); + +/* + * ioctl() definitions + * + * Airspeed drivers also implement the generic sensor driver + * interfaces from drv_sensor.h + */ + +#define _AIRSPEEDIOCBASE (0x7700) +#define __AIRSPEEDIOC(_n) (_IOC(_AIRSPEEDIOCBASE, _n)) + + +#endif /* _DRV_AIRSPEED_H */ From 42f4a9e8800c4d5d2823b4f477c556547fe0d3d0 Mon Sep 17 00:00:00 2001 From: Simon Wilks Date: Sat, 13 Apr 2013 08:47:12 +0200 Subject: [PATCH 04/84] Switch to differential pressure topic --- apps/drivers/drv_airspeed.h | 14 +- apps/drivers/ets_airspeed/ets_airspeed.cpp | 150 ++++++++++++++------- apps/systemlib/airspeed.c | 2 +- apps/uORB/objects_common.cpp | 3 - 4 files changed, 110 insertions(+), 59 deletions(-) diff --git a/apps/drivers/drv_airspeed.h b/apps/drivers/drv_airspeed.h index a98f568070..269ee45591 100644 --- a/apps/drivers/drv_airspeed.h +++ b/apps/drivers/drv_airspeed.h @@ -47,18 +47,18 @@ #define AIRSPEED_DEVICE_PATH "/dev/airspeed" /** - * Airspeed report structure. Reads from the device must be in multiples of this + * Airspeed report structure. Reads from the device must be in multiples of this * structure. */ -struct airspeed_report { - uint64_t timestamp; - uint8_t speed; /** in meters/sec */ -}; +//struct airspeed_report { +// uint64_t timestamp; +// uint8_t diff_pressure; /** differential pressure in Pa */ +//}; /* * ObjDev tag for raw range finder data. */ -ORB_DECLARE(sensor_differential_pressure); +//ORB_DECLARE(sensor_differential_pressure); /* * ioctl() definitions @@ -67,7 +67,7 @@ ORB_DECLARE(sensor_differential_pressure); * interfaces from drv_sensor.h */ -#define _AIRSPEEDIOCBASE (0x7700) +#define _AIRSPEEDIOCBASE (0x7700) #define __AIRSPEEDIOC(_n) (_IOC(_AIRSPEEDIOCBASE, _n)) diff --git a/apps/drivers/ets_airspeed/ets_airspeed.cpp b/apps/drivers/ets_airspeed/ets_airspeed.cpp index 790e949e0f..0b535b0b5f 100644 --- a/apps/drivers/ets_airspeed/ets_airspeed.cpp +++ b/apps/drivers/ets_airspeed/ets_airspeed.cpp @@ -63,24 +63,28 @@ #include #include +#include -#include #include +#include #include +#include +#include /* for baro readings */ #include - /* Configuration Constants */ -#define ETS_AIRSPEED_BUS PX4_I2C_BUS_ESC -#define ETS_AIRSPEED_ADDRESS 0x75 +#define I2C_BUS PX4_I2C_BUS_ESC +#define I2C_ADDRESS 0x75 /* ETS_AIRSPEED Registers addresses */ - -#define ETS_AIRSPEED_READ_CMD 0x07 /* Read the data */ +#define READ_CMD 0x07 /* Read the data */ /* Max measurement rate is 100Hz */ -#define ETS_AIRSPEED_CONVERSION_INTERVAL (1000000 / 100) /* microseconds */ +#define CONVERSION_INTERVAL (1000000 / 10) /* microseconds */ + +#define DIFF_PRESSURE_SCALE 1.0 +#define DIFF_PRESSURE_OFFSET 1673 /* oddly, ERROR is not defined for c++ */ #ifdef ERROR @@ -92,10 +96,13 @@ static const int ERROR = -1; # error This requires CONFIG_SCHED_WORKQUEUE. #endif +static int _sensor_sub = -1; + + class ETS_AIRSPEED : public device::I2C { public: - ETS_AIRSPEED(int bus = ETS_AIRSPEED_BUS, int address = ETS_AIRSPEED_ADDRESS); + ETS_AIRSPEED(int bus = I2C_BUS, int address = I2C_ADDRESS); virtual ~ETS_AIRSPEED(); virtual int init(); @@ -112,20 +119,21 @@ protected: virtual int probe(); private: - work_s _work; - unsigned _num_reports; - volatile unsigned _next_report; - volatile unsigned _oldest_report; - airspeed_report *_reports; - bool _sensor_ok; - int _measure_ticks; - bool _collect_phase; + work_s _work; + unsigned _num_reports; + volatile unsigned _next_report; + volatile unsigned _oldest_report; + differential_pressure_s *_reports; + bool _sensor_ok; + int _measure_ticks; + bool _collect_phase; - orb_advert_t _differential_pressure_topic; + orb_advert_t _airspeed_pub; + + perf_counter_t _sample_perf; + perf_counter_t _comms_errors; + perf_counter_t _buffer_overflows; - perf_counter_t _sample_perf; - perf_counter_t _comms_errors; - perf_counter_t _buffer_overflows; /** * Test whether the device supported by the driver is present at a @@ -184,7 +192,7 @@ ETS_AIRSPEED::ETS_AIRSPEED(int bus, int address) : _sensor_ok(false), _measure_ticks(0), _collect_phase(false), - _differential_pressure_topic(-1), + _airspeed_pub(-1), _sample_perf(perf_alloc(PC_ELAPSED, "ETS_AIRSPEED_read")), _comms_errors(perf_alloc(PC_COUNT, "ETS_AIRSPEED_comms_errors")), _buffer_overflows(perf_alloc(PC_COUNT, "ETS_AIRSPEED_buffer_overflows")) @@ -217,7 +225,7 @@ ETS_AIRSPEED::init() /* allocate basic report buffers */ _num_reports = 2; - _reports = new struct airspeed_report[_num_reports]; + _reports = new struct differential_pressure_s[_num_reports]; if (_reports == nullptr) goto out; @@ -226,11 +234,18 @@ ETS_AIRSPEED::init() /* get a publish handle on the airspeed topic */ memset(&_reports[0], 0, sizeof(_reports[0])); - _differential_pressure_topic = orb_advertise(ORB_ID(sensor_differential_pressure), &_reports[0]); + _airspeed_pub = orb_advertise(ORB_ID(differential_pressure), &_reports[0]); - if (_differential_pressure_topic < 0) + if (_airspeed_pub < 0) debug("failed to create airspeed sensor object. Did you start uOrb?"); + _sensor_sub = orb_subscribe(ORB_ID(sensor_combined)); + + if (_sensor_sub < 0) { + debug("failed to subscribe to sensor_combined object."); + return ret; + } + ret = OK; /* sensor is ok, but we don't really know if it is within range */ _sensor_ok = true; @@ -272,7 +287,7 @@ ETS_AIRSPEED::ioctl(struct file *filp, int cmd, unsigned long arg) bool want_start = (_measure_ticks == 0); /* set interval for next measurement to minimum legal value */ - _measure_ticks = USEC2TICK(ETS_AIRSPEED_CONVERSION_INTERVAL); + _measure_ticks = USEC2TICK(CONVERSION_INTERVAL); /* if we need to start the poll state machine, do it */ if (want_start) @@ -290,7 +305,7 @@ ETS_AIRSPEED::ioctl(struct file *filp, int cmd, unsigned long arg) unsigned ticks = USEC2TICK(1000000 / arg); /* check against maximum rate */ - if (ticks < USEC2TICK(ETS_AIRSPEED_CONVERSION_INTERVAL)) + if (ticks < USEC2TICK(CONVERSION_INTERVAL)) return -EINVAL; /* update interval for next measurement */ @@ -320,7 +335,7 @@ ETS_AIRSPEED::ioctl(struct file *filp, int cmd, unsigned long arg) return -EINVAL; /* allocate new buffer */ - struct airspeed_report *buf = new struct airspeed_report[arg]; + struct differential_pressure_s *buf = new struct differential_pressure_s[arg]; if (nullptr == buf) return -ENOMEM; @@ -351,7 +366,7 @@ ETS_AIRSPEED::ioctl(struct file *filp, int cmd, unsigned long arg) ssize_t ETS_AIRSPEED::read(struct file *filp, char *buffer, size_t buflen) { - unsigned count = buflen / sizeof(struct airspeed_report); + unsigned count = buflen / sizeof(struct differential_pressure_s); int ret = 0; /* buffer must be large enough */ @@ -390,7 +405,7 @@ ETS_AIRSPEED::read(struct file *filp, char *buffer, size_t buflen) } /* wait for it to complete */ - usleep(ETS_AIRSPEED_CONVERSION_INTERVAL); + usleep(CONVERSION_INTERVAL); /* run the collection phase */ if (OK != collect()) { @@ -415,7 +430,7 @@ ETS_AIRSPEED::measure() /* * Send the command to begin a measurement. */ - uint8_t cmd = ETS_AIRSPEED_READ_CMD; + uint8_t cmd = READ_CMD; ret = transfer(&cmd, 1, nullptr, 0); if (OK != ret) @@ -441,20 +456,48 @@ ETS_AIRSPEED::collect() ret = transfer(nullptr, 0, &val[0], 2); - if (ret < 0) - { + if (ret < 0) { log("error reading from sensor: %d", ret); return ret; } - uint16_t distance = val[0] << 8 | val[1]; - float si_units = (distance * 1.0f)/ 100.0f; /* cm to m */ - /* this should be fairly close to the end of the measurement, so the best approximation of the time */ - _reports[_next_report].timestamp = hrt_absolute_time(); - _reports[_next_report].speed = si_units; + uint16_t diff_pres_pa = val[1] << 8 | val[0]; + //log("val: %0.3f", (float)(diff_pressure)); + + /* adjust if necessary */ + diff_pres_pa = DIFF_PRESSURE_SCALE * (diff_pres_pa - DIFF_PRESSURE_OFFSET); + //log("measurement: %0.2f m/s", calc_indicated_airspeed((float)_reports[_next_report].diff_pressure)); + + struct sensor_combined_s raw; + memset(&raw, 0, sizeof(raw)); + + bool updated; + orb_check(_sensor_sub, &updated); + if (updated) { + orb_copy(ORB_ID(sensor_combined), _sensor_sub, &raw); + printf("baro temp %3.6f\n", raw.baro_pres_mbar); + } + unlock(); + //if (raw.baro_temp_celcius > 0) + // log("baro temp %3.3f\n", (uint8_t) raw.baro_temp_celcius); + + float airspeed_true = calc_true_airspeed(diff_pres_pa + raw.baro_pres_mbar*1e2f, + raw.baro_pres_mbar*1e2f, raw.baro_temp_celcius - 5.0f); //factor 1e2 for conversion from mBar to Pa + // XXX HACK - true temperature is much less than indicated temperature in baro, + // subtract 5 degrees in an attempt to account for the electrical upheating of the PCB + + float airspeed_indicated = calc_indicated_airspeed(diff_pres_pa); - /* publish it */ - orb_publish(ORB_ID(sensor_differential_pressure), _differential_pressure_topic, &_reports[_next_report]); + _reports[_next_report].timestamp = hrt_absolute_time(); + _reports[_next_report].static_pressure_mbar = raw.baro_pres_mbar; + _reports[_next_report].differential_pressure_mbar = diff_pres_pa * 1e-2f; + _reports[_next_report].temperature_celcius = raw.baro_temp_celcius; + _reports[_next_report].indicated_airspeed_m_s = airspeed_indicated; + _reports[_next_report].true_airspeed_m_s = airspeed_true; + _reports[_next_report].voltage = 0; + + /* announce the airspeed if needed, just publish else */ + orb_publish(ORB_ID(differential_pressure), _airspeed_pub, &_reports[_next_report]); /* post a report to the ring - note, not locked */ INCREMENT(_next_report, _num_reports); @@ -472,7 +515,6 @@ ETS_AIRSPEED::collect() out: perf_end(_sample_perf); - return ret; return ret; } @@ -536,14 +578,14 @@ ETS_AIRSPEED::cycle() /* * Is there a collect->measure gap? */ - if (_measure_ticks > USEC2TICK(ETS_AIRSPEED_CONVERSION_INTERVAL)) { + if (_measure_ticks > USEC2TICK(CONVERSION_INTERVAL)) { /* schedule a fresh cycle call when we are ready to measure again */ work_queue(HPWORK, &_work, (worker_t)&ETS_AIRSPEED::cycle_trampoline, this, - _measure_ticks - USEC2TICK(ETS_AIRSPEED_CONVERSION_INTERVAL)); + _measure_ticks - USEC2TICK(CONVERSION_INTERVAL)); return; } @@ -561,7 +603,7 @@ ETS_AIRSPEED::cycle() &_work, (worker_t)&ETS_AIRSPEED::cycle_trampoline, this, - USEC2TICK(ETS_AIRSPEED_CONVERSION_INTERVAL)); + USEC2TICK(CONVERSION_INTERVAL)); } void @@ -607,7 +649,7 @@ start() errx(1, "already started"); /* create the driver */ - g_dev = new ETS_AIRSPEED(ETS_AIRSPEED_BUS); + g_dev = new ETS_AIRSPEED(I2C_BUS); if (g_dev == nullptr) goto fail; @@ -662,7 +704,7 @@ void stop() void test() { - struct airspeed_report report; + struct differential_pressure_s report; ssize_t sz; int ret; @@ -678,7 +720,18 @@ test() err(1, "immediate read failed"); warnx("single read"); - warnx("measurement: %0.2f m", (double)report.speed); + warnx("diff pressure: %0.3f mbar", report.differential_pressure_mbar); + warnx("indicated airspeed: %0.1f m/s", report.indicated_airspeed_m_s); + warnx("true airspeed: %0.1f m/s", report.true_airspeed_m_s); + + struct sensor_combined_s raw; + memset(&raw, 0, sizeof(raw)); + int sensor_sub = orb_subscribe(ORB_ID(sensor_combined)); + orb_copy(ORB_ID(sensor_combined), sensor_sub, &raw); + + //if (raw.baro_temp_celcius > 0) + // log("baro temp %3.3f\n", (uint8_t) raw.baro_temp_celcius); + warnx("temp: %3.5f", raw.baro_temp_celcius); warnx("time: %lld", report.timestamp); /* start the sensor polling at 2Hz */ @@ -704,8 +757,9 @@ test() err(1, "periodic read failed"); warnx("periodic read %u", i); - warnx("measurement: %0.3f", (double)report.speed); - warnx("time: %lld", report.timestamp); + warnx("diff pressure: %0.3f mbar", report.differential_pressure_mbar); + warnx("indicated airspeed: %0.1f m/s", report.indicated_airspeed_m_s); + warnx("true airspeed: %0.1f m/s", report.true_airspeed_m_s); warnx("time: %lld", report.timestamp); } errx(0, "PASS"); diff --git a/apps/systemlib/airspeed.c b/apps/systemlib/airspeed.c index 264287b10f..15bb833a99 100644 --- a/apps/systemlib/airspeed.c +++ b/apps/systemlib/airspeed.c @@ -97,7 +97,7 @@ float calc_true_airspeed(float total_pressure, float static_pressure, float temp float density = get_air_density(static_pressure, temperature_celsius); if (density < 0.0001f || !isfinite(density)) { density = CONSTANTS_AIR_DENSITY_SEA_LEVEL_15C; - printf("[airspeed] Invalid air density, using density at sea level\n"); +// printf("[airspeed] Invalid air density, using density at sea level\n"); } float pressure_difference = total_pressure - static_pressure; diff --git a/apps/uORB/objects_common.cpp b/apps/uORB/objects_common.cpp index cd21d556c5..1363751401 100644 --- a/apps/uORB/objects_common.cpp +++ b/apps/uORB/objects_common.cpp @@ -56,9 +56,6 @@ ORB_DEFINE(sensor_baro, struct baro_report); #include ORB_DEFINE(sensor_range_finder, struct range_finder_report); -#include -ORB_DEFINE(sensor_differential_pressure, struct airspeed_report); - #include ORB_DEFINE(output_pwm, struct pwm_output_values); From c5a453cd18949d2d4673c0b343e22c22a8d2854d Mon Sep 17 00:00:00 2001 From: Simon Wilks Date: Sat, 13 Apr 2013 09:09:21 +0200 Subject: [PATCH 05/84] Remove some testing code. --- apps/drivers/ets_airspeed/ets_airspeed.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/drivers/ets_airspeed/ets_airspeed.cpp b/apps/drivers/ets_airspeed/ets_airspeed.cpp index 0b535b0b5f..58d016a307 100644 --- a/apps/drivers/ets_airspeed/ets_airspeed.cpp +++ b/apps/drivers/ets_airspeed/ets_airspeed.cpp @@ -477,7 +477,6 @@ ETS_AIRSPEED::collect() orb_copy(ORB_ID(sensor_combined), _sensor_sub, &raw); printf("baro temp %3.6f\n", raw.baro_pres_mbar); } - unlock(); //if (raw.baro_temp_celcius > 0) // log("baro temp %3.3f\n", (uint8_t) raw.baro_temp_celcius); From 59573e5b69f9afc5dbe00bc165ae8e1f4d457f89 Mon Sep 17 00:00:00 2001 From: marco Date: Wed, 17 Apr 2013 19:46:01 +0200 Subject: [PATCH 06/84] BLCtrl 2.0 testing - currently only 8 Bit resolution - this should fly --- apps/drivers/mkblctrl/Makefile | 44 + apps/drivers/mkblctrl/mkblctrl.cpp | 1403 ++++++++++++++++++++++++++++ nuttx/configs/px4fmu/nsh/appconfig | 1 + 3 files changed, 1448 insertions(+) create mode 100644 apps/drivers/mkblctrl/Makefile create mode 100644 apps/drivers/mkblctrl/mkblctrl.cpp diff --git a/apps/drivers/mkblctrl/Makefile b/apps/drivers/mkblctrl/Makefile new file mode 100644 index 0000000000..b3be2c4687 --- /dev/null +++ b/apps/drivers/mkblctrl/Makefile @@ -0,0 +1,44 @@ +############################################################################ +# +# Copyright (C) 2012 PX4 Development Team. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name PX4 nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +# +# Interface driver for the Mikrokopter BLCtrl +# + +APPNAME = mkblctrl +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 2048 + +INCLUDES = $(TOPDIR)/arch/arm/src/stm32 $(TOPDIR)/arch/arm/src/common + +include $(APPDIR)/mk/app.mk diff --git a/apps/drivers/mkblctrl/mkblctrl.cpp b/apps/drivers/mkblctrl/mkblctrl.cpp new file mode 100644 index 0000000000..c14fdfd1d8 --- /dev/null +++ b/apps/drivers/mkblctrl/mkblctrl.cpp @@ -0,0 +1,1403 @@ +/**************************************************************************** + * + * Copyright (C) 2012 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/** + * @file mkblctrl.cpp + * + * Driver/configurator for the Mikrokopter BL-Ctrl. + * Marco Bauer + * + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define I2C_BUS_SPEED 400000 +#define UPDATE_RATE 400 +#define MAX_MOTORS 8 +#define BLCTRL_BASE_ADDR 0x29 +#define BLCTRL_OLD 0 +#define BLCTRL_NEW 1 +#define BLCTRL_MIN_VALUE -0.984F +#define MOTOR_STATE_PRESENT_MASK 0x80 +#define MOTOR_STATE_ERROR_MASK 0x7F +#define MOTOR_SPINUP_COUNTER 2500 + + +class MK : public device::I2C +{ +public: + enum Mode { + MODE_2PWM, + MODE_4PWM, + MODE_NONE + }; + + enum MappingMode { + MAPPING_MK = 0, + MAPPING_PX4, + }; + + enum FrameType { + FRAME_PLUS = 0, + FRAME_X, + }; + + MK(int bus); + ~MK(); + + virtual int ioctl(file *filp, int cmd, unsigned long arg); + virtual int init(unsigned motors); + + int set_mode(Mode mode); + int set_pwm_rate(unsigned rate); + int set_motor_count(unsigned count); + int set_motor_test(bool motortest); + int set_px4mode(int px4mode); + int set_frametype(int frametype); + +private: + static const unsigned _max_actuators = MAX_MOTORS; + static const bool showDebug = false; + + Mode _mode; + int _update_rate; + int _current_update_rate; + int _task; + int _t_actuators; + int _t_armed; + unsigned int _motor; + int _px4mode; + int _frametype; + orb_advert_t _t_outputs; + orb_advert_t _t_actuators_effective; + unsigned int _num_outputs; + bool _primary_pwm_device; + bool _motortest; + + volatile bool _task_should_exit; + bool _armed; + + unsigned long debugCounter; + + MixerGroup *_mixers; + + actuator_controls_s _controls; + + static void task_main_trampoline(int argc, char *argv[]); + void task_main() __attribute__((noreturn)); + + static int control_callback(uintptr_t handle, + uint8_t control_group, + uint8_t control_index, + float &input); + + int pwm_ioctl(file *filp, int cmd, unsigned long arg); + + struct GPIOConfig { + uint32_t input; + uint32_t output; + uint32_t alt; + }; + + static const GPIOConfig _gpio_tab[]; + static const unsigned _ngpio; + + void gpio_reset(void); + void gpio_set_function(uint32_t gpios, int function); + void gpio_write(uint32_t gpios, int function); + uint32_t gpio_read(void); + int gpio_ioctl(file *filp, int cmd, unsigned long arg); + int mk_servo_arm(bool status); + + int mk_check_for_blctrl(unsigned int count); + int mk_servo_set(unsigned int chan, float val); + int mk_servo_set_test(unsigned int chan, float val); + int mk_servo_test(unsigned int chan); + + +}; + +const MK::GPIOConfig MK::_gpio_tab[] = { + {GPIO_GPIO0_INPUT, GPIO_GPIO0_OUTPUT, 0}, + {GPIO_GPIO1_INPUT, GPIO_GPIO1_OUTPUT, 0}, + {GPIO_GPIO2_INPUT, GPIO_GPIO2_OUTPUT, GPIO_USART2_CTS_1}, + {GPIO_GPIO3_INPUT, GPIO_GPIO3_OUTPUT, GPIO_USART2_RTS_1}, + {GPIO_GPIO4_INPUT, GPIO_GPIO4_OUTPUT, GPIO_USART2_TX_1}, + {GPIO_GPIO5_INPUT, GPIO_GPIO5_OUTPUT, GPIO_USART2_RX_1}, + {GPIO_GPIO6_INPUT, GPIO_GPIO6_OUTPUT, GPIO_CAN2_TX_2}, + {GPIO_GPIO7_INPUT, GPIO_GPIO7_OUTPUT, GPIO_CAN2_RX_2}, +}; + +const unsigned MK::_ngpio = sizeof(MK::_gpio_tab) / sizeof(MK::_gpio_tab[0]); + +const int blctrlAddr_quad_plus[] = { 2, 2, -2, -2, 0, 0, 0, 0 }; // Addresstranslator for Quad + configuration +const int blctrlAddr_hexa_plus[] = { 0, 2, 2, -2, 1, -3, 0, 0 }; // Addresstranslator for Hexa + configuration +const int blctrlAddr_octo_plus[] = { 0, 3, -1, 0, 3, 0, 0, -5 }; // Addresstranslator for Octo + configuration + +const int blctrlAddr_quad_x[] = { 2, 2, -2, -2, 0, 0, 0, 0 }; // Addresstranslator for Quad X configuration +const int blctrlAddr_hexa_x[] = { 2, 4, -2, 0, -3, -1, 0, 0 }; // Addresstranslator for Hexa X configuration +const int blctrlAddr_octo_x[] = { 1, 4, 0, 1, -4, 1, 1, -4 }; // Addresstranslator for Octo X configuration + +const int blctrlAddr_px4[] = { 0, 0, 0, 0, 0, 0, 0, 0}; + +int addrTranslator[] = {0,0,0,0,0,0,0,0}; + +struct MotorData_t +{ + unsigned int Version; // the version of the BL (0 = old) + unsigned int SetPoint; // written by attitude controller + unsigned int SetPointLowerBits; // for higher Resolution of new BLs + unsigned int State; // 7 bit for I2C error counter, highest bit indicates if motor is present + unsigned int ReadMode; // select data to read + // the following bytes must be exactly in that order! + unsigned int Current; // in 0.1 A steps, read back from BL + unsigned int MaxPWM; // read back from BL is less than 255 if BL is in current limit + unsigned int Temperature; // old BL-Ctrl will return a 255 here, the new version the temp. in °C + unsigned int RoundCount; +}; + +MotorData_t Motor[MAX_MOTORS]; + + +namespace +{ + +MK *g_mk; + +} // namespace + +MK::MK(int bus) : + I2C("mkblctrl", "/dev/mkblctrl", bus, 0, I2C_BUS_SPEED), + _mode(MODE_NONE), + _update_rate(50), + _task(-1), + _t_actuators(-1), + _t_armed(-1), + _t_outputs(0), + _t_actuators_effective(0), + _num_outputs(0), + _motortest(false), + _motor(-1), + _px4mode(MAPPING_MK), + _frametype(FRAME_PLUS), + _primary_pwm_device(false), + _task_should_exit(false), + _armed(false), + _mixers(nullptr) +{ + _debug_enabled = true; +} + +MK::~MK() +{ + if (_task != -1) { + /* tell the task we want it to go away */ + _task_should_exit = true; + + unsigned i = 10; + + do { + /* wait 50ms - it should wake every 100ms or so worst-case */ + usleep(50000); + + /* if we have given up, kill it */ + if (--i == 0) { + task_delete(_task); + break; + } + + } while (_task != -1); + } + + /* clean up the alternate device node */ + if (_primary_pwm_device) + unregister_driver(PWM_OUTPUT_DEVICE_PATH); + + g_mk = nullptr; +} + +int +MK::init(unsigned motors) +{ + _num_outputs = motors; + debugCounter = 0; + int ret; + ASSERT(_task == -1); + + ret = I2C::init(); + + if (ret != OK) { + warnx("I2C init failed"); + return ret; + } + + usleep(500000); + + /* try to claim the generic PWM output device node as well - it's OK if we fail at this */ + ret = register_driver(PWM_OUTPUT_DEVICE_PATH, &fops, 0666, (void *)this); + + if (ret == OK) { + log("default PWM output device"); + _primary_pwm_device = true; + } + + /* reset GPIOs */ + gpio_reset(); + + /* check for connected blctrls */ + //mk_check_for_blctrl(_num_outputs); + + /* start the IO interface task */ + _task = task_spawn("mkblctrl", + SCHED_DEFAULT, + SCHED_PRIORITY_MAX -20, + 2048, + (main_t)&MK::task_main_trampoline, + nullptr); + + + if (_task < 0) { + debug("task start failed: %d", errno); + return -errno; + } + + return OK; +} + +void +MK::task_main_trampoline(int argc, char *argv[]) +{ + g_mk->task_main(); +} + +int +MK::set_mode(Mode mode) +{ + /* + * Configure for PWM output. + * + * Note that regardless of the configured mode, the task is always + * listening and mixing; the mode just selects which of the channels + * are presented on the output pins. + */ + switch (mode) { + case MODE_2PWM: + if(_num_outputs == 4) { + debug("MODE_QUAD"); + } else if(_num_outputs == 6) { + debug("MODE_HEXA"); + } else if(_num_outputs == 8) { + debug("MODE_OCTO"); + } + //up_pwm_servo_init(0x3); + up_pwm_servo_deinit(); + _update_rate = UPDATE_RATE; /* default output rate */ + break; + + case MODE_4PWM: + if(_num_outputs == 4) { + debug("MODE_QUADRO"); + } else if(_num_outputs == 6) { + debug("MODE_HEXA"); + } else if(_num_outputs == 8) { + debug("MODE_OCTO"); + } + //up_pwm_servo_init(0xf); + up_pwm_servo_deinit(); + _update_rate = UPDATE_RATE; /* default output rate */ + break; + + case MODE_NONE: + debug("MODE_NONE"); + /* disable servo outputs and set a very low update rate */ + up_pwm_servo_deinit(); + _update_rate = UPDATE_RATE; + break; + + default: + return -EINVAL; + } + + _mode = mode; + return OK; +} + +int +MK::set_pwm_rate(unsigned rate) +{ + if ((rate > 500) || (rate < 10)) + return -EINVAL; + + _update_rate = rate; + return OK; +} + +int +MK::set_px4mode(int px4mode) +{ + _px4mode = px4mode; +} + +int +MK::set_frametype(int frametype) +{ + _frametype = frametype; +} + + +int +MK::set_motor_count(unsigned count) +{ + _num_outputs = count; + + if(_px4mode == MAPPING_MK) { + if(_frametype == FRAME_PLUS) { + fprintf(stderr, "[mkblctrl] addresstanslator for Mikrokopter addressing used. Frametype: +\n"); + } else if(_frametype == FRAME_X) { + fprintf(stderr, "[mkblctrl] addresstanslator for Mikrokopter addressing used. Frametype: X\n"); + } + if(_num_outputs == 4) { + if(_frametype == FRAME_PLUS) { + memcpy(&addrTranslator, &blctrlAddr_quad_plus, sizeof(blctrlAddr_quad_plus)); + } else if(_frametype == FRAME_X) { + memcpy(&addrTranslator, &blctrlAddr_quad_x, sizeof(blctrlAddr_quad_x)); + } + } else if(_num_outputs == 6) { + if(_frametype == FRAME_PLUS) { + memcpy(&addrTranslator, &blctrlAddr_hexa_plus, sizeof(blctrlAddr_hexa_plus)); + } else if(_frametype == FRAME_X) { + memcpy(&addrTranslator, &blctrlAddr_hexa_x, sizeof(blctrlAddr_hexa_x)); + } + } else if(_num_outputs == 8) { + if(_frametype == FRAME_PLUS) { + memcpy(&addrTranslator, &blctrlAddr_octo_plus, sizeof(blctrlAddr_octo_plus)); + } else if(_frametype == FRAME_X) { + memcpy(&addrTranslator, &blctrlAddr_octo_x, sizeof(blctrlAddr_octo_x)); + } + } + } else { + fprintf(stderr, "[mkblctrl] PX4 native addressing used.\n"); + memcpy(&addrTranslator, &blctrlAddr_px4, sizeof(blctrlAddr_px4)); + } + + /* check for connected blctrls */ + mk_check_for_blctrl(_num_outputs); + + return OK; +} + +int +MK::set_motor_test(bool motortest) +{ + _motortest = motortest; + return OK; +} + + +void +MK::task_main() +{ + /* + * Subscribe to the appropriate PWM output topic based on whether we are the + * primary PWM output or not. + */ + _t_actuators = orb_subscribe(_primary_pwm_device ? ORB_ID_VEHICLE_ATTITUDE_CONTROLS : + ORB_ID(actuator_controls_1)); + /* force a reset of the update rate */ + _current_update_rate = 0; + + _t_armed = orb_subscribe(ORB_ID(actuator_armed)); + orb_set_interval(_t_armed, 200); /* 5Hz update rate */ + + /* advertise the mixed control outputs */ + actuator_outputs_s outputs; + memset(&outputs, 0, sizeof(outputs)); + /* advertise the mixed control outputs */ + _t_outputs = orb_advertise(_primary_pwm_device ? ORB_ID_VEHICLE_CONTROLS : ORB_ID(actuator_outputs_1), + &outputs); + + /* advertise the effective control inputs */ + actuator_controls_effective_s controls_effective; + memset(&controls_effective, 0, sizeof(controls_effective)); + /* advertise the effective control inputs */ + _t_actuators_effective = orb_advertise(_primary_pwm_device ? ORB_ID_VEHICLE_ATTITUDE_CONTROLS_EFFECTIVE : ORB_ID(actuator_controls_effective_1), + &controls_effective); + + pollfd fds[2]; + fds[0].fd = _t_actuators; + fds[0].events = POLLIN; + fds[1].fd = _t_armed; + fds[1].events = POLLIN; + + log("starting"); + long update_rate_in_us = 0; + + /* loop until killed */ + while (!_task_should_exit) { + + /* handle update rate changes */ + if (_current_update_rate != _update_rate) { + int update_rate_in_ms = int(1000 / _update_rate); + update_rate_in_us = long(1000000 / _update_rate); + + /* reject faster than 500 Hz updates */ + if (update_rate_in_ms < 2) { + update_rate_in_ms = 2; + _update_rate = 500; + } + /* reject slower than 50 Hz updates */ + if (update_rate_in_ms > 20) { + update_rate_in_ms = 20; + _update_rate = 50; + } + + orb_set_interval(_t_actuators, update_rate_in_ms); + up_pwm_servo_set_rate(_update_rate); + _current_update_rate = _update_rate; + } + + /* sleep waiting for data, but no more than a second */ + int ret = ::poll(&fds[0], 2, 1000); + + /* this would be bad... */ + if (ret < 0) { + log("poll error %d", errno); + usleep(1000000); + continue; + } + + /* do we have a control update? */ + if (fds[0].revents & POLLIN) { + + /* get controls - must always do this to avoid spinning */ + orb_copy(_primary_pwm_device ? ORB_ID_VEHICLE_ATTITUDE_CONTROLS : ORB_ID(actuator_controls_1), _t_actuators, &_controls); + + /* can we mix? */ + if (_mixers != nullptr) { + + /* do mixing */ + outputs.noutputs = _mixers->mix(&outputs.output[0], _num_outputs); + outputs.timestamp = hrt_absolute_time(); + + // XXX output actual limited values + memcpy(&controls_effective, &_controls, sizeof(controls_effective)); + + orb_publish(_primary_pwm_device ? ORB_ID_VEHICLE_ATTITUDE_CONTROLS_EFFECTIVE : ORB_ID(actuator_controls_effective_1), _t_actuators_effective, &controls_effective); + + /* iterate actuators */ + for (unsigned int i = 0; i < _num_outputs; i++) { + + /* last resort: catch NaN, INF and out-of-band errors */ + if (i < outputs.noutputs && + isfinite(outputs.output[i]) && + outputs.output[i] >= -1.0f && + outputs.output[i] <= 1.0f) { + /* scale for PWM output 900 - 2100us */ + //outputs.output[i] = 1500 + (600 * outputs.output[i]); + //outputs.output[i] = 127 + (127 * outputs.output[i]); + } else { + /* + * Value is NaN, INF or out of band - set to the minimum value. + * This will be clearly visible on the servo status and will limit the risk of accidentally + * spinning motors. It would be deadly in flight. + */ + if(outputs.output[i] < -1.0f) { + outputs.output[i] = -1.0f; + } else if(outputs.output[i] > 1.0f) { + outputs.output[i] = 1.0f; + } else { + outputs.output[i] = -1.0f; + } + } + + /* don't go under BLCTRL_MIN_VALUE */ + if(outputs.output[i] < BLCTRL_MIN_VALUE) { + outputs.output[i] = BLCTRL_MIN_VALUE; + } + //_motortest = true; + /* output to BLCtrl's */ + if(_motortest == true) { + mk_servo_test(i); + } else { + //mk_servo_set(i, outputs.output[i]); + mk_servo_set_test(i, outputs.output[i]); // 8Bit + } + + + } + + /* and publish for anyone that cares to see */ + orb_publish(_primary_pwm_device ? ORB_ID_VEHICLE_CONTROLS : ORB_ID(actuator_outputs_1), _t_outputs, &outputs); + } + } + + /* how about an arming update? */ + if (fds[1].revents & POLLIN) { + actuator_armed_s aa; + + /* get new value */ + orb_copy(ORB_ID(actuator_armed), _t_armed, &aa); + + /* update PWM servo armed status if armed and not locked down */ + ////up_pwm_servo_arm(aa.armed && !aa.lockdown); + mk_servo_arm(aa.armed && !aa.lockdown); + } + } + + ::close(_t_actuators); + ::close(_t_actuators_effective); + ::close(_t_armed); + + + /* make sure servos are off */ + up_pwm_servo_deinit(); + + log("stopping"); + + /* note - someone else is responsible for restoring the GPIO config */ + + /* tell the dtor that we are exiting */ + _task = -1; + _exit(0); +} + + +int +MK::mk_servo_arm(bool status) +{ + _armed = status; + return 0; +} + + +int +MK::mk_check_for_blctrl(unsigned int count) +{ + _retries = 10; + uint8_t foundMotorCount = 0; + + for(unsigned i=0; i 2047) { + tmpVal = 2047; + } + + + Motor[chan].SetPoint = (uint8_t) tmpVal / 3; // divide 8 + Motor[chan].SetPointLowerBits = (uint8_t) tmpVal % 8; // rest of divide 8 + //rod = (uint8_t) tmpVal % 8; + //Motor[chan].SetPointLowerBits = rod<<1; // rest of divide 8 + Motor[chan].SetPointLowerBits = 0; + + if(_armed == false) { + Motor[chan].SetPoint = 0; + Motor[chan].SetPointLowerBits = 0; + } + + //if(Motor[chan].State & MOTOR_STATE_PRESENT_MASK) { + set_address(BLCTRL_BASE_ADDR + (chan + addrTranslator[chan])); + + if(Motor[chan].Version == BLCTRL_OLD) { + /* + * Old BL-Ctrl 8Bit served. Version < 2.0 + */ + msg[0] = Motor[chan].SetPoint; + if(Motor[chan].RoundCount >= 16) { + // on each 16th cyle we read out the status messages from the blctrl + if (OK == transfer(&msg[0], 1, &result[0], 2)) { + Motor[chan].Current = result[0]; + Motor[chan].MaxPWM = result[1]; + Motor[chan].Temperature = 255;; + } else { + if((Motor[chan].State & MOTOR_STATE_ERROR_MASK) < MOTOR_STATE_ERROR_MASK) Motor[chan].State++; // error + } + Motor[chan].RoundCount = 0; + } else { + if (OK != transfer(&msg[0], 1, nullptr, 0)) { + if((Motor[chan].State & MOTOR_STATE_ERROR_MASK) < MOTOR_STATE_ERROR_MASK) Motor[chan].State++; // error + } + } + + } else { + /* + * New BL-Ctrl 11Bit served. Version >= 2.0 + */ + msg[0] = Motor[chan].SetPoint; + msg[1] = Motor[chan].SetPointLowerBits; + + if(Motor[chan].SetPointLowerBits == 0) { + bytesToSendBL2 = 1; // if setpoint lower bits are zero, we send only the higher bits - this saves time + } + + if(Motor[chan].RoundCount >= 16) { + // on each 16th cyle we read out the status messages from the blctrl + if (OK == transfer(&msg[0], bytesToSendBL2, &result[0], 3)) { + Motor[chan].Current = result[0]; + Motor[chan].MaxPWM = result[1]; + Motor[chan].Temperature = result[2]; + } else { + if((Motor[chan].State & MOTOR_STATE_ERROR_MASK) < MOTOR_STATE_ERROR_MASK) Motor[chan].State++; // error + } + Motor[chan].RoundCount = 0; + } else { + if (OK != transfer(&msg[0], bytesToSendBL2, nullptr, 0)) { + if((Motor[chan].State & MOTOR_STATE_ERROR_MASK) < MOTOR_STATE_ERROR_MASK) Motor[chan].State++; // error + } + } + + } + + Motor[chan].RoundCount++; + //} + + if(showDebug == true) { + debugCounter++; + if(debugCounter == 2000) { + debugCounter = 0; + for(int i=0; i<_num_outputs; i++){ + if(Motor[i].State & MOTOR_STATE_PRESENT_MASK) { + fprintf(stderr, "[mkblctrl] #%i:\tVer: %i\tVal: %i\tCurr: %i\tMaxPWM: %i\tTemp: %i\tState: %i\n", i, Motor[i].Version, Motor[i].SetPoint, Motor[i].Current, Motor[i].MaxPWM, Motor[i].Temperature, Motor[i].State); + } + } + fprintf(stderr, "\n"); + } + } + return 0; +} + +int +MK::mk_servo_set_test(unsigned int chan, float val) +{ + _retries = 0; + int ret; + + float tmpVal = 0; + + uint8_t msg[2] = { 0,0 }; + + tmpVal = (1023 + (1023 * val)); + if(tmpVal > 2048) { + tmpVal = 2048; + } + + Motor[chan].SetPoint = (uint8_t) (tmpVal / 8); + + if(_armed == false) { + Motor[chan].SetPoint = 0; + Motor[chan].SetPointLowerBits = 0; + } + + msg[0] = Motor[chan].SetPoint; + + set_address(BLCTRL_BASE_ADDR + (chan + addrTranslator[chan])); + ret = transfer(&msg[0], 1, nullptr, 0); + + ret = OK; + + return ret; +} + + +int +MK::mk_servo_test(unsigned int chan) +{ + int ret=0; + float tmpVal = 0; + float val = -1; + _retries = 0; + uint8_t msg[2] = { 0,0 }; + + if(debugCounter >= MOTOR_SPINUP_COUNTER) { + debugCounter = 0; + _motor++; + + if(_motor < _num_outputs) { + fprintf(stderr, "[mkblctrl] Motortest - #%i:\tspinup\n", _motor); + } + + if(_motor >= _num_outputs) { + _motor = -1; + _motortest = false; + } + + } + debugCounter++; + + if(_motor == chan) { + val = BLCTRL_MIN_VALUE; + } else { + val = -1; + } + + tmpVal = (1023 + (1023 * val)); + if(tmpVal > 2048) { + tmpVal = 2048; + } + + //Motor[chan].SetPoint = (uint8_t) (tmpVal / 8); + //Motor[chan].SetPointLowerBits = (uint8_t) (tmpVal % 8) & 0x07; + Motor[chan].SetPoint = (uint8_t) tmpVal>>3; + Motor[chan].SetPointLowerBits = (uint8_t) tmpVal & 0x07; + + if(_motor != chan) { + Motor[chan].SetPoint = 0; + Motor[chan].SetPointLowerBits = 0; + } + + if(Motor[chan].Version == BLCTRL_OLD) { + msg[0] = Motor[chan].SetPoint; + } else { + msg[0] = Motor[chan].SetPoint; + msg[1] = Motor[chan].SetPointLowerBits; + } + + set_address(BLCTRL_BASE_ADDR + (chan + addrTranslator[chan])); + if(Motor[chan].Version == BLCTRL_OLD) { + ret = transfer(&msg[0], 1, nullptr, 0); + } else { + ret = transfer(&msg[0], 2, nullptr, 0); + } + + return ret; +} + + +int +MK::control_callback(uintptr_t handle, + uint8_t control_group, + uint8_t control_index, + float &input) +{ + const actuator_controls_s *controls = (actuator_controls_s *)handle; + + input = controls->control[control_index]; + return 0; +} + +int +MK::ioctl(file *filp, int cmd, unsigned long arg) +{ + int ret; + + // XXX disabled, confusing users + //debug("ioctl 0x%04x 0x%08x", cmd, arg); + + /* try it as a GPIO ioctl first */ + ret = gpio_ioctl(filp, cmd, arg); + + if (ret != -ENOTTY) + return ret; + + /* if we are in valid PWM mode, try it as a PWM ioctl as well */ + switch (_mode) { + case MODE_2PWM: + case MODE_4PWM: + ret = pwm_ioctl(filp, cmd, arg); + break; + + default: + debug("not in a PWM mode"); + break; + } + + /* if nobody wants it, let CDev have it */ + if (ret == -ENOTTY) + ret = CDev::ioctl(filp, cmd, arg); + + return ret; +} + +int +MK::pwm_ioctl(file *filp, int cmd, unsigned long arg) +{ + int ret = OK; + int channel; + + lock(); + + switch (cmd) { + case PWM_SERVO_ARM: + ////up_pwm_servo_arm(true); + mk_servo_arm(true); + break; + + case PWM_SERVO_DISARM: + ////up_pwm_servo_arm(false); + mk_servo_arm(false); + break; + + case PWM_SERVO_SET_UPDATE_RATE: + set_pwm_rate(arg); + break; + + + case PWM_SERVO_SET(0) ... PWM_SERVO_SET(_max_actuators - 1): + + /* fake an update to the selected 'servo' channel */ + if ((arg >= 0) && (arg <= 255)) { + channel = cmd - PWM_SERVO_SET(0); + //mk_servo_set(channel, arg); + } else { + ret = -EINVAL; + } + + break; + + case PWM_SERVO_GET(0) ... PWM_SERVO_GET(_max_actuators - 1): + /* copy the current output value from the channel */ + *(servo_position_t *)arg = cmd - PWM_SERVO_GET(0); + break; + + case MIXERIOCGETOUTPUTCOUNT: + /* + if (_mode == MODE_4PWM) { + *(unsigned *)arg = 4; + } else { + *(unsigned *)arg = 2; + } + */ + + *(unsigned *)arg = _num_outputs; + + break; + + case MIXERIOCRESET: + if (_mixers != nullptr) { + delete _mixers; + _mixers = nullptr; + } + + break; + + case MIXERIOCADDSIMPLE: { + mixer_simple_s *mixinfo = (mixer_simple_s *)arg; + + SimpleMixer *mixer = new SimpleMixer(control_callback, + (uintptr_t)&_controls, mixinfo); + + if (mixer->check()) { + delete mixer; + ret = -EINVAL; + + } else { + if (_mixers == nullptr) + _mixers = new MixerGroup(control_callback, + (uintptr_t)&_controls); + + _mixers->add_mixer(mixer); + } + + break; + } + + case MIXERIOCLOADBUF: { + const char *buf = (const char *)arg; + unsigned buflen = strnlen(buf, 1024); + + if (_mixers == nullptr) + _mixers = new MixerGroup(control_callback, (uintptr_t)&_controls); + + if (_mixers == nullptr) { + ret = -ENOMEM; + + } else { + + ret = _mixers->load_from_buf(buf, buflen); + + if (ret != 0) { + debug("mixer load failed with %d", ret); + delete _mixers; + _mixers = nullptr; + ret = -EINVAL; + } + } + break; + } + + default: + ret = -ENOTTY; + break; + } + + unlock(); + + return ret; +} + +void +MK::gpio_reset(void) +{ + /* + * Setup default GPIO config - all pins as GPIOs, GPIO driver chip + * to input mode. + */ + for (unsigned i = 0; i < _ngpio; i++) + stm32_configgpio(_gpio_tab[i].input); + + stm32_gpiowrite(GPIO_GPIO_DIR, 0); + stm32_configgpio(GPIO_GPIO_DIR); +} + +void +MK::gpio_set_function(uint32_t gpios, int function) +{ + /* + * GPIOs 0 and 1 must have the same direction as they are buffered + * by a shared 2-port driver. Any attempt to set either sets both. + */ + if (gpios & 3) { + gpios |= 3; + + /* flip the buffer to output mode if required */ + if (GPIO_SET_OUTPUT == function) + stm32_gpiowrite(GPIO_GPIO_DIR, 1); + } + + /* configure selected GPIOs as required */ + for (unsigned i = 0; i < _ngpio; i++) { + if (gpios & (1 << i)) { + switch (function) { + case GPIO_SET_INPUT: + stm32_configgpio(_gpio_tab[i].input); + break; + + case GPIO_SET_OUTPUT: + stm32_configgpio(_gpio_tab[i].output); + break; + + case GPIO_SET_ALT_1: + if (_gpio_tab[i].alt != 0) + stm32_configgpio(_gpio_tab[i].alt); + + break; + } + } + } + + /* flip buffer to input mode if required */ + if ((GPIO_SET_INPUT == function) && (gpios & 3)) + stm32_gpiowrite(GPIO_GPIO_DIR, 0); +} + +void +MK::gpio_write(uint32_t gpios, int function) +{ + int value = (function == GPIO_SET) ? 1 : 0; + + for (unsigned i = 0; i < _ngpio; i++) + if (gpios & (1 << i)) + stm32_gpiowrite(_gpio_tab[i].output, value); +} + +uint32_t +MK::gpio_read(void) +{ + uint32_t bits = 0; + + for (unsigned i = 0; i < _ngpio; i++) + if (stm32_gpioread(_gpio_tab[i].input)) + bits |= (1 << i); + + return bits; +} + +int +MK::gpio_ioctl(struct file *filp, int cmd, unsigned long arg) +{ + int ret = OK; + + lock(); + + switch (cmd) { + + case GPIO_RESET: + gpio_reset(); + break; + + case GPIO_SET_OUTPUT: + case GPIO_SET_INPUT: + case GPIO_SET_ALT_1: + gpio_set_function(arg, cmd); + break; + + case GPIO_SET_ALT_2: + case GPIO_SET_ALT_3: + case GPIO_SET_ALT_4: + ret = -EINVAL; + break; + + case GPIO_SET: + case GPIO_CLEAR: + gpio_write(arg, cmd); + break; + + case GPIO_GET: + *(uint32_t *)arg = gpio_read(); + break; + + default: + ret = -ENOTTY; + } + + unlock(); + + return ret; +} + +namespace +{ + +enum PortMode { + PORT_MODE_UNSET = 0, + PORT_FULL_GPIO, + PORT_FULL_SERIAL, + PORT_FULL_PWM, + PORT_GPIO_AND_SERIAL, + PORT_PWM_AND_SERIAL, + PORT_PWM_AND_GPIO, +}; + +enum MappingMode { + MAPPING_MK = 0, + MAPPING_PX4, +}; + + enum FrameType { + FRAME_PLUS = 0, + FRAME_X, + }; + +PortMode g_port_mode; + +int +mk_new_mode(PortMode new_mode, int update_rate, int motorcount, bool motortest, int px4mode, int frametype) +{ + uint32_t gpio_bits; + MK::Mode servo_mode; + + /* reset to all-inputs */ + g_mk->ioctl(0, GPIO_RESET, 0); + + gpio_bits = 0; + servo_mode = MK::MODE_NONE; + + switch (new_mode) { + case PORT_FULL_GPIO: + case PORT_MODE_UNSET: + /* nothing more to do here */ + break; + + case PORT_FULL_SERIAL: + /* set all multi-GPIOs to serial mode */ + gpio_bits = GPIO_MULTI_1 | GPIO_MULTI_2 | GPIO_MULTI_3 | GPIO_MULTI_4; + break; + + case PORT_FULL_PWM: + /* select 4-pin PWM mode */ + servo_mode = MK::MODE_4PWM; + break; + + case PORT_GPIO_AND_SERIAL: + /* set RX/TX multi-GPIOs to serial mode */ + gpio_bits = GPIO_MULTI_3 | GPIO_MULTI_4; + break; + + case PORT_PWM_AND_SERIAL: + /* select 2-pin PWM mode */ + servo_mode = MK::MODE_2PWM; + /* set RX/TX multi-GPIOs to serial mode */ + gpio_bits = GPIO_MULTI_3 | GPIO_MULTI_4; + break; + + case PORT_PWM_AND_GPIO: + /* select 2-pin PWM mode */ + servo_mode = MK::MODE_2PWM; + break; + } + + /* adjust GPIO config for serial mode(s) */ + if (gpio_bits != 0) + g_mk->ioctl(0, GPIO_SET_ALT_1, gpio_bits); + + /* native PX4 addressing) */ + g_mk->set_px4mode(px4mode); + + /* set frametype (geometry) */ + g_mk->set_frametype(frametype); + + /* (re)set count of used motors */ + g_mk->set_motor_count(motorcount); + + /* (re)set the PWM output mode */ + g_mk->set_mode(servo_mode); + + /* motortest if enabled */ + g_mk->set_motor_test(motortest); + + if ((servo_mode != MK::MODE_NONE) && (update_rate != 0)) + g_mk->set_pwm_rate(update_rate); + + return OK; +} + +int +mk_start(unsigned bus, unsigned motors) +{ + int ret = OK; + + if (g_mk == nullptr) { + + g_mk = new MK(bus); + + if (g_mk == nullptr) { + ret = -ENOMEM; + + } else { + ret = g_mk->init(motors); + + if (ret != OK) { + delete g_mk; + g_mk = nullptr; + } + } + } + + return ret; +} + + +} // namespace + +extern "C" __EXPORT int mkblctrl_main(int argc, char *argv[]); + +int +mkblctrl_main(int argc, char *argv[]) +{ + PortMode new_mode = PORT_MODE_UNSET; + int pwm_update_rate_in_hz = UPDATE_RATE; + int motorcount = 0; + int bus = 1; + bool motortest = false; + int px4mode = MAPPING_MK; + int frametype = FRAME_PLUS; // + plus is default + + /* + * Mode switches. + * + * XXX use getopt? + */ + for (int i = 1; i < argc; i++) { /* argv[0] is "mk" */ + if (!strcmp(argv[i], "mode_quad")) { + new_mode = PORT_FULL_PWM; + motorcount = 4; + } else if (!strcmp(argv[i], "mode_hexa")) { + new_mode = PORT_FULL_PWM; + motorcount = 6; + } else if (!strcmp(argv[i], "mode_octo")) { + new_mode = PORT_FULL_PWM; + motorcount = 8; + } + + /* look for the optional update rate for the supported modes */ + if (strcmp(argv[i], "-u") == 0 || strcmp(argv[i], "--update-rate") == 0) { + if (argc > i + 1) { + pwm_update_rate_in_hz = atoi(argv[i + 1]); + } else { + errx(1, "missing argument for update rate (-u)"); + return 1; + } + } + + /* look for the optional i2c bus parameter */ + if (strcmp(argv[i], "-b") == 0 || strcmp(argv[i], "--bus") == 0) { + if (argc > i + 1) { + bus = atoi(argv[i + 1]); + } else { + errx(1, "missing argument for i2c bus (-b)"); + return 1; + } + } + + /* look for the optional frame parameter */ + if (strcmp(argv[i], "-f") == 0 || strcmp(argv[i], "--frame") == 0) { + if (argc > i + 1) { + if(strcmp(argv[i + 1], "+") == 0 || strcmp(argv[i + 1], "x") == 0 || strcmp(argv[i + 1], "X") == 0) { + if(strcmp(argv[i + 1], "+") == 0) { + frametype = FRAME_PLUS; + } else { + frametype = FRAME_PLUS; + } + } else { + errx(1, "only + or x for frametype supported !"); + } + } else { + errx(1, "missing argument for frametype (-f)"); + return 1; + } + } + + /* look for the optional geometry parameter */ + if (strcmp(argv[i], "-px4mode") == 0) { + px4mode = MAPPING_PX4; + } + + /* look for the optional test parameter */ + if (strcmp(argv[i], "-t") == 0) { + motortest = true; + } + + } + + if(new_mode == PORT_MODE_UNSET) { + fprintf(stderr, "mkblctrl: unrecognised command, try:\n"); + fprintf(stderr, " mode_quad, mode_hexa, mode_octo [-b i2c_bus_number] [-u update_rate_in_hz] [-t motortest] [-px4mode] [-f frame{+/x}]\n"); + exit(1); + } + + if (mk_start(bus, motorcount) != OK) + errx(1, "failed to start the MK-BLCtrl driver"); + + + /* was a new mode set? */ + if (new_mode != PORT_MODE_UNSET) { + + /* yes but it's the same mode */ + //if (new_mode == g_port_mode) + //return OK; + + /* switch modes */ + fprintf(stderr, "[mkblctrl] %iHz Update Rate\n",pwm_update_rate_in_hz); + return mk_new_mode(new_mode, pwm_update_rate_in_hz, motorcount, motortest, px4mode, frametype); + } + + /* test, etc. here g*/ + + exit(1); +} diff --git a/nuttx/configs/px4fmu/nsh/appconfig b/nuttx/configs/px4fmu/nsh/appconfig index 80cf6f312c..5bac6214c9 100644 --- a/nuttx/configs/px4fmu/nsh/appconfig +++ b/nuttx/configs/px4fmu/nsh/appconfig @@ -124,6 +124,7 @@ CONFIGURED_APPS += drivers/blinkm CONFIGURED_APPS += drivers/stm32/tone_alarm CONFIGURED_APPS += drivers/stm32/adc CONFIGURED_APPS += drivers/px4fmu +CONFIGURED_APPS += drivers/mkblctrl CONFIGURED_APPS += drivers/hil CONFIGURED_APPS += drivers/gps CONFIGURED_APPS += drivers/mb12xx From df6976c8d640b395220d46f5b1fd7ecfc8ae3e04 Mon Sep 17 00:00:00 2001 From: Simon Wilks Date: Fri, 19 Apr 2013 16:20:40 +0200 Subject: [PATCH 07/84] Split diff pressure and airspeed. --- apps/commander/commander.c | 10 +-- apps/drivers/ets_airspeed/ets_airspeed.cpp | 71 ++++------------------ apps/sdlog/sdlog.c | 17 +++++- apps/sensors/sensors.cpp | 59 ++++++++++++------ apps/uORB/objects_common.cpp | 3 + apps/uORB/topics/differential_pressure.h | 11 ++-- apps/uORB/topics/sensor_combined.h | 2 + 7 files changed, 80 insertions(+), 93 deletions(-) diff --git a/apps/commander/commander.c b/apps/commander/commander.c index 7c0a25f862..fcfffcfef7 100644 --- a/apps/commander/commander.c +++ b/apps/commander/commander.c @@ -801,7 +801,7 @@ void do_airspeed_calibration(int status_pub, struct vehicle_status_s *status) struct differential_pressure_s differential_pressure; int calibration_counter = 0; - float airspeed_offset = 0.0f; + float diff_pres_offset = 0.0f; while (calibration_counter < calibration_count) { @@ -812,7 +812,7 @@ void do_airspeed_calibration(int status_pub, struct vehicle_status_s *status) if (poll_ret) { orb_copy(ORB_ID(differential_pressure), sub_differential_pressure, &differential_pressure); - airspeed_offset += differential_pressure.voltage; + diff_pres_offset += differential_pressure.differential_pressure_pa; calibration_counter++; } else if (poll_ret == 0) { @@ -822,11 +822,11 @@ void do_airspeed_calibration(int status_pub, struct vehicle_status_s *status) } } - airspeed_offset = airspeed_offset / calibration_count; + diff_pres_offset = diff_pres_offset / calibration_count; - if (isfinite(airspeed_offset)) { + if (isfinite(diff_pres_offset)) { - if (param_set(param_find("SENS_VAIR_OFF"), &(airspeed_offset))) { + if (param_set(param_find("SENS_VAIR_OFF"), &(diff_pres_offset))) { mavlink_log_critical(mavlink_fd, "Setting offs failed!"); } diff --git a/apps/drivers/ets_airspeed/ets_airspeed.cpp b/apps/drivers/ets_airspeed/ets_airspeed.cpp index 58d016a307..860baa760c 100644 --- a/apps/drivers/ets_airspeed/ets_airspeed.cpp +++ b/apps/drivers/ets_airspeed/ets_airspeed.cpp @@ -61,16 +61,16 @@ #include -#include -#include #include +#include +#include +#include #include #include #include #include -#include /* for baro readings */ #include /* Configuration Constants */ @@ -83,9 +83,6 @@ /* Max measurement rate is 100Hz */ #define CONVERSION_INTERVAL (1000000 / 10) /* microseconds */ -#define DIFF_PRESSURE_SCALE 1.0 -#define DIFF_PRESSURE_OFFSET 1673 - /* oddly, ERROR is not defined for c++ */ #ifdef ERROR # undef ERROR @@ -96,9 +93,6 @@ static const int ERROR = -1; # error This requires CONFIG_SCHED_WORKQUEUE. #endif -static int _sensor_sub = -1; - - class ETS_AIRSPEED : public device::I2C { public: @@ -127,6 +121,7 @@ private: bool _sensor_ok; int _measure_ticks; bool _collect_phase; + int _differential_pressure_offset; orb_advert_t _airspeed_pub; @@ -195,7 +190,8 @@ ETS_AIRSPEED::ETS_AIRSPEED(int bus, int address) : _airspeed_pub(-1), _sample_perf(perf_alloc(PC_ELAPSED, "ETS_AIRSPEED_read")), _comms_errors(perf_alloc(PC_COUNT, "ETS_AIRSPEED_comms_errors")), - _buffer_overflows(perf_alloc(PC_COUNT, "ETS_AIRSPEED_buffer_overflows")) + _buffer_overflows(perf_alloc(PC_COUNT, "ETS_AIRSPEED_buffer_overflows")), + _differential_pressure_offset(0) { // enable debug() calls _debug_enabled = true; @@ -239,12 +235,7 @@ ETS_AIRSPEED::init() if (_airspeed_pub < 0) debug("failed to create airspeed sensor object. Did you start uOrb?"); - _sensor_sub = orb_subscribe(ORB_ID(sensor_combined)); - - if (_sensor_sub < 0) { - debug("failed to subscribe to sensor_combined object."); - return ret; - } + param_get(param_find("SENS_VAIR_OFF"), &_differential_pressure_offset); ret = OK; /* sensor is ok, but we don't really know if it is within range */ @@ -462,38 +453,13 @@ ETS_AIRSPEED::collect() } uint16_t diff_pres_pa = val[1] << 8 | val[0]; - //log("val: %0.3f", (float)(diff_pressure)); /* adjust if necessary */ - diff_pres_pa = DIFF_PRESSURE_SCALE * (diff_pres_pa - DIFF_PRESSURE_OFFSET); + diff_pres_pa -= _differential_pressure_offset; //log("measurement: %0.2f m/s", calc_indicated_airspeed((float)_reports[_next_report].diff_pressure)); - - struct sensor_combined_s raw; - memset(&raw, 0, sizeof(raw)); - - bool updated; - orb_check(_sensor_sub, &updated); - if (updated) { - orb_copy(ORB_ID(sensor_combined), _sensor_sub, &raw); - printf("baro temp %3.6f\n", raw.baro_pres_mbar); - } - //if (raw.baro_temp_celcius > 0) - // log("baro temp %3.3f\n", (uint8_t) raw.baro_temp_celcius); - - float airspeed_true = calc_true_airspeed(diff_pres_pa + raw.baro_pres_mbar*1e2f, - raw.baro_pres_mbar*1e2f, raw.baro_temp_celcius - 5.0f); //factor 1e2 for conversion from mBar to Pa - // XXX HACK - true temperature is much less than indicated temperature in baro, - // subtract 5 degrees in an attempt to account for the electrical upheating of the PCB - - float airspeed_indicated = calc_indicated_airspeed(diff_pres_pa); _reports[_next_report].timestamp = hrt_absolute_time(); - _reports[_next_report].static_pressure_mbar = raw.baro_pres_mbar; - _reports[_next_report].differential_pressure_mbar = diff_pres_pa * 1e-2f; - _reports[_next_report].temperature_celcius = raw.baro_temp_celcius; - _reports[_next_report].indicated_airspeed_m_s = airspeed_indicated; - _reports[_next_report].true_airspeed_m_s = airspeed_true; - _reports[_next_report].voltage = 0; + _reports[_next_report].differential_pressure_pa = diff_pres_pa; /* announce the airspeed if needed, just publish else */ orb_publish(ORB_ID(differential_pressure), _airspeed_pub, &_reports[_next_report]); @@ -512,7 +478,6 @@ ETS_AIRSPEED::collect() ret = OK; -out: perf_end(_sample_perf); return ret; @@ -719,19 +684,7 @@ test() err(1, "immediate read failed"); warnx("single read"); - warnx("diff pressure: %0.3f mbar", report.differential_pressure_mbar); - warnx("indicated airspeed: %0.1f m/s", report.indicated_airspeed_m_s); - warnx("true airspeed: %0.1f m/s", report.true_airspeed_m_s); - - struct sensor_combined_s raw; - memset(&raw, 0, sizeof(raw)); - int sensor_sub = orb_subscribe(ORB_ID(sensor_combined)); - orb_copy(ORB_ID(sensor_combined), sensor_sub, &raw); - - //if (raw.baro_temp_celcius > 0) - // log("baro temp %3.3f\n", (uint8_t) raw.baro_temp_celcius); - warnx("temp: %3.5f", raw.baro_temp_celcius); - warnx("time: %lld", report.timestamp); + warnx("diff pressure: %0.3f pa", (double) report.differential_pressure_pa); /* start the sensor polling at 2Hz */ if (OK != ioctl(fd, SENSORIOCSPOLLRATE, 2)) @@ -756,9 +709,7 @@ test() err(1, "periodic read failed"); warnx("periodic read %u", i); - warnx("diff pressure: %0.3f mbar", report.differential_pressure_mbar); - warnx("indicated airspeed: %0.1f m/s", report.indicated_airspeed_m_s); - warnx("true airspeed: %0.1f m/s", report.true_airspeed_m_s); warnx("time: %lld", report.timestamp); + warnx("diff pressure: %0.3f pa", (double) report.differential_pressure_pa); } errx(0, "PASS"); diff --git a/apps/sdlog/sdlog.c b/apps/sdlog/sdlog.c index df8745d9f5..46b232c34d 100644 --- a/apps/sdlog/sdlog.c +++ b/apps/sdlog/sdlog.c @@ -71,6 +71,7 @@ #include #include #include +#include #include @@ -444,6 +445,7 @@ int sdlog_thread_main(int argc, char *argv[]) struct optical_flow_s flow; struct battery_status_s batt; struct differential_pressure_s diff_pressure; + struct airspeed_s airspeed; } buf; memset(&buf, 0, sizeof(buf)); @@ -462,6 +464,7 @@ int sdlog_thread_main(int argc, char *argv[]) int flow_sub; int batt_sub; int diff_pressure_sub; + int airspeed_sub; } subs; /* --- MANAGEMENT - LOGGING COMMAND --- */ @@ -563,6 +566,13 @@ int sdlog_thread_main(int argc, char *argv[]) fds[fdsc_count].events = POLLIN; fdsc_count++; + /* --- AIRSPEED --- */ + /* subscribe to ORB for airspeed */ + subs.airspeed_sub = orb_subscribe(ORB_ID(airspeed)); + fds[fdsc_count].fd = subs.airspeed_sub; + fds[fdsc_count].events = POLLIN; + fdsc_count++; + /* WARNING: If you get the error message below, * then the number of registered messages (fdsc) * differs from the number of messages in the above list. @@ -655,6 +665,7 @@ int sdlog_thread_main(int argc, char *argv[]) orb_copy(ORB_ID(vehicle_vicon_position), subs.vicon_pos_sub, &buf.vicon_pos); orb_copy(ORB_ID(optical_flow), subs.flow_sub, &buf.flow); orb_copy(ORB_ID(differential_pressure), subs.diff_pressure_sub, &buf.diff_pressure); + orb_copy(ORB_ID(airspeed), subs.airspeed_sub, &buf.airspeed); orb_copy(ORB_ID(battery_status), subs.batt_sub, &buf.batt); /* if skipping is on or logging is disabled, ignore */ @@ -691,9 +702,9 @@ int sdlog_thread_main(int argc, char *argv[]) .vicon = {buf.vicon_pos.x, buf.vicon_pos.y, buf.vicon_pos.z, buf.vicon_pos.roll, buf.vicon_pos.pitch, buf.vicon_pos.yaw}, .control_effective = {buf.act_controls_effective.control_effective[0], buf.act_controls_effective.control_effective[1], buf.act_controls_effective.control_effective[2], buf.act_controls_effective.control_effective[3]}, .flow = {buf.flow.flow_raw_x, buf.flow.flow_raw_y, buf.flow.flow_comp_x_m, buf.flow.flow_comp_y_m, buf.flow.ground_distance_m, buf.flow.quality}, - .diff_pressure = buf.diff_pressure.differential_pressure_mbar, - .ind_airspeed = buf.diff_pressure.indicated_airspeed_m_s, - .true_airspeed = buf.diff_pressure.true_airspeed_m_s + .diff_pressure = buf.diff_pressure.differential_pressure_pa, + .ind_airspeed = buf.airspeed.indicated_airspeed_m_s, + .true_airspeed = buf.airspeed.true_airspeed_m_s }; /* put into buffer for later IO */ diff --git a/apps/sensors/sensors.cpp b/apps/sensors/sensors.cpp index d725c7727f..2cf3b92ef7 100644 --- a/apps/sensors/sensors.cpp +++ b/apps/sensors/sensors.cpp @@ -77,6 +77,7 @@ #include #include #include +#include #define GYRO_HEALTH_COUNTER_LIMIT_ERROR 20 /* 40 ms downtime at 500 Hz update rate */ #define ACC_HEALTH_COUNTER_LIMIT_ERROR 20 /* 40 ms downtime at 500 Hz update rate */ @@ -156,6 +157,8 @@ private: int _mag_sub; /**< raw mag data subscription */ int _rc_sub; /**< raw rc channels data subscription */ int _baro_sub; /**< raw baro data subscription */ + int _airspeed_sub; /**< airspeed subscription */ + int _differential_pressure_sub; /**< raw differential pressure subscription */ int _vstatus_sub; /**< vehicle status subscription */ int _params_sub; /**< notification of parameter updates */ int _manual_control_sub; /**< notification of manual control updates */ @@ -165,6 +168,7 @@ private: orb_advert_t _rc_pub; /**< raw r/c control topic */ orb_advert_t _battery_pub; /**< battery status */ orb_advert_t _airspeed_pub; /**< airspeed */ + orb_advert_t _differential_pressure_pub; /**< differential_pressure */ perf_counter_t _loop_perf; /**< loop performance counter */ @@ -172,6 +176,7 @@ private: struct battery_status_s _battery_status; /**< battery status */ struct baro_report _barometer; /**< barometer data */ struct differential_pressure_s _differential_pressure; + struct airspeed_s _airspeed; struct { float min[_rc_max_chan_count]; @@ -330,6 +335,14 @@ private: */ void baro_poll(struct sensor_combined_s &raw); + /** + * Poll the differential pressure sensor for updated data. + * + * @param raw Combined sensor data structure into which + * data should be returned. + */ + void differential_pressure_poll(struct sensor_combined_s &raw); + /** * Check for changes in vehicle status. */ @@ -398,6 +411,7 @@ Sensors::Sensors() : _rc_pub(-1), _battery_pub(-1), _airspeed_pub(-1), + _differential_pressure_pub(-1), /* performance counters */ _loop_perf(perf_alloc(PC_ELAPSED, "sensor task update")) @@ -887,6 +901,27 @@ Sensors::baro_poll(struct sensor_combined_s &raw) } } +void +Sensors::differential_pressure_poll(struct sensor_combined_s &raw) +{ + bool updated; + orb_check(_differential_pressure_sub, &updated); + + if (updated) { + orb_copy(ORB_ID(differential_pressure), _differential_pressure_sub, &_differential_pressure); + + float airspeed_true = calc_true_airspeed(_differential_pressure.differential_pressure_pa + raw.baro_pres_mbar*1e2f, + raw.baro_pres_mbar*1e2f, raw.baro_temp_celcius - 5.0f); //factor 1e2 for conversion from mBar to Pa + // XXX HACK - true temperature is much less than indicated temperature in baro, + // subtract 5 degrees in an attempt to account for the electrical upheating of the PCB + + float airspeed_indicated = calc_indicated_airspeed(_differential_pressure.differential_pressure_pa); + + raw.differential_pressure_pa = _differential_pressure.differential_pressure_pa; + raw.differential_pressure_counter++; + } +} + void Sensors::vehicle_status_poll() { @@ -1045,31 +1080,18 @@ Sensors::adc_poll(struct sensor_combined_s &raw) */ if (voltage > 0.4f) { - float diff_pres_pa = (voltage - _parameters.airspeed_offset) * 1000.0f; //for MPXV7002DP sensor - - float airspeed_true = calc_true_airspeed(diff_pres_pa + _barometer.pressure*1e2f, - _barometer.pressure*1e2f, _barometer.temperature - 5.0f); //factor 1e2 for conversion from mBar to Pa - // XXX HACK - true temperature is much less than indicated temperature in baro, - // subtract 5 degrees in an attempt to account for the electrical upheating of the PCB - - float airspeed_indicated = calc_indicated_airspeed(diff_pres_pa); - - //printf("voltage: %.4f, diff_pres_pa %.4f, baro press %.4f Pa, v_ind %.4f, v_true %.4f\n", (double)voltage, (double)diff_pres_pa, (double)_barometer.pressure*1e2f, (double)airspeed_indicated, (double)airspeed_true); + float diff_pres_pa = voltage * 1000.0f - _parameters.airspeed_offset; //for MPXV7002DP sensor _differential_pressure.timestamp = hrt_absolute_time(); - _differential_pressure.static_pressure_mbar = _barometer.pressure; - _differential_pressure.differential_pressure_mbar = diff_pres_pa*1e-2f; - _differential_pressure.temperature_celcius = _barometer.temperature; - _differential_pressure.indicated_airspeed_m_s = airspeed_indicated; - _differential_pressure.true_airspeed_m_s = airspeed_true; + _differential_pressure.differential_pressure_pa = diff_pres_pa; _differential_pressure.voltage = voltage; /* announce the airspeed if needed, just publish else */ - if (_airspeed_pub > 0) { - orb_publish(ORB_ID(differential_pressure), _airspeed_pub, &_differential_pressure); + if (_differential_pressure_pub > 0) { + orb_publish(ORB_ID(differential_pressure), _differential_pressure_pub, &_differential_pressure); } else { - _airspeed_pub = orb_advertise(ORB_ID(differential_pressure), &_differential_pressure); + _differential_pressure_pub = orb_advertise(ORB_ID(differential_pressure), &_differential_pressure); } } } @@ -1334,6 +1356,7 @@ Sensors::task_main() gyro_poll(raw); mag_poll(raw); baro_poll(raw); + differential_pressure_poll(raw); parameter_update_poll(true /* forced */); diff --git a/apps/uORB/objects_common.cpp b/apps/uORB/objects_common.cpp index 1363751401..4197f6fb2d 100644 --- a/apps/uORB/objects_common.cpp +++ b/apps/uORB/objects_common.cpp @@ -122,6 +122,9 @@ ORB_DEFINE(optical_flow, struct optical_flow_s); #include "topics/omnidirectional_flow.h" ORB_DEFINE(omnidirectional_flow, struct omnidirectional_flow_s); +#include "topics/airspeed.h" +ORB_DEFINE(airspeed, struct airspeed_s); + #include "topics/differential_pressure.h" ORB_DEFINE(differential_pressure, struct differential_pressure_s); diff --git a/apps/uORB/topics/differential_pressure.h b/apps/uORB/topics/differential_pressure.h index d5e4bf37ef..ac52206192 100644 --- a/apps/uORB/topics/differential_pressure.h +++ b/apps/uORB/topics/differential_pressure.h @@ -49,16 +49,13 @@ */ /** - * Differential pressure and airspeed + * Differential pressure. */ struct differential_pressure_s { uint64_t timestamp; /**< microseconds since system boot, needed to integrate */ - float static_pressure_mbar; /**< Static / environment pressure */ - float differential_pressure_mbar; /**< Differential pressure reading */ - float temperature_celcius; /**< ambient temperature in celcius, -1 if unknown */ - float indicated_airspeed_m_s; /**< indicated airspeed in meters per second, -1 if unknown */ - float true_airspeed_m_s; /**< true airspeed in meters per second, -1 if unknown */ - float voltage; /**< Voltage from the airspeed sensor (voltage divider already compensated) */ + float differential_pressure_pa; /**< Differential pressure reading */ + float voltage; /**< Voltage from analog airspeed sensors (voltage divider already compensated) */ + }; /** diff --git a/apps/uORB/topics/sensor_combined.h b/apps/uORB/topics/sensor_combined.h index 961ee8b4a6..ad88e4b6e1 100644 --- a/apps/uORB/topics/sensor_combined.h +++ b/apps/uORB/topics/sensor_combined.h @@ -103,6 +103,8 @@ struct sensor_combined_s { float mcu_temp_celcius; /**< Internal temperature measurement of MCU */ uint32_t baro_counter; /**< Number of raw baro measurements taken */ + float differential_pressure_pa; /**< Airspeed sensor differential pressure */ + uint32_t differential_pressure_counter; /**< Number of raw differential pressure measurements taken */ }; /** From 696e48fbf38de9d0ac12494cb2749ba3b04f852f Mon Sep 17 00:00:00 2001 From: Simon Wilks Date: Fri, 19 Apr 2013 18:28:06 +0200 Subject: [PATCH 08/84] Cleanup variable names and such --- apps/commander/commander.c | 30 ++++++++-------- apps/drivers/ets_airspeed/ets_airspeed.cpp | 8 ++--- apps/sdlog/sdlog.c | 12 +++---- apps/sensors/sensor_params.c | 2 +- apps/sensors/sensors.cpp | 40 +++++++++++----------- apps/uORB/topics/sensor_combined.h | 2 +- 6 files changed, 47 insertions(+), 47 deletions(-) diff --git a/apps/commander/commander.c b/apps/commander/commander.c index fcfffcfef7..2980ab118e 100644 --- a/apps/commander/commander.c +++ b/apps/commander/commander.c @@ -797,8 +797,8 @@ void do_airspeed_calibration(int status_pub, struct vehicle_status_s *status) const int calibration_count = 2500; - int sub_differential_pressure = orb_subscribe(ORB_ID(differential_pressure)); - struct differential_pressure_s differential_pressure; + int diff_pres_sub = orb_subscribe(ORB_ID(differential_pressure)); + struct differential_pressure_s diff_pres; int calibration_counter = 0; float diff_pres_offset = 0.0f; @@ -806,13 +806,13 @@ void do_airspeed_calibration(int status_pub, struct vehicle_status_s *status) while (calibration_counter < calibration_count) { /* wait blocking for new data */ - struct pollfd fds[1] = { { .fd = sub_differential_pressure, .events = POLLIN } }; + struct pollfd fds[1] = { { .fd = diff_pres_sub, .events = POLLIN } }; int poll_ret = poll(fds, 1, 1000); if (poll_ret) { - orb_copy(ORB_ID(differential_pressure), sub_differential_pressure, &differential_pressure); - diff_pres_offset += differential_pressure.differential_pressure_pa; + orb_copy(ORB_ID(differential_pressure), diff_pres_sub, &diff_pres); + diff_pres_offset += diff_pres.differential_pressure_pa; calibration_counter++; } else if (poll_ret == 0) { @@ -826,7 +826,7 @@ void do_airspeed_calibration(int status_pub, struct vehicle_status_s *status) if (isfinite(diff_pres_offset)) { - if (param_set(param_find("SENS_VAIR_OFF"), &(diff_pres_offset))) { + if (param_set(param_find("SENS_DPRES_OFF"), &(diff_pres_offset))) { mavlink_log_critical(mavlink_fd, "Setting offs failed!"); } @@ -856,7 +856,7 @@ void do_airspeed_calibration(int status_pub, struct vehicle_status_s *status) status->flag_preflight_airspeed_calibration = false; state_machine_publish(status_pub, status, mavlink_fd); - close(sub_differential_pressure); + close(diff_pres_sub); } @@ -1477,10 +1477,10 @@ int commander_thread_main(int argc, char *argv[]) struct sensor_combined_s sensors; memset(&sensors, 0, sizeof(sensors)); - int differential_pressure_sub = orb_subscribe(ORB_ID(differential_pressure)); - struct differential_pressure_s differential_pressure; - memset(&differential_pressure, 0, sizeof(differential_pressure)); - uint64_t last_differential_pressure_time = 0; + int diff_pres_sub = orb_subscribe(ORB_ID(differential_pressure)); + struct differential_pressure_s diff_pres; + memset(&diff_pres, 0, sizeof(diff_pres)); + uint64_t last_diff_pres_time = 0; /* Subscribe to command topic */ int cmd_sub = orb_subscribe(ORB_ID(vehicle_command)); @@ -1535,11 +1535,11 @@ int commander_thread_main(int argc, char *argv[]) orb_copy(ORB_ID(sensor_combined), sensor_sub, &sensors); } - orb_check(differential_pressure_sub, &new_data); + orb_check(diff_pres_sub, &new_data); if (new_data) { - orb_copy(ORB_ID(differential_pressure), differential_pressure_sub, &differential_pressure); - last_differential_pressure_time = differential_pressure.timestamp; + orb_copy(ORB_ID(differential_pressure), diff_pres_sub, &diff_pres); + last_diff_pres_time = diff_pres.timestamp; } orb_check(cmd_sub, &new_data); @@ -1754,7 +1754,7 @@ int commander_thread_main(int argc, char *argv[]) } /* Check for valid airspeed/differential pressure measurements */ - if (hrt_absolute_time() - last_differential_pressure_time < 2000000) { + if (hrt_absolute_time() - last_diff_pres_time < 2000000) { current_status.flag_airspeed_valid = true; } else { diff --git a/apps/drivers/ets_airspeed/ets_airspeed.cpp b/apps/drivers/ets_airspeed/ets_airspeed.cpp index 860baa760c..943848d438 100644 --- a/apps/drivers/ets_airspeed/ets_airspeed.cpp +++ b/apps/drivers/ets_airspeed/ets_airspeed.cpp @@ -121,7 +121,7 @@ private: bool _sensor_ok; int _measure_ticks; bool _collect_phase; - int _differential_pressure_offset; + int _diff_pres_offset; orb_advert_t _airspeed_pub; @@ -191,7 +191,7 @@ ETS_AIRSPEED::ETS_AIRSPEED(int bus, int address) : _sample_perf(perf_alloc(PC_ELAPSED, "ETS_AIRSPEED_read")), _comms_errors(perf_alloc(PC_COUNT, "ETS_AIRSPEED_comms_errors")), _buffer_overflows(perf_alloc(PC_COUNT, "ETS_AIRSPEED_buffer_overflows")), - _differential_pressure_offset(0) + _diff_pres_offset(0) { // enable debug() calls _debug_enabled = true; @@ -235,7 +235,7 @@ ETS_AIRSPEED::init() if (_airspeed_pub < 0) debug("failed to create airspeed sensor object. Did you start uOrb?"); - param_get(param_find("SENS_VAIR_OFF"), &_differential_pressure_offset); + param_get(param_find("SENS_DPRES_OFF"), &_diff_pres_offset); ret = OK; /* sensor is ok, but we don't really know if it is within range */ @@ -455,7 +455,7 @@ ETS_AIRSPEED::collect() uint16_t diff_pres_pa = val[1] << 8 | val[0]; /* adjust if necessary */ - diff_pres_pa -= _differential_pressure_offset; + diff_pres_pa -= _diff_pres_offset; //log("measurement: %0.2f m/s", calc_indicated_airspeed((float)_reports[_next_report].diff_pressure)); _reports[_next_report].timestamp = hrt_absolute_time(); diff --git a/apps/sdlog/sdlog.c b/apps/sdlog/sdlog.c index 46b232c34d..84a9eb6ac5 100644 --- a/apps/sdlog/sdlog.c +++ b/apps/sdlog/sdlog.c @@ -444,7 +444,7 @@ int sdlog_thread_main(int argc, char *argv[]) struct vehicle_vicon_position_s vicon_pos; struct optical_flow_s flow; struct battery_status_s batt; - struct differential_pressure_s diff_pressure; + struct differential_pressure_s diff_pres; struct airspeed_s airspeed; } buf; memset(&buf, 0, sizeof(buf)); @@ -463,7 +463,7 @@ int sdlog_thread_main(int argc, char *argv[]) int vicon_pos_sub; int flow_sub; int batt_sub; - int diff_pressure_sub; + int diff_pres_sub; int airspeed_sub; } subs; @@ -561,8 +561,8 @@ int sdlog_thread_main(int argc, char *argv[]) /* --- DIFFERENTIAL PRESSURE --- */ /* subscribe to ORB for flow measurements */ - subs.diff_pressure_sub = orb_subscribe(ORB_ID(differential_pressure)); - fds[fdsc_count].fd = subs.diff_pressure_sub; + subs.diff_pres_sub = orb_subscribe(ORB_ID(differential_pressure)); + fds[fdsc_count].fd = subs.diff_pres_sub; fds[fdsc_count].events = POLLIN; fdsc_count++; @@ -664,7 +664,7 @@ int sdlog_thread_main(int argc, char *argv[]) orb_copy(ORB_ID(vehicle_attitude), subs.att_sub, &buf.att); orb_copy(ORB_ID(vehicle_vicon_position), subs.vicon_pos_sub, &buf.vicon_pos); orb_copy(ORB_ID(optical_flow), subs.flow_sub, &buf.flow); - orb_copy(ORB_ID(differential_pressure), subs.diff_pressure_sub, &buf.diff_pressure); + orb_copy(ORB_ID(differential_pressure), subs.diff_pres_sub, &buf.diff_pres); orb_copy(ORB_ID(airspeed), subs.airspeed_sub, &buf.airspeed); orb_copy(ORB_ID(battery_status), subs.batt_sub, &buf.batt); @@ -702,7 +702,7 @@ int sdlog_thread_main(int argc, char *argv[]) .vicon = {buf.vicon_pos.x, buf.vicon_pos.y, buf.vicon_pos.z, buf.vicon_pos.roll, buf.vicon_pos.pitch, buf.vicon_pos.yaw}, .control_effective = {buf.act_controls_effective.control_effective[0], buf.act_controls_effective.control_effective[1], buf.act_controls_effective.control_effective[2], buf.act_controls_effective.control_effective[3]}, .flow = {buf.flow.flow_raw_x, buf.flow.flow_raw_y, buf.flow.flow_comp_x_m, buf.flow.flow_comp_y_m, buf.flow.ground_distance_m, buf.flow.quality}, - .diff_pressure = buf.diff_pressure.differential_pressure_pa, + .diff_pressure = buf.diff_pres.differential_pressure_pa, .ind_airspeed = buf.airspeed.indicated_airspeed_m_s, .true_airspeed = buf.airspeed.true_airspeed_m_s }; diff --git a/apps/sensors/sensor_params.c b/apps/sensors/sensor_params.c index a1ef9d136e..da2dfcca67 100644 --- a/apps/sensors/sensor_params.c +++ b/apps/sensors/sensor_params.c @@ -64,7 +64,7 @@ PARAM_DEFINE_FLOAT(SENS_ACC_XSCALE, 1.0f); PARAM_DEFINE_FLOAT(SENS_ACC_YSCALE, 1.0f); PARAM_DEFINE_FLOAT(SENS_ACC_ZSCALE, 1.0f); -PARAM_DEFINE_FLOAT(SENS_VAIR_OFF, 2.5f); +PARAM_DEFINE_FLOAT(SENS_DPRES_OFF, 2.5f); PARAM_DEFINE_FLOAT(RC1_MIN, 1000.0f); PARAM_DEFINE_FLOAT(RC1_TRIM, 1500.0f); diff --git a/apps/sensors/sensors.cpp b/apps/sensors/sensors.cpp index 2cf3b92ef7..ab8818b40c 100644 --- a/apps/sensors/sensors.cpp +++ b/apps/sensors/sensors.cpp @@ -158,7 +158,7 @@ private: int _rc_sub; /**< raw rc channels data subscription */ int _baro_sub; /**< raw baro data subscription */ int _airspeed_sub; /**< airspeed subscription */ - int _differential_pressure_sub; /**< raw differential pressure subscription */ + int _diff_pres_sub; /**< raw differential pressure subscription */ int _vstatus_sub; /**< vehicle status subscription */ int _params_sub; /**< notification of parameter updates */ int _manual_control_sub; /**< notification of manual control updates */ @@ -168,14 +168,14 @@ private: orb_advert_t _rc_pub; /**< raw r/c control topic */ orb_advert_t _battery_pub; /**< battery status */ orb_advert_t _airspeed_pub; /**< airspeed */ - orb_advert_t _differential_pressure_pub; /**< differential_pressure */ + orb_advert_t _diff_pres_pub; /**< differential_pressure */ perf_counter_t _loop_perf; /**< loop performance counter */ struct rc_channels_s _rc; /**< r/c channel data */ struct battery_status_s _battery_status; /**< battery status */ struct baro_report _barometer; /**< barometer data */ - struct differential_pressure_s _differential_pressure; + struct differential_pressure_s _diff_pres; struct airspeed_s _airspeed; struct { @@ -341,7 +341,7 @@ private: * @param raw Combined sensor data structure into which * data should be returned. */ - void differential_pressure_poll(struct sensor_combined_s &raw); + void diff_pres_poll(struct sensor_combined_s &raw); /** * Check for changes in vehicle status. @@ -411,7 +411,7 @@ Sensors::Sensors() : _rc_pub(-1), _battery_pub(-1), _airspeed_pub(-1), - _differential_pressure_pub(-1), + _diff_pres_pub(-1), /* performance counters */ _loop_perf(perf_alloc(PC_ELAPSED, "sensor task update")) @@ -496,8 +496,8 @@ Sensors::Sensors() : _parameter_handles.mag_scale[1] = param_find("SENS_MAG_YSCALE"); _parameter_handles.mag_scale[2] = param_find("SENS_MAG_ZSCALE"); - /*Airspeed offset */ - _parameter_handles.airspeed_offset = param_find("SENS_VAIR_OFF"); + /* Differential pressure offset */ + _parameter_handles.airspeed_offset = param_find("SENS_DPRES_OFF"); _parameter_handles.battery_voltage_scaling = param_find("BAT_V_SCALING"); @@ -902,22 +902,22 @@ Sensors::baro_poll(struct sensor_combined_s &raw) } void -Sensors::differential_pressure_poll(struct sensor_combined_s &raw) +Sensors::diff_pres_poll(struct sensor_combined_s &raw) { bool updated; - orb_check(_differential_pressure_sub, &updated); + orb_check(_diff_pres_sub, &updated); if (updated) { - orb_copy(ORB_ID(differential_pressure), _differential_pressure_sub, &_differential_pressure); + orb_copy(ORB_ID(differential_pressure), _diff_pres_sub, &_diff_pres); - float airspeed_true = calc_true_airspeed(_differential_pressure.differential_pressure_pa + raw.baro_pres_mbar*1e2f, + float airspeed_true = calc_true_airspeed(_diff_pres.differential_pressure_pa + raw.baro_pres_mbar*1e2f, raw.baro_pres_mbar*1e2f, raw.baro_temp_celcius - 5.0f); //factor 1e2 for conversion from mBar to Pa // XXX HACK - true temperature is much less than indicated temperature in baro, // subtract 5 degrees in an attempt to account for the electrical upheating of the PCB - float airspeed_indicated = calc_indicated_airspeed(_differential_pressure.differential_pressure_pa); + float airspeed_indicated = calc_indicated_airspeed(_diff_pres.differential_pressure_pa); - raw.differential_pressure_pa = _differential_pressure.differential_pressure_pa; + raw.differential_pressure_pa = _diff_pres.differential_pressure_pa; raw.differential_pressure_counter++; } } @@ -1082,16 +1082,16 @@ Sensors::adc_poll(struct sensor_combined_s &raw) float diff_pres_pa = voltage * 1000.0f - _parameters.airspeed_offset; //for MPXV7002DP sensor - _differential_pressure.timestamp = hrt_absolute_time(); - _differential_pressure.differential_pressure_pa = diff_pres_pa; - _differential_pressure.voltage = voltage; + _diff_pres.timestamp = hrt_absolute_time(); + _diff_pres.differential_pressure_pa = diff_pres_pa; + _diff_pres.voltage = voltage; /* announce the airspeed if needed, just publish else */ - if (_differential_pressure_pub > 0) { - orb_publish(ORB_ID(differential_pressure), _differential_pressure_pub, &_differential_pressure); + if (_diff_pres_pub > 0) { + orb_publish(ORB_ID(differential_pressure), _diff_pres_pub, &_diff_pres); } else { - _differential_pressure_pub = orb_advertise(ORB_ID(differential_pressure), &_differential_pressure); + _diff_pres_pub = orb_advertise(ORB_ID(differential_pressure), &_diff_pres); } } } @@ -1356,7 +1356,7 @@ Sensors::task_main() gyro_poll(raw); mag_poll(raw); baro_poll(raw); - differential_pressure_poll(raw); + diff_pres_poll(raw); parameter_update_poll(true /* forced */); diff --git a/apps/uORB/topics/sensor_combined.h b/apps/uORB/topics/sensor_combined.h index ad88e4b6e1..9a76b51829 100644 --- a/apps/uORB/topics/sensor_combined.h +++ b/apps/uORB/topics/sensor_combined.h @@ -103,7 +103,7 @@ struct sensor_combined_s { float mcu_temp_celcius; /**< Internal temperature measurement of MCU */ uint32_t baro_counter; /**< Number of raw baro measurements taken */ - float differential_pressure_pa; /**< Airspeed sensor differential pressure */ + float differential_pressure_pa; /**< Airspeed sensor differential pressure */ uint32_t differential_pressure_counter; /**< Number of raw differential pressure measurements taken */ }; From 853ba612b132f0a8f41fae1dbadc68ef3960f0d0 Mon Sep 17 00:00:00 2001 From: Simon Wilks Date: Fri, 19 Apr 2013 18:28:47 +0200 Subject: [PATCH 09/84] Add missing uORB topic --- apps/uORB/topics/airspeed.h | 67 +++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 apps/uORB/topics/airspeed.h diff --git a/apps/uORB/topics/airspeed.h b/apps/uORB/topics/airspeed.h new file mode 100644 index 0000000000..a3da3758fd --- /dev/null +++ b/apps/uORB/topics/airspeed.h @@ -0,0 +1,67 @@ +/**************************************************************************** + * + * Copyright (C) 2012-2013 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/** + * @file airspeed.h + * + * Definition of airspeed topic + */ + +#ifndef TOPIC_AIRSPEED_H_ +#define TOPIC_AIRSPEED_H_ + +#include "../uORB.h" +#include + +/** + * @addtogroup topics + * @{ + */ + +/** + * Airspeed + */ +struct airspeed_s { + uint64_t timestamp; /**< microseconds since system boot, needed to integrate */ + float indicated_airspeed_m_s; /**< indicated airspeed in meters per second, -1 if unknown */ + float true_airspeed_m_s; /**< true airspeed in meters per second, -1 if unknown */ +}; + +/** + * @} + */ + +/* register this as object request broker structure */ +ORB_DECLARE(airspeed); + +#endif From 48f815860b5900f3770486d88aea9084c75441e0 Mon Sep 17 00:00:00 2001 From: Simon Wilks Date: Sun, 21 Apr 2013 01:29:07 +0200 Subject: [PATCH 10/84] Debugging, cleanup and added airspeed to HoTT telemetry. --- apps/drivers/ets_airspeed/ets_airspeed.cpp | 31 ++++++++++++++++------ apps/hott_telemetry/messages.c | 12 +++++++++ apps/sensors/sensor_params.c | 2 +- apps/sensors/sensors.cpp | 30 +++++++++++++++------ apps/uORB/topics/differential_pressure.h | 7 ++--- 5 files changed, 62 insertions(+), 20 deletions(-) diff --git a/apps/drivers/ets_airspeed/ets_airspeed.cpp b/apps/drivers/ets_airspeed/ets_airspeed.cpp index 943848d438..276f4bf593 100644 --- a/apps/drivers/ets_airspeed/ets_airspeed.cpp +++ b/apps/drivers/ets_airspeed/ets_airspeed.cpp @@ -81,7 +81,11 @@ #define READ_CMD 0x07 /* Read the data */ /* Max measurement rate is 100Hz */ -#define CONVERSION_INTERVAL (1000000 / 10) /* microseconds */ +#define CONVERSION_INTERVAL (1000000 / 100) /* microseconds */ + +/* The Eagle Tree Airspeed V3 can only provide accurate readings + for speeds from 15km/h upwards. */ +#define MIN_ACCURATE_DIFF_PRES_PA 12 /* oddly, ERROR is not defined for c++ */ #ifdef ERROR @@ -222,6 +226,8 @@ ETS_AIRSPEED::init() /* allocate basic report buffers */ _num_reports = 2; _reports = new struct differential_pressure_s[_num_reports]; + for (int i = 0; i < _num_reports; i++) + _reports[i].max_differential_pressure_pa = 0; if (_reports == nullptr) goto out; @@ -235,8 +241,6 @@ ETS_AIRSPEED::init() if (_airspeed_pub < 0) debug("failed to create airspeed sensor object. Did you start uOrb?"); - param_get(param_find("SENS_DPRES_OFF"), &_diff_pres_offset); - ret = OK; /* sensor is ok, but we don't really know if it is within range */ _sensor_ok = true; @@ -454,13 +458,24 @@ ETS_AIRSPEED::collect() uint16_t diff_pres_pa = val[1] << 8 | val[0]; - /* adjust if necessary */ - diff_pres_pa -= _diff_pres_offset; - //log("measurement: %0.2f m/s", calc_indicated_airspeed((float)_reports[_next_report].diff_pressure)); + param_get(param_find("SENS_DPRES_OFF"), &_diff_pres_offset); + if (diff_pres_pa < _diff_pres_offset + MIN_ACCURATE_DIFF_PRES_PA) { + diff_pres_pa = 0; + } else { + diff_pres_pa -= _diff_pres_offset; + } + + // XXX we may want to smooth out the readings to remove noise. + _reports[_next_report].timestamp = hrt_absolute_time(); _reports[_next_report].differential_pressure_pa = diff_pres_pa; + // Track maximum differential pressure measured (so we can work out top speed). + if (diff_pres_pa > _reports[_next_report].max_differential_pressure_pa) { + _reports[_next_report].max_differential_pressure_pa = diff_pres_pa; + } + /* announce the airspeed if needed, just publish else */ orb_publish(ORB_ID(differential_pressure), _airspeed_pub, &_reports[_next_report]); @@ -684,7 +699,7 @@ test() err(1, "immediate read failed"); warnx("single read"); - warnx("diff pressure: %0.3f pa", (double) report.differential_pressure_pa); + warnx("diff pressure: %d pa", report.differential_pressure_pa); /* start the sensor polling at 2Hz */ if (OK != ioctl(fd, SENSORIOCSPOLLRATE, 2)) @@ -709,7 +724,7 @@ test() err(1, "periodic read failed"); warnx("periodic read %u", i); - warnx("diff pressure: %0.3f pa", (double) report.differential_pressure_pa); + warnx("diff pressure: %d pa", report.differential_pressure_pa); } errx(0, "PASS"); diff --git a/apps/hott_telemetry/messages.c b/apps/hott_telemetry/messages.c index 8bfb997737..0e466e8209 100644 --- a/apps/hott_telemetry/messages.c +++ b/apps/hott_telemetry/messages.c @@ -42,9 +42,11 @@ #include #include #include +#include #include #include +static int airspeed_sub = -1; static int battery_sub = -1; static int sensor_sub = -1; @@ -52,6 +54,7 @@ void messages_init(void) { battery_sub = orb_subscribe(ORB_ID(battery_status)); sensor_sub = orb_subscribe(ORB_ID(sensor_combined)); + airspeed_sub = orb_subscribe(ORB_ID(airspeed)); } void build_eam_response(uint8_t *buffer, int *size) @@ -81,6 +84,15 @@ void build_eam_response(uint8_t *buffer, int *size) msg.altitude_L = (uint8_t)alt & 0xff; msg.altitude_H = (uint8_t)(alt >> 8) & 0xff; + /* get a local copy of the current sensor values */ + struct airspeed_s airspeed; + memset(&airspeed, 0, sizeof(airspeed)); + orb_copy(ORB_ID(airspeed), airspeed_sub, &airspeed); + + uint16_t speed = (uint16_t)(airspeed.indicated_airspeed_m_s * 3.6); + msg.speed_L = (uint8_t)speed & 0xff; + msg.speed_H = (uint8_t)(speed >> 8) & 0xff; + msg.stop = STOP_BYTE; memcpy(buffer, &msg, *size); diff --git a/apps/sensors/sensor_params.c b/apps/sensors/sensor_params.c index da2dfcca67..0bab992a78 100644 --- a/apps/sensors/sensor_params.c +++ b/apps/sensors/sensor_params.c @@ -64,7 +64,7 @@ PARAM_DEFINE_FLOAT(SENS_ACC_XSCALE, 1.0f); PARAM_DEFINE_FLOAT(SENS_ACC_YSCALE, 1.0f); PARAM_DEFINE_FLOAT(SENS_ACC_ZSCALE, 1.0f); -PARAM_DEFINE_FLOAT(SENS_DPRES_OFF, 2.5f); +PARAM_DEFINE_INT32(SENS_DPRES_OFF, 1667); PARAM_DEFINE_FLOAT(RC1_MIN, 1000.0f); PARAM_DEFINE_FLOAT(RC1_TRIM, 1500.0f); diff --git a/apps/sensors/sensors.cpp b/apps/sensors/sensors.cpp index ab8818b40c..fcd1d869f9 100644 --- a/apps/sensors/sensors.cpp +++ b/apps/sensors/sensors.cpp @@ -192,7 +192,7 @@ private: float mag_scale[3]; float accel_offset[3]; float accel_scale[3]; - float airspeed_offset; + int diff_pres_offset_pa; int rc_type; @@ -241,7 +241,7 @@ private: param_t accel_scale[3]; param_t mag_offset[3]; param_t mag_scale[3]; - param_t airspeed_offset; + param_t diff_pres_offset_pa; param_t rc_map_roll; param_t rc_map_pitch; @@ -497,7 +497,7 @@ Sensors::Sensors() : _parameter_handles.mag_scale[2] = param_find("SENS_MAG_ZSCALE"); /* Differential pressure offset */ - _parameter_handles.airspeed_offset = param_find("SENS_DPRES_OFF"); + _parameter_handles.diff_pres_offset_pa = param_find("SENS_DPRES_OFF"); _parameter_handles.battery_voltage_scaling = param_find("BAT_V_SCALING"); @@ -707,7 +707,7 @@ Sensors::parameters_update() param_get(_parameter_handles.mag_scale[2], &(_parameters.mag_scale[2])); /* Airspeed offset */ - param_get(_parameter_handles.airspeed_offset, &(_parameters.airspeed_offset)); + param_get(_parameter_handles.diff_pres_offset_pa, &(_parameters.diff_pres_offset_pa)); /* scaling of ADC ticks to battery voltage */ if (param_get(_parameter_handles.battery_voltage_scaling, &(_parameters.battery_voltage_scaling)) != OK) { @@ -910,15 +910,26 @@ Sensors::diff_pres_poll(struct sensor_combined_s &raw) if (updated) { orb_copy(ORB_ID(differential_pressure), _diff_pres_sub, &_diff_pres); + raw.differential_pressure_pa = _diff_pres.differential_pressure_pa; + raw.differential_pressure_counter++; + float airspeed_true = calc_true_airspeed(_diff_pres.differential_pressure_pa + raw.baro_pres_mbar*1e2f, raw.baro_pres_mbar*1e2f, raw.baro_temp_celcius - 5.0f); //factor 1e2 for conversion from mBar to Pa // XXX HACK - true temperature is much less than indicated temperature in baro, // subtract 5 degrees in an attempt to account for the electrical upheating of the PCB float airspeed_indicated = calc_indicated_airspeed(_diff_pres.differential_pressure_pa); - - raw.differential_pressure_pa = _diff_pres.differential_pressure_pa; - raw.differential_pressure_counter++; + + _airspeed.indicated_airspeed_m_s = airspeed_indicated; + _airspeed.true_airspeed_m_s = airspeed_true; + + /* announce the airspeed if needed, just publish else */ + if (_airspeed_pub > 0) { + orb_publish(ORB_ID(airspeed), _airspeed_pub, &_airspeed); + + } else { + _airspeed_pub = orb_advertise(ORB_ID(airspeed), &_airspeed); + } } } @@ -1080,7 +1091,7 @@ Sensors::adc_poll(struct sensor_combined_s &raw) */ if (voltage > 0.4f) { - float diff_pres_pa = voltage * 1000.0f - _parameters.airspeed_offset; //for MPXV7002DP sensor + float diff_pres_pa = voltage * 1000.0f - _parameters.diff_pres_offset_pa; //for MPXV7002DP sensor _diff_pres.timestamp = hrt_absolute_time(); _diff_pres.differential_pressure_pa = diff_pres_pa; @@ -1330,6 +1341,7 @@ Sensors::task_main() _mag_sub = orb_subscribe(ORB_ID(sensor_mag)); _rc_sub = orb_subscribe(ORB_ID(input_rc)); _baro_sub = orb_subscribe(ORB_ID(sensor_baro)); + _diff_pres_sub = orb_subscribe(ORB_ID(differential_pressure)); _vstatus_sub = orb_subscribe(ORB_ID(vehicle_status)); _params_sub = orb_subscribe(ORB_ID(parameter_update)); _manual_control_sub = orb_subscribe(ORB_ID(manual_control_setpoint)); @@ -1405,6 +1417,8 @@ Sensors::task_main() /* check battery voltage */ adc_poll(raw); + diff_pres_poll(raw); + /* Inform other processes that new data is available to copy */ if (_publishing) orb_publish(ORB_ID(sensor_combined), _sensor_pub, &raw); diff --git a/apps/uORB/topics/differential_pressure.h b/apps/uORB/topics/differential_pressure.h index ac52206192..8ce85213be 100644 --- a/apps/uORB/topics/differential_pressure.h +++ b/apps/uORB/topics/differential_pressure.h @@ -52,9 +52,10 @@ * Differential pressure. */ struct differential_pressure_s { - uint64_t timestamp; /**< microseconds since system boot, needed to integrate */ - float differential_pressure_pa; /**< Differential pressure reading */ - float voltage; /**< Voltage from analog airspeed sensors (voltage divider already compensated) */ + uint64_t timestamp; /**< microseconds since system boot, needed to integrate */ + uint16_t differential_pressure_pa; /**< Differential pressure reading */ + uint16_t max_differential_pressure_pa; /**< Maximum differential pressure reading */ + float voltage; /**< Voltage from analog airspeed sensors (voltage divider already compensated) */ }; From 715e3e2ebe0546edfa8c053ff90f4f1fdc521da7 Mon Sep 17 00:00:00 2001 From: Simon Wilks Date: Mon, 22 Apr 2013 08:51:49 +0200 Subject: [PATCH 11/84] Cleanup --- apps/drivers/drv_airspeed.h | 14 -------------- apps/drivers/ets_airspeed/ets_airspeed.cpp | 17 ++++++++++------- apps/sensors/sensors.cpp | 18 +++++++++--------- 3 files changed, 19 insertions(+), 30 deletions(-) diff --git a/apps/drivers/drv_airspeed.h b/apps/drivers/drv_airspeed.h index 269ee45591..54213c0754 100644 --- a/apps/drivers/drv_airspeed.h +++ b/apps/drivers/drv_airspeed.h @@ -46,20 +46,6 @@ #define AIRSPEED_DEVICE_PATH "/dev/airspeed" -/** - * Airspeed report structure. Reads from the device must be in multiples of this - * structure. - */ -//struct airspeed_report { -// uint64_t timestamp; -// uint8_t diff_pressure; /** differential pressure in Pa */ -//}; - -/* - * ObjDev tag for raw range finder data. - */ -//ORB_DECLARE(sensor_differential_pressure); - /* * ioctl() definitions * diff --git a/apps/drivers/ets_airspeed/ets_airspeed.cpp b/apps/drivers/ets_airspeed/ets_airspeed.cpp index 276f4bf593..88e0fbb13f 100644 --- a/apps/drivers/ets_airspeed/ets_airspeed.cpp +++ b/apps/drivers/ets_airspeed/ets_airspeed.cpp @@ -74,20 +74,22 @@ #include /* Configuration Constants */ -#define I2C_BUS PX4_I2C_BUS_ESC +#define I2C_BUS PX4_I2C_BUS_ESC // XXX Replace with PX4_I2C_BUS_EXPANSION before submitting. #define I2C_ADDRESS 0x75 /* ETS_AIRSPEED Registers addresses */ #define READ_CMD 0x07 /* Read the data */ -/* Max measurement rate is 100Hz */ +/* Measurement rate is 100Hz */ #define CONVERSION_INTERVAL (1000000 / 100) /* microseconds */ -/* The Eagle Tree Airspeed V3 can only provide accurate readings - for speeds from 15km/h upwards. */ +/** + * The Eagle Tree Airspeed V3 can only provide accurate readings + * for speeds from 15km/h upwards. + */ #define MIN_ACCURATE_DIFF_PRES_PA 12 -/* oddly, ERROR is not defined for c++ */ +/* Oddly, ERROR is not defined for C++ */ #ifdef ERROR # undef ERROR #endif @@ -109,8 +111,8 @@ public: virtual int ioctl(struct file *filp, int cmd, unsigned long arg); /** - * Diagnostics - print some basic information about the driver. - */ + * Diagnostics - print some basic information about the driver. + */ void print_info(); protected: @@ -163,6 +165,7 @@ private: void cycle(); int measure(); int collect(); + /** * Static trampoline from the workq context; because we don't have a * generic workq wrapper yet. diff --git a/apps/sensors/sensors.cpp b/apps/sensors/sensors.cpp index fcd1d869f9..8b6f184737 100644 --- a/apps/sensors/sensors.cpp +++ b/apps/sensors/sensors.cpp @@ -99,6 +99,12 @@ #define BAT_VOL_LOWPASS_2 0.01f #define VOLTAGE_BATTERY_IGNORE_THRESHOLD_VOLTS 3.5f +/** + * HACK - true temperature is much less than indicated temperature in baro, + * subtract 5 degrees in an attempt to account for the electrical upheating of the PCB + */ +#define PCB_TEMP_ESTIMATE_DEG 5.0f + #define PPM_INPUT_TIMEOUT_INTERVAL 50000 /**< 50 ms timeout / 20 Hz */ #define limit_minus_one_to_one(arg) (arg < -1.0f) ? -1.0f : ((arg > 1.0f) ? 1.0f : arg) @@ -913,15 +919,9 @@ Sensors::diff_pres_poll(struct sensor_combined_s &raw) raw.differential_pressure_pa = _diff_pres.differential_pressure_pa; raw.differential_pressure_counter++; - float airspeed_true = calc_true_airspeed(_diff_pres.differential_pressure_pa + raw.baro_pres_mbar*1e2f, - raw.baro_pres_mbar*1e2f, raw.baro_temp_celcius - 5.0f); //factor 1e2 for conversion from mBar to Pa - // XXX HACK - true temperature is much less than indicated temperature in baro, - // subtract 5 degrees in an attempt to account for the electrical upheating of the PCB - - float airspeed_indicated = calc_indicated_airspeed(_diff_pres.differential_pressure_pa); - - _airspeed.indicated_airspeed_m_s = airspeed_indicated; - _airspeed.true_airspeed_m_s = airspeed_true; + _airspeed.indicated_airspeed_m_s = calc_indicated_airspeed(_diff_pres.differential_pressure_pa); + _airspeed.true_airspeed_m_s = calc_true_airspeed(_diff_pres.differential_pressure_pa + raw.baro_pres_mbar*1e2f, + raw.baro_pres_mbar*1e2f, raw.baro_temp_celcius - PCB_TEMP_ESTIMATE_DEG); /* announce the airspeed if needed, just publish else */ if (_airspeed_pub > 0) { From ad212ee628cd08c5c063757e4a5a2edc82392f3b Mon Sep 17 00:00:00 2001 From: Simon Wilks Date: Mon, 22 Apr 2013 15:00:15 +0200 Subject: [PATCH 12/84] More cleanups --- apps/drivers/ets_airspeed/ets_airspeed.cpp | 65 +++++++++++++++------- 1 file changed, 45 insertions(+), 20 deletions(-) diff --git a/apps/drivers/ets_airspeed/ets_airspeed.cpp b/apps/drivers/ets_airspeed/ets_airspeed.cpp index 88e0fbb13f..cede0534d1 100644 --- a/apps/drivers/ets_airspeed/ets_airspeed.cpp +++ b/apps/drivers/ets_airspeed/ets_airspeed.cpp @@ -73,22 +73,23 @@ #include #include -/* Configuration Constants */ -#define I2C_BUS PX4_I2C_BUS_ESC // XXX Replace with PX4_I2C_BUS_EXPANSION before submitting. -#define I2C_ADDRESS 0x75 +/* Default I2C bus */ +#define PX4_I2C_BUS_DEFAULT PX4_I2C_BUS_EXPANSION -/* ETS_AIRSPEED Registers addresses */ -#define READ_CMD 0x07 /* Read the data */ +/* I2C bus address */ +#define I2C_ADDRESS 0x75 /* 7-bit address. 8-bit address is 0xEA */ + +/* Register address */ +#define READ_CMD 0x07 /* Read the data */ -/* Measurement rate is 100Hz */ -#define CONVERSION_INTERVAL (1000000 / 100) /* microseconds */ - /** - * The Eagle Tree Airspeed V3 can only provide accurate readings - * for speeds from 15km/h upwards. + * The Eagle Tree Airspeed V3 cannot provide accurate reading below speeds of 15km/h. */ #define MIN_ACCURATE_DIFF_PRES_PA 12 +/* Measurement rate is 100Hz */ +#define CONVERSION_INTERVAL (1000000 / 100) /* microseconds */ + /* Oddly, ERROR is not defined for C++ */ #ifdef ERROR # undef ERROR @@ -102,7 +103,7 @@ static const int ERROR = -1; class ETS_AIRSPEED : public device::I2C { public: - ETS_AIRSPEED(int bus = I2C_BUS, int address = I2C_ADDRESS); + ETS_AIRSPEED(int bus, int address = I2C_ADDRESS); virtual ~ETS_AIRSPEED(); virtual int init(); @@ -194,11 +195,11 @@ ETS_AIRSPEED::ETS_AIRSPEED(int bus, int address) : _sensor_ok(false), _measure_ticks(0), _collect_phase(false), + _diff_pres_offset(0), _airspeed_pub(-1), _sample_perf(perf_alloc(PC_ELAPSED, "ETS_AIRSPEED_read")), _comms_errors(perf_alloc(PC_COUNT, "ETS_AIRSPEED_comms_errors")), - _buffer_overflows(perf_alloc(PC_COUNT, "ETS_AIRSPEED_buffer_overflows")), - _diff_pres_offset(0) + _buffer_overflows(perf_alloc(PC_COUNT, "ETS_AIRSPEED_buffer_overflows")) { // enable debug() calls _debug_enabled = true; @@ -229,7 +230,7 @@ ETS_AIRSPEED::init() /* allocate basic report buffers */ _num_reports = 2; _reports = new struct differential_pressure_s[_num_reports]; - for (int i = 0; i < _num_reports; i++) + for (unsigned i = 0; i < _num_reports; i++) _reports[i].max_differential_pressure_pa = 0; if (_reports == nullptr) @@ -613,7 +614,7 @@ const int ERROR = -1; ETS_AIRSPEED *g_dev; -void start(); +void start(int i2c_bus); void stop(); void test(); void reset(); @@ -623,7 +624,7 @@ void info(); * Start the driver. */ void -start() +start(int i2c_bus) { int fd; @@ -631,7 +632,7 @@ start() errx(1, "already started"); /* create the driver */ - g_dev = new ETS_AIRSPEED(I2C_BUS); + g_dev = new ETS_AIRSPEED(i2c_bus); if (g_dev == nullptr) goto fail; @@ -664,7 +665,8 @@ fail: /** * Stop the driver */ -void stop() +void +stop() { if (g_dev != nullptr) { @@ -770,14 +772,36 @@ info() } // namespace + +static void +ets_airspeed_usage() +{ + fprintf(stderr, "usage: ets_airspeed [options] command\n"); + fprintf(stderr, "options:\n"); + fprintf(stderr, "\t-b --bus i2cbus (%d)\n", PX4_I2C_BUS_DEFAULT); + fprintf(stderr, "command:\n"); + fprintf(stderr, "\tstart|stop|reset|test|info\n"); +} + int ets_airspeed_main(int argc, char *argv[]) { + int i2c_bus = PX4_I2C_BUS_DEFAULT; + + int i; + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-b") == 0 || strcmp(argv[i], "--bus") == 0) { + if (argc > i + 1) { + i2c_bus = atoi(argv[i + 1]); + } + } + } + /* * Start/load the driver. */ if (!strcmp(argv[1], "start")) - ets_airspeed::start(); + ets_airspeed::start(i2c_bus); /* * Stop the driver @@ -803,5 +827,6 @@ ets_airspeed_main(int argc, char *argv[]) if (!strcmp(argv[1], "info") || !strcmp(argv[1], "status")) ets_airspeed::info(); - errx(1, "unrecognized command, try 'start', 'test', 'reset' or 'info'"); + ets_airspeed_usage(); + exit(0); } From 24630f15b6d0b465bd62f1105def4e96ffc92e10 Mon Sep 17 00:00:00 2001 From: Simon Wilks Date: Mon, 22 Apr 2013 21:30:20 +0200 Subject: [PATCH 13/84] Yet more cleanups. --- apps/drivers/drv_airspeed.h | 1 + apps/drivers/ets_airspeed/Makefile | 2 +- apps/drivers/ets_airspeed/ets_airspeed.cpp | 8 ++++---- apps/px4io/controls.c | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/drivers/drv_airspeed.h b/apps/drivers/drv_airspeed.h index 54213c0754..bffc35c62c 100644 --- a/apps/drivers/drv_airspeed.h +++ b/apps/drivers/drv_airspeed.h @@ -33,6 +33,7 @@ /** * @file Airspeed driver interface. + * @author Simon Wilks */ #ifndef _DRV_AIRSPEED_H diff --git a/apps/drivers/ets_airspeed/Makefile b/apps/drivers/ets_airspeed/Makefile index 9089d97af2..f6639b470c 100644 --- a/apps/drivers/ets_airspeed/Makefile +++ b/apps/drivers/ets_airspeed/Makefile @@ -37,6 +37,6 @@ APPNAME = ets_airspeed PRIORITY = SCHED_PRIORITY_DEFAULT -STACKSIZE = 2048 +STACKSIZE = 1024 include $(APPDIR)/mk/app.mk diff --git a/apps/drivers/ets_airspeed/ets_airspeed.cpp b/apps/drivers/ets_airspeed/ets_airspeed.cpp index cede0534d1..5bff4c7203 100644 --- a/apps/drivers/ets_airspeed/ets_airspeed.cpp +++ b/apps/drivers/ets_airspeed/ets_airspeed.cpp @@ -32,7 +32,7 @@ ****************************************************************************/ /** - * @file airspeed.cpp + * @file ets_airspeed.cpp * @author Simon Wilks * * Driver for the Eagle Tree Airspeed V3 connected via I2C. @@ -197,9 +197,9 @@ ETS_AIRSPEED::ETS_AIRSPEED(int bus, int address) : _collect_phase(false), _diff_pres_offset(0), _airspeed_pub(-1), - _sample_perf(perf_alloc(PC_ELAPSED, "ETS_AIRSPEED_read")), - _comms_errors(perf_alloc(PC_COUNT, "ETS_AIRSPEED_comms_errors")), - _buffer_overflows(perf_alloc(PC_COUNT, "ETS_AIRSPEED_buffer_overflows")) + _sample_perf(perf_alloc(PC_ELAPSED, "ets_airspeed_read")), + _comms_errors(perf_alloc(PC_COUNT, "ets_airspeed_comms_errors")), + _buffer_overflows(perf_alloc(PC_COUNT, "ets_airspeed_buffer_overflows")) { // enable debug() calls _debug_enabled = true; diff --git a/apps/px4io/controls.c b/apps/px4io/controls.c index e519830710..dc36f6c934 100644 --- a/apps/px4io/controls.c +++ b/apps/px4io/controls.c @@ -70,7 +70,7 @@ controls_init(void) unsigned base = PX4IO_P_RC_CONFIG_STRIDE * i; r_page_rc_input_config[base + PX4IO_P_RC_CONFIG_OPTIONS] = 0; - r_page_rc_input_config[base + PX4IO_P_RC_CONFIG_MIN] = 950; + r_page_rc_input_config[base + PX4IO_P_RC_CONFIG_MIN] = 1000; r_page_rc_input_config[base + PX4IO_P_RC_CONFIG_CENTER] = 1500; r_page_rc_input_config[base + PX4IO_P_RC_CONFIG_MAX] = 2000; r_page_rc_input_config[base + PX4IO_P_RC_CONFIG_DEADZONE] = 30; From 5b60991c63b0c6b87632369fde73236263670448 Mon Sep 17 00:00:00 2001 From: Simon Wilks Date: Tue, 23 Apr 2013 08:49:33 +0200 Subject: [PATCH 14/84] Style fix: ETS_AIRSPEED > ETSAirspeed --- apps/drivers/ets_airspeed/ets_airspeed.cpp | 46 +++++++++++----------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/apps/drivers/ets_airspeed/ets_airspeed.cpp b/apps/drivers/ets_airspeed/ets_airspeed.cpp index 5bff4c7203..e50395e479 100644 --- a/apps/drivers/ets_airspeed/ets_airspeed.cpp +++ b/apps/drivers/ets_airspeed/ets_airspeed.cpp @@ -100,11 +100,11 @@ static const int ERROR = -1; # error This requires CONFIG_SCHED_WORKQUEUE. #endif -class ETS_AIRSPEED : public device::I2C +class ETSAirspeed : public device::I2C { public: - ETS_AIRSPEED(int bus, int address = I2C_ADDRESS); - virtual ~ETS_AIRSPEED(); + ETSAirspeed(int bus, int address = I2C_ADDRESS); + virtual ~ETSAirspeed(); virtual int init(); @@ -186,8 +186,8 @@ private: */ extern "C" __EXPORT int ets_airspeed_main(int argc, char *argv[]); -ETS_AIRSPEED::ETS_AIRSPEED(int bus, int address) : - I2C("ETS_AIRSPEED", AIRSPEED_DEVICE_PATH, bus, address, 100000), +ETSAirspeed::ETSAirspeed(int bus, int address) : + I2C("ETSAirspeed", AIRSPEED_DEVICE_PATH, bus, address, 100000), _num_reports(0), _next_report(0), _oldest_report(0), @@ -208,7 +208,7 @@ ETS_AIRSPEED::ETS_AIRSPEED(int bus, int address) : memset(&_work, 0, sizeof(_work)); } -ETS_AIRSPEED::~ETS_AIRSPEED() +ETSAirspeed::~ETSAirspeed() { /* make sure we are truly inactive */ stop(); @@ -219,7 +219,7 @@ ETS_AIRSPEED::~ETS_AIRSPEED() } int -ETS_AIRSPEED::init() +ETSAirspeed::init() { int ret = ERROR; @@ -253,13 +253,13 @@ out: } int -ETS_AIRSPEED::probe() +ETSAirspeed::probe() { return measure(); } int -ETS_AIRSPEED::ioctl(struct file *filp, int cmd, unsigned long arg) +ETSAirspeed::ioctl(struct file *filp, int cmd, unsigned long arg) { switch (cmd) { @@ -363,7 +363,7 @@ ETS_AIRSPEED::ioctl(struct file *filp, int cmd, unsigned long arg) } ssize_t -ETS_AIRSPEED::read(struct file *filp, char *buffer, size_t buflen) +ETSAirspeed::read(struct file *filp, char *buffer, size_t buflen) { unsigned count = buflen / sizeof(struct differential_pressure_s); int ret = 0; @@ -422,7 +422,7 @@ ETS_AIRSPEED::read(struct file *filp, char *buffer, size_t buflen) } int -ETS_AIRSPEED::measure() +ETSAirspeed::measure() { int ret; @@ -444,7 +444,7 @@ ETS_AIRSPEED::measure() } int -ETS_AIRSPEED::collect() +ETSAirspeed::collect() { int ret = -EIO; @@ -503,14 +503,14 @@ ETS_AIRSPEED::collect() } void -ETS_AIRSPEED::start() +ETSAirspeed::start() { /* reset the report ring and state machine */ _collect_phase = false; _oldest_report = _next_report = 0; /* schedule a cycle to start things */ - work_queue(HPWORK, &_work, (worker_t)&ETS_AIRSPEED::cycle_trampoline, this, 1); + work_queue(HPWORK, &_work, (worker_t)&ETSAirspeed::cycle_trampoline, this, 1); /* notify about state change */ struct subsystem_info_s info = { @@ -528,21 +528,21 @@ ETS_AIRSPEED::start() } void -ETS_AIRSPEED::stop() +ETSAirspeed::stop() { work_cancel(HPWORK, &_work); } void -ETS_AIRSPEED::cycle_trampoline(void *arg) +ETSAirspeed::cycle_trampoline(void *arg) { - ETS_AIRSPEED *dev = (ETS_AIRSPEED *)arg; + ETSAirspeed *dev = (ETSAirspeed *)arg; dev->cycle(); } void -ETS_AIRSPEED::cycle() +ETSAirspeed::cycle() { /* collection phase? */ if (_collect_phase) { @@ -566,7 +566,7 @@ ETS_AIRSPEED::cycle() /* schedule a fresh cycle call when we are ready to measure again */ work_queue(HPWORK, &_work, - (worker_t)&ETS_AIRSPEED::cycle_trampoline, + (worker_t)&ETSAirspeed::cycle_trampoline, this, _measure_ticks - USEC2TICK(CONVERSION_INTERVAL)); @@ -584,13 +584,13 @@ ETS_AIRSPEED::cycle() /* schedule a fresh cycle call when the measurement is done */ work_queue(HPWORK, &_work, - (worker_t)&ETS_AIRSPEED::cycle_trampoline, + (worker_t)&ETSAirspeed::cycle_trampoline, this, USEC2TICK(CONVERSION_INTERVAL)); } void -ETS_AIRSPEED::print_info() +ETSAirspeed::print_info() { perf_print_counter(_sample_perf); perf_print_counter(_comms_errors); @@ -612,7 +612,7 @@ namespace ets_airspeed #endif const int ERROR = -1; -ETS_AIRSPEED *g_dev; +ETSAirspeed *g_dev; void start(int i2c_bus); void stop(); @@ -632,7 +632,7 @@ start(int i2c_bus) errx(1, "already started"); /* create the driver */ - g_dev = new ETS_AIRSPEED(i2c_bus); + g_dev = new ETSAirspeed(i2c_bus); if (g_dev == nullptr) goto fail; From e37f471ac4ce52e724b0d89714d9db6e1d16ee8e Mon Sep 17 00:00:00 2001 From: Anton Babushkin Date: Thu, 25 Apr 2013 23:59:46 +0400 Subject: [PATCH 15/84] 6-point accelerometer calibration implemented --- apps/commander/accelerometer_calibration.c | 414 +++++++++++++++++++++ apps/commander/accelerometer_calibration.h | 19 + apps/commander/commander.c | 125 +------ 3 files changed, 435 insertions(+), 123 deletions(-) create mode 100644 apps/commander/accelerometer_calibration.c create mode 100644 apps/commander/accelerometer_calibration.h diff --git a/apps/commander/accelerometer_calibration.c b/apps/commander/accelerometer_calibration.c new file mode 100644 index 0000000000..f950398815 --- /dev/null +++ b/apps/commander/accelerometer_calibration.c @@ -0,0 +1,414 @@ +/* + * accelerometer_calibration.c + * + * Copyright (C) 2013 Anton Babushkin. All rights reserved. + * Author: Anton Babushkin + * + * Transform acceleration vector to true orientation and scale + * + * * * * Model * * * + * accel_corr = accel_T * (accel_raw - accel_offs) + * + * accel_corr[3] - fully corrected acceleration vector in body frame + * accel_T[3][3] - accelerometers transform matrix, rotation and scaling transform + * accel_raw[3] - raw acceleration vector + * accel_offs[3] - acceleration offset vector + * + * * * * Calibration * * * + * + * Reference vectors + * accel_corr_ref[6][3] = [ g 0 0 ] // nose up + * | -g 0 0 | // nose down + * | 0 g 0 | // left side down + * | 0 -g 0 | // right side down + * | 0 0 g | // on back + * [ 0 0 -g ] // level + * accel_raw_ref[6][3] + * + * accel_corr_ref[i] = accel_T * (accel_raw_ref[i] - accel_offs), i = 0...5 + * + * 6 reference vectors * 3 axes = 18 equations + * 9 (accel_T) + 3 (accel_offs) = 12 unknown constants + * + * Find accel_offs + * + * accel_offs[i] = (accel_raw_ref[i*2][i] + accel_raw_ref[i*2+1][i]) / 2 + * + * + * Find accel_T + * + * 9 unknown constants + * need 9 equations -> use 3 of 6 measurements -> 3 * 3 = 9 equations + * + * accel_corr_ref[i*2] = accel_T * (accel_raw_ref[i*2] - accel_offs), i = 0...2 + * + * Solve separate system for each row of accel_T: + * + * accel_corr_ref[j*2][i] = accel_T[i] * (accel_raw_ref[j*2] - accel_offs), j = 0...2 + * + * A * x = b + * + * x = [ accel_T[0][i] ] + * | accel_T[1][i] | + * [ accel_T[2][i] ] + * + * b = [ accel_corr_ref[0][i] ] // One measurement per axis is enough + * | accel_corr_ref[2][i] | + * [ accel_corr_ref[4][i] ] + * + * a[i][j] = accel_raw_ref[i][j] - accel_offs[j], i = 0;2;4, j = 0...2 + * + * Matrix A is common for all three systems: + * A = [ a[0][0] a[0][1] a[0][2] ] + * | a[2][0] a[2][1] a[2][2] | + * [ a[4][0] a[4][1] a[4][2] ] + * + * x = A^-1 * b + * + * accel_T = A^-1 * g + * g = 9.80665 + */ + +#include "accelerometer_calibration.h" + +#include +#include +#include +#include +#include +#include + +void do_accel_calibration(int status_pub, struct vehicle_status_s *status, int mavlink_fd) { + /* announce change */ + mavlink_log_info(mavlink_fd, "accelerometer calibration started"); + /* set to accel calibration mode */ + status->flag_preflight_accel_calibration = true; + state_machine_publish(status_pub, status, mavlink_fd); + + float accel_offs_scaled[3]; + float accel_scale[3]; + int res = do_accel_calibration_mesurements(mavlink_fd, accel_offs_scaled, accel_scale); + if (res == OK) { + /* measurements complete successfully, set parameters */ + if (param_set(param_find("SENS_ACC_XOFF"), &(accel_offs_scaled[0])) + || param_set(param_find("SENS_ACC_YOFF"), &(accel_offs_scaled[1])) + || param_set(param_find("SENS_ACC_ZOFF"), &(accel_offs_scaled[2])) + || param_set(param_find("SENS_ACC_XSCALE"), &(accel_scale[0])) + || param_set(param_find("SENS_ACC_YSCALE"), &(accel_scale[1])) + || param_set(param_find("SENS_ACC_ZSCALE"), &(accel_scale[2]))) { + mavlink_log_critical(mavlink_fd, "Setting offs or scale failed!"); + } + + int fd = open(ACCEL_DEVICE_PATH, 0); + struct accel_scale ascale = { + accel_offs_scaled[0], + accel_scale[0], + accel_offs_scaled[1], + accel_scale[1], + accel_offs_scaled[2], + accel_scale[2], + }; + + if (OK != ioctl(fd, ACCELIOCSSCALE, (long unsigned int)&ascale)) + warn("WARNING: failed to set scale / offsets for accel"); + + close(fd); + + /* auto-save to EEPROM */ + int save_ret = param_save_default(); + + if (save_ret != 0) { + warn("WARNING: auto-save of params to storage failed"); + } + + mavlink_log_info(mavlink_fd, "accel calibration done"); + + tune_confirm(); + sleep(2); + tune_confirm(); + sleep(2); + /* third beep by cal end routine */ + } else { + /* measurements error */ + mavlink_log_info(mavlink_fd, "accel calibration aborted"); + tune_error(); + sleep(2); + } + + /* exit accel calibration mode */ + status->flag_preflight_accel_calibration = false; + state_machine_publish(status_pub, status, mavlink_fd); +} + +int do_accel_calibration_mesurements(int mavlink_fd, float accel_offs_scaled[3], float accel_scale[3]) { + const int samples_num = 2500; + + int sensor_combined_sub = orb_subscribe(ORB_ID(sensor_combined)); + + int16_t accel_raw_ref[6][3]; + bool data_collected[6] = { false, false, false, false, false, false }; + const char *orientation_strs[6] = { "x+", "x-", "y+", "y-", "z+", "z-" }; + while (true) { + bool done = true; + char str[80]; + int str_ptr; + str_ptr = sprintf(str, "keep vehicle still:"); + for (int i = 0; i < 6; i++) { + if (!data_collected[i]) { + str_ptr += sprintf(&(str[str_ptr]), " %s", orientation_strs[i]); + done = false; + } + } + if (done) { + mavlink_log_info(mavlink_fd, "all accel measurements complete"); + break; + } else { + mavlink_log_info(mavlink_fd, str); + int orient = detect_orientation(mavlink_fd, sensor_combined_sub); + if (orient < 0) { + sprintf(str, "orientation detection error: %i", orient); + mavlink_log_info(mavlink_fd, str); + return ERROR; + } + mavlink_log_info(mavlink_fd, "accel measurement started"); + read_accelerometer_raw_avg(sensor_combined_sub, &(accel_raw_ref[orient][0]), samples_num); + //mavlink_log_info(mavlink_fd, "accel measurement complete"); + str_ptr = sprintf(str, "complete: %i [ %i %i %i ]", orient, accel_raw_ref[orient][0], accel_raw_ref[orient][1], accel_raw_ref[orient][2]); + mavlink_log_info(mavlink_fd, str); + data_collected[orient] = true; + tune_confirm(); + } + } + close(sensor_combined_sub); + + /* calculate offsets and rotation+scale matrix */ + int16_t accel_offs[3]; + float accel_T[3][3]; + int res = calculate_calibration_values(accel_raw_ref, accel_T, accel_offs, CONSTANTS_ONE_G); + if (res != 0) { + mavlink_log_info(mavlink_fd, "calibration values calculation error"); + return ERROR; + } + + char str[80]; + sprintf(str, "accel offsets: [ %i %i %i ]", accel_offs[0], accel_offs[1], accel_offs[2]); + mavlink_log_info(mavlink_fd, str); + //mavlink_log_info(mavlink_fd, "accel transform matrix:"); + for (int i = 0; i < 3; i++) { + //sprintf(str, "\t[ %0.6f %0.6f %0.6f ]", accel_T[i][0], accel_T[i][1], accel_T[i][2]); + //mavlink_log_info(mavlink_fd, str); + } + + /* convert raw accel offset to scaled and transform matrix to scales + * rotation part of transform matrix is not used by now */ + for (int i = 0; i < 3; i++) { + accel_offs_scaled[i] = accel_offs[i] * accel_T[i][i]; + accel_scale[i] = accel_T[i][i]; + } + + return OK; +} + +/* + * Wait for vehicle become still and detect it's orientation. + * + * @return 0..5 according to orientation when vehicle is still and ready for measurements, + * ERROR if vehicle is not still after 10s or orientation error is more than 20% + */ +int detect_orientation(int mavlink_fd, int sub_sensor_combined) { + struct sensor_combined_s sensor; + /* exponential moving average of accel */ + float accel_ema[3] = { 0.0f, 0.0f, 0.0f }; + /* max-hold dispersion of accel */ + float accel_disp[3] = { 0.0f, 0.0f, 0.0f }; + float accel_len2 = 0.0f; + /* EMA time constant in seconds*/ + float ema_len = 0.2f; + /* set "still" threshold to 0.005 m/s^2 */ + float still_thr2 = pow(0.05f / CONSTANTS_ONE_G, 2); + /* set accel error threshold to 20% of accel vector length */ + float accel_err_thr = 0.2f; + /* still time required in us */ + int64_t still_time = 2000000; + struct pollfd fds[1] = { { .fd = sub_sensor_combined, .events = POLLIN } }; + + hrt_abstime t_start = hrt_absolute_time(); + /* set deadline to 20s */ + hrt_abstime timeout = 20000000; + hrt_abstime t_timeout = t_start + timeout; + hrt_abstime t = t_start; + hrt_abstime t_prev = t_start; + hrt_abstime t_still = 0; + while (true) { + /* wait blocking for new data */ + int poll_ret = poll(fds, 1, 1000); + if (poll_ret) { + orb_copy(ORB_ID(sensor_combined), sub_sensor_combined, &sensor); + t = hrt_absolute_time(); + float dt = (t - t_prev) / 1000000.0f; + t_prev = t; + float w = dt / ema_len; + for (int i = 0; i < 3; i++) { + accel_ema[i] = accel_ema[i] * (1.0f - w) + sensor.accelerometer_raw[i] * w; + float d = (float) sensor.accelerometer_raw[i] - accel_ema[i]; + d = d * d; + accel_disp[i] = accel_disp[i] * (1.0f - w); + if (d > accel_disp[i]) + accel_disp[i] = d; + } + accel_len2 = accel_ema[0] * accel_ema[0] + accel_ema[1] * accel_ema[1] + accel_ema[2] * accel_ema[2]; + float still_thr_raw2 = still_thr2 * accel_len2; + if ( accel_disp[0] < still_thr_raw2 && + accel_disp[1] < still_thr_raw2 && + accel_disp[2] < still_thr_raw2 ) { + /* is still now */ + if (t_still == 0) { + /* first time */ + mavlink_log_info(mavlink_fd, "still"); + t_still = t; + t_timeout = t + timeout; + } else { + /* still since t_still */ + if ((int64_t) t - (int64_t) t_still > still_time) { + /* vehicle is still, exit from the loop to detection of its orientation */ + break; + } + } + } else { + /* not still, reset still start time */ + if (t_still != 0) { + mavlink_log_info(mavlink_fd, "moving"); + t_still = 0; + } + } + } else if (poll_ret == 0) { + /* any poll failure for 1s is a reason to abort */ + mavlink_log_info(mavlink_fd, "ERROR: poll failure"); + return -3; + } + if (t > t_timeout) { + mavlink_log_info(mavlink_fd, "ERROR: timeout"); + return -1; + } + } + float accel_len = sqrt(accel_len2); + float accel_err_thr_raw = accel_len * accel_err_thr; + char str[80]; + sprintf(str, "ema: [ %.1f %.1f %.1f ]", accel_ema[0], accel_ema[1], accel_ema[2]); + mavlink_log_info(mavlink_fd, str); + sprintf(str, "disp: [ %.1f %.1f %.1f ]", accel_disp[0], accel_disp[1], accel_disp[2]); + mavlink_log_info(mavlink_fd, str); + if ( fabs(accel_ema[0] - accel_len) < accel_err_thr_raw && + fabs(accel_ema[1]) < accel_err_thr_raw && + fabs(accel_ema[2]) < accel_err_thr_raw ) + return 0; // [ g, 0, 0 ] + if ( fabs(accel_ema[0] + accel_len) < accel_err_thr_raw && + fabs(accel_ema[1]) < accel_err_thr_raw && + fabs(accel_ema[2]) < accel_err_thr_raw ) + return 1; // [ -g, 0, 0 ] + if ( fabs(accel_ema[0]) < accel_err_thr_raw && + fabs(accel_ema[1] - accel_len) < accel_err_thr_raw && + fabs(accel_ema[2]) < accel_err_thr_raw ) + return 2; // [ 0, g, 0 ] + if ( fabs(accel_ema[0]) < accel_err_thr_raw && + fabs(accel_ema[1] + accel_len) < accel_err_thr_raw && + fabs(accel_ema[2]) < accel_err_thr_raw ) + return 3; // [ 0, -g, 0 ] + if ( abs(accel_ema[0]) < accel_err_thr_raw && + abs(accel_ema[1]) < accel_err_thr_raw && + abs(accel_ema[2] - accel_len) < accel_err_thr_raw ) + return 4; // [ 0, 0, g ] + if ( abs(accel_ema[0]) < accel_err_thr_raw && + abs(accel_ema[1]) < accel_err_thr_raw && + abs(accel_ema[2] + accel_len) < accel_err_thr_raw ) + return 5; // [ 0, 0, -g ] + mavlink_log_info(mavlink_fd, "ERROR: invalid orientation"); + return -2; // Can't detect orientation +} + +/* + * Read specified number of accelerometer samples, calculate average and dispersion. + */ +int read_accelerometer_raw_avg(int sensor_combined_sub, int16_t accel_avg[3], int samples_num) { + struct pollfd fds[1] = { { .fd = sensor_combined_sub, .events = POLLIN } }; + int count = 0; + int32_t accel_sum[3] = { 0, 0, 0 }; + while (count < samples_num) { + int poll_ret = poll(fds, 1, 1000); + if (poll_ret == 1) { + struct sensor_combined_s sensor; + orb_copy(ORB_ID(sensor_combined), sensor_combined_sub, &sensor); + for (int i = 0; i < 3; i++) { + accel_sum[i] += sensor.accelerometer_raw[i]; + } + count++; + } else { + return ERROR; + } + } + for (int i = 0; i < 3; i++) { + accel_avg[i] = (accel_sum[i] + count / 2) / count; + } + /* calculate dispersion */ + return OK; +} + +/* + * Convert raw values from accelerometers to m/s^2. + */ +void acceleration_raw_to_m_s2(float accel_corr[3], int16_t accel_raw[3], + float accel_T[3][3], int16_t accel_offs[3]) { + for (int i = 0; i < 3; i++) { + accel_corr[i] = 0.0f; + for (int j = 0; j < 3; j++) { + accel_corr[i] += accel_T[i][j] * (accel_raw[j] - accel_offs[j]); + } + } +} + +int mat_invert3(float src[3][3], float dst[3][3]) { + float det = src[0][0] * (src[1][1] * src[2][2] - src[1][2] * src[2][1]) - + src[0][1] * (src[1][0] * src[2][2] - src[1][2] * src[2][0]) + + src[0][2] * (src[1][0] * src[2][1] - src[1][1] * src[2][0]); + if (det == 0.0) + return -1; // Singular matrix + dst[0][0] = (src[1][1] * src[2][2] - src[1][2] * src[2][1]) / det; + dst[1][0] = (src[1][2] * src[2][0] - src[1][0] * src[2][2]) / det; + dst[2][0] = (src[1][0] * src[2][1] - src[1][1] * src[2][0]) / det; + dst[0][1] = (src[0][2] * src[2][1] - src[0][1] * src[2][2]) / det; + dst[1][1] = (src[0][0] * src[2][2] - src[0][2] * src[2][0]) / det; + dst[2][1] = (src[0][1] * src[2][0] - src[0][0] * src[2][1]) / det; + dst[0][2] = (src[0][1] * src[1][2] - src[0][2] * src[1][1]) / det; + dst[1][2] = (src[0][2] * src[1][0] - src[0][0] * src[1][2]) / det; + dst[2][2] = (src[0][0] * src[1][1] - src[0][1] * src[1][0]) / det; + return 0; +} + +int calculate_calibration_values(int16_t accel_raw_ref[6][3], + float accel_T[3][3], int16_t accel_offs[3], float g) { + /* calculate raw offsets */ + for (int i = 0; i < 3; i++) { + accel_offs[i] = (int16_t) (((int32_t) (accel_raw_ref[i * 2][i]) + + (int32_t) (accel_raw_ref[i * 2 + 1][i])) / 2); + } + /* fill matrix A for linear equations system*/ + float mat_A[3][3]; + memset(mat_A, 0, sizeof(mat_A)); + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + float a = (accel_raw_ref[i * 2][j] - accel_offs[j]); + mat_A[i][j] = a; + } + } + /* calculate inverse matrix for A */ + float mat_A_inv[3][3]; + mat_invert3(mat_A, mat_A_inv); + for (int i = 0; i < 3; i++) { + /* copy results to accel_T */ + for (int j = 0; j < 3; j++) { + /* simplify matrices mult because b has only one non-zero element == g at index i */ + accel_T[j][i] = mat_A_inv[j][i] * g; + } + } + return 0; +} diff --git a/apps/commander/accelerometer_calibration.h b/apps/commander/accelerometer_calibration.h new file mode 100644 index 0000000000..acf45b6b6e --- /dev/null +++ b/apps/commander/accelerometer_calibration.h @@ -0,0 +1,19 @@ +/* + * accelerometer_calibration.h + * + * Created on: 25.04.2013 + * Author: ton + */ + +#ifndef ACCELEROMETER_CALIBRATION_H_ +#define ACCELEROMETER_CALIBRATION_H_ + +#include +#include + +void do_accel_calibration(int status_pub, struct vehicle_status_s *status, int mavlink_fd); +int detect_orientation(int mavlink_fd, int sub_sensor_combined); +int mat_invert3(float src[3][3], float dst[3][3]); +int calculate_calibration_values(int16_t accel_raw_ref[6][3], float accel_T[3][3], int16_t accel_offs[3], float g); + +#endif /* ACCELEROMETER_CALIBRATION_H_ */ diff --git a/apps/commander/commander.c b/apps/commander/commander.c index 7c0a25f862..0f18d6cef5 100644 --- a/apps/commander/commander.c +++ b/apps/commander/commander.c @@ -94,7 +94,7 @@ #include #include "calibration_routines.h" - +#include "accelerometer_calibration.h" PARAM_DEFINE_INT32(SYS_FAILSAVE_LL, 0); /**< Go into low-level failsafe after 0 ms */ //PARAM_DEFINE_INT32(SYS_FAILSAVE_HL, 0); /**< Go into high-level failsafe after 0 ms */ @@ -158,7 +158,6 @@ static int led_off(int led); static void do_gyro_calibration(int status_pub, struct vehicle_status_s *status); static void do_mag_calibration(int status_pub, struct vehicle_status_s *status); static void do_rc_calibration(int status_pub, struct vehicle_status_s *status); -static void do_accel_calibration(int status_pub, struct vehicle_status_s *status); static void handle_command(int status_pub, struct vehicle_status_s *current_status, struct vehicle_command_s *cmd); int trigger_audio_alarm(uint8_t old_mode, uint8_t old_state, uint8_t new_mode, uint8_t new_state); @@ -666,126 +665,6 @@ void do_gyro_calibration(int status_pub, struct vehicle_status_s *status) close(sub_sensor_combined); } -void do_accel_calibration(int status_pub, struct vehicle_status_s *status) -{ - /* announce change */ - - mavlink_log_info(mavlink_fd, "keep it level and still"); - /* set to accel calibration mode */ - status->flag_preflight_accel_calibration = true; - state_machine_publish(status_pub, status, mavlink_fd); - - const int calibration_count = 2500; - - int sub_sensor_combined = orb_subscribe(ORB_ID(sensor_combined)); - struct sensor_combined_s raw; - - int calibration_counter = 0; - float accel_offset[3] = {0.0f, 0.0f, 0.0f}; - - int fd = open(ACCEL_DEVICE_PATH, 0); - struct accel_scale ascale_null = { - 0.0f, - 1.0f, - 0.0f, - 1.0f, - 0.0f, - 1.0f, - }; - - if (OK != ioctl(fd, ACCELIOCSSCALE, (long unsigned int)&ascale_null)) - warn("WARNING: failed to set scale / offsets for accel"); - - close(fd); - - while (calibration_counter < calibration_count) { - - /* wait blocking for new data */ - struct pollfd fds[1] = { { .fd = sub_sensor_combined, .events = POLLIN } }; - - int poll_ret = poll(fds, 1, 1000); - - if (poll_ret) { - orb_copy(ORB_ID(sensor_combined), sub_sensor_combined, &raw); - accel_offset[0] += raw.accelerometer_m_s2[0]; - accel_offset[1] += raw.accelerometer_m_s2[1]; - accel_offset[2] += raw.accelerometer_m_s2[2]; - calibration_counter++; - - } else if (poll_ret == 0) { - /* any poll failure for 1s is a reason to abort */ - mavlink_log_info(mavlink_fd, "acceleration calibration aborted"); - return; - } - } - - accel_offset[0] = accel_offset[0] / calibration_count; - accel_offset[1] = accel_offset[1] / calibration_count; - accel_offset[2] = accel_offset[2] / calibration_count; - - if (isfinite(accel_offset[0]) && isfinite(accel_offset[1]) && isfinite(accel_offset[2])) { - - /* add the removed length from x / y to z, since we induce a scaling issue else */ - float total_len = sqrtf(accel_offset[0] * accel_offset[0] + accel_offset[1] * accel_offset[1] + accel_offset[2] * accel_offset[2]); - - /* if length is correct, zero results here */ - accel_offset[2] = accel_offset[2] + total_len; - - float scale = 9.80665f / total_len; - - if (param_set(param_find("SENS_ACC_XOFF"), &(accel_offset[0])) - || param_set(param_find("SENS_ACC_YOFF"), &(accel_offset[1])) - || param_set(param_find("SENS_ACC_ZOFF"), &(accel_offset[2])) - || param_set(param_find("SENS_ACC_XSCALE"), &(scale)) - || param_set(param_find("SENS_ACC_YSCALE"), &(scale)) - || param_set(param_find("SENS_ACC_ZSCALE"), &(scale))) { - mavlink_log_critical(mavlink_fd, "Setting offs or scale failed!"); - } - - fd = open(ACCEL_DEVICE_PATH, 0); - struct accel_scale ascale = { - accel_offset[0], - scale, - accel_offset[1], - scale, - accel_offset[2], - scale, - }; - - if (OK != ioctl(fd, ACCELIOCSSCALE, (long unsigned int)&ascale)) - warn("WARNING: failed to set scale / offsets for accel"); - - close(fd); - - /* auto-save to EEPROM */ - int save_ret = param_save_default(); - - if (save_ret != 0) { - warn("WARNING: auto-save of params to storage failed"); - } - - //char buf[50]; - //sprintf(buf, "[cmd] accel cal: x:%8.4f y:%8.4f z:%8.4f\n", (double)accel_offset[0], (double)accel_offset[1], (double)accel_offset[2]); - //mavlink_log_info(mavlink_fd, buf); - mavlink_log_info(mavlink_fd, "accel calibration done"); - - tune_confirm(); - sleep(2); - tune_confirm(); - sleep(2); - /* third beep by cal end routine */ - - } else { - mavlink_log_info(mavlink_fd, "accel calibration FAILED (NaN)"); - } - - /* exit accel calibration mode */ - status->flag_preflight_accel_calibration = false; - state_machine_publish(status_pub, status, mavlink_fd); - - close(sub_sensor_combined); -} - void do_airspeed_calibration(int status_pub, struct vehicle_status_s *status) { /* announce change */ @@ -1040,7 +919,7 @@ void handle_command(int status_pub, struct vehicle_status_s *current_vehicle_sta if (current_status.state_machine == SYSTEM_STATE_PREFLIGHT) { mavlink_log_info(mavlink_fd, "CMD starting accel cal"); tune_confirm(); - do_accel_calibration(status_pub, ¤t_status); + do_accel_calibration(status_pub, ¤t_status, mavlink_fd); tune_confirm(); mavlink_log_info(mavlink_fd, "CMD finished accel cal"); do_state_update(status_pub, ¤t_status, mavlink_fd, SYSTEM_STATE_STANDBY); From 593e3252dd90b2437862aba1c8a54b5c6edb5600 Mon Sep 17 00:00:00 2001 From: Anton Babushkin Date: Fri, 26 Apr 2013 13:52:25 +0400 Subject: [PATCH 16/84] Added hysteresis to still detector --- apps/commander/accelerometer_calibration.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/commander/accelerometer_calibration.c b/apps/commander/accelerometer_calibration.c index f950398815..9e7a3b99e0 100644 --- a/apps/commander/accelerometer_calibration.c +++ b/apps/commander/accelerometer_calibration.c @@ -274,7 +274,9 @@ int detect_orientation(int mavlink_fd, int sub_sensor_combined) { break; } } - } else { + } else if ( accel_disp[0] > still_thr_raw2 * 2.0f || + accel_disp[1] > still_thr_raw2 * 2.0f || + accel_disp[2] > still_thr_raw2 * 2.0f) { /* not still, reset still start time */ if (t_still != 0) { mavlink_log_info(mavlink_fd, "moving"); From 26f9a1d42c6402a283a679e66236f247fd274cd2 Mon Sep 17 00:00:00 2001 From: Anton Babushkin Date: Fri, 26 Apr 2013 15:25:17 +0400 Subject: [PATCH 17/84] abs/fabs bugfix, logging cleanup --- apps/commander/accelerometer_calibration.c | 80 ++++++++-------------- 1 file changed, 29 insertions(+), 51 deletions(-) diff --git a/apps/commander/accelerometer_calibration.c b/apps/commander/accelerometer_calibration.c index 9e7a3b99e0..f607b6da69 100644 --- a/apps/commander/accelerometer_calibration.c +++ b/apps/commander/accelerometer_calibration.c @@ -80,7 +80,7 @@ void do_accel_calibration(int status_pub, struct vehicle_status_s *status, int mavlink_fd) { /* announce change */ - mavlink_log_info(mavlink_fd, "accelerometer calibration started"); + mavlink_log_info(mavlink_fd, "accel calibration started"); /* set to accel calibration mode */ status->flag_preflight_accel_calibration = true; state_machine_publish(status_pub, status, mavlink_fd); @@ -96,7 +96,7 @@ void do_accel_calibration(int status_pub, struct vehicle_status_s *status, int m || param_set(param_find("SENS_ACC_XSCALE"), &(accel_scale[0])) || param_set(param_find("SENS_ACC_YSCALE"), &(accel_scale[1])) || param_set(param_find("SENS_ACC_ZSCALE"), &(accel_scale[2]))) { - mavlink_log_critical(mavlink_fd, "Setting offs or scale failed!"); + mavlink_log_critical(mavlink_fd, "ERROR: setting offs or scale failed"); } int fd = open(ACCEL_DEVICE_PATH, 0); @@ -122,7 +122,6 @@ void do_accel_calibration(int status_pub, struct vehicle_status_s *status, int m } mavlink_log_info(mavlink_fd, "accel calibration done"); - tune_confirm(); sleep(2); tune_confirm(); @@ -142,12 +141,11 @@ void do_accel_calibration(int status_pub, struct vehicle_status_s *status, int m int do_accel_calibration_mesurements(int mavlink_fd, float accel_offs_scaled[3], float accel_scale[3]) { const int samples_num = 2500; - - int sensor_combined_sub = orb_subscribe(ORB_ID(sensor_combined)); - int16_t accel_raw_ref[6][3]; bool data_collected[6] = { false, false, false, false, false, false }; const char *orientation_strs[6] = { "x+", "x-", "y+", "y-", "z+", "z-" }; + + int sensor_combined_sub = orb_subscribe(ORB_ID(sensor_combined)); while (true) { bool done = true; char str[80]; @@ -159,25 +157,21 @@ int do_accel_calibration_mesurements(int mavlink_fd, float accel_offs_scaled[3], done = false; } } - if (done) { - mavlink_log_info(mavlink_fd, "all accel measurements complete"); + if (done) break; - } else { - mavlink_log_info(mavlink_fd, str); - int orient = detect_orientation(mavlink_fd, sensor_combined_sub); - if (orient < 0) { - sprintf(str, "orientation detection error: %i", orient); - mavlink_log_info(mavlink_fd, str); - return ERROR; - } - mavlink_log_info(mavlink_fd, "accel measurement started"); - read_accelerometer_raw_avg(sensor_combined_sub, &(accel_raw_ref[orient][0]), samples_num); - //mavlink_log_info(mavlink_fd, "accel measurement complete"); - str_ptr = sprintf(str, "complete: %i [ %i %i %i ]", orient, accel_raw_ref[orient][0], accel_raw_ref[orient][1], accel_raw_ref[orient][2]); - mavlink_log_info(mavlink_fd, str); - data_collected[orient] = true; - tune_confirm(); - } + mavlink_log_info(mavlink_fd, str); + + int orient = detect_orientation(mavlink_fd, sensor_combined_sub); + if (orient < 0) + return ERROR; + + sprintf(str, "meas started: %s", orientation_strs[orient]); + mavlink_log_info(mavlink_fd, str); + read_accelerometer_raw_avg(sensor_combined_sub, &(accel_raw_ref[orient][0]), samples_num); + str_ptr = sprintf(str, "meas result for %s: [ %i %i %i ]", orientation_strs[orient], accel_raw_ref[orient][0], accel_raw_ref[orient][1], accel_raw_ref[orient][2]); + mavlink_log_info(mavlink_fd, str); + data_collected[orient] = true; + tune_confirm(); } close(sensor_combined_sub); @@ -186,26 +180,16 @@ int do_accel_calibration_mesurements(int mavlink_fd, float accel_offs_scaled[3], float accel_T[3][3]; int res = calculate_calibration_values(accel_raw_ref, accel_T, accel_offs, CONSTANTS_ONE_G); if (res != 0) { - mavlink_log_info(mavlink_fd, "calibration values calculation error"); + mavlink_log_info(mavlink_fd, "ERROR: calibration values calc error"); return ERROR; } - char str[80]; - sprintf(str, "accel offsets: [ %i %i %i ]", accel_offs[0], accel_offs[1], accel_offs[2]); - mavlink_log_info(mavlink_fd, str); - //mavlink_log_info(mavlink_fd, "accel transform matrix:"); - for (int i = 0; i < 3; i++) { - //sprintf(str, "\t[ %0.6f %0.6f %0.6f ]", accel_T[i][0], accel_T[i][1], accel_T[i][2]); - //mavlink_log_info(mavlink_fd, str); - } - /* convert raw accel offset to scaled and transform matrix to scales * rotation part of transform matrix is not used by now */ for (int i = 0; i < 3; i++) { accel_offs_scaled[i] = accel_offs[i] * accel_T[i][i]; accel_scale[i] = accel_T[i][i]; } - return OK; } @@ -226,8 +210,8 @@ int detect_orientation(int mavlink_fd, int sub_sensor_combined) { float ema_len = 0.2f; /* set "still" threshold to 0.005 m/s^2 */ float still_thr2 = pow(0.05f / CONSTANTS_ONE_G, 2); - /* set accel error threshold to 20% of accel vector length */ - float accel_err_thr = 0.2f; + /* set accel error threshold to 30% of accel vector length */ + float accel_err_thr = 0.3f; /* still time required in us */ int64_t still_time = 2000000; struct pollfd fds[1] = { { .fd = sub_sensor_combined, .events = POLLIN } }; @@ -264,7 +248,7 @@ int detect_orientation(int mavlink_fd, int sub_sensor_combined) { /* is still now */ if (t_still == 0) { /* first time */ - mavlink_log_info(mavlink_fd, "still"); + mavlink_log_info(mavlink_fd, "still..."); t_still = t; t_timeout = t + timeout; } else { @@ -279,7 +263,7 @@ int detect_orientation(int mavlink_fd, int sub_sensor_combined) { accel_disp[2] > still_thr_raw2 * 2.0f) { /* not still, reset still start time */ if (t_still != 0) { - mavlink_log_info(mavlink_fd, "moving"); + mavlink_log_info(mavlink_fd, "moving..."); t_still = 0; } } @@ -289,17 +273,11 @@ int detect_orientation(int mavlink_fd, int sub_sensor_combined) { return -3; } if (t > t_timeout) { - mavlink_log_info(mavlink_fd, "ERROR: timeout"); return -1; } } float accel_len = sqrt(accel_len2); float accel_err_thr_raw = accel_len * accel_err_thr; - char str[80]; - sprintf(str, "ema: [ %.1f %.1f %.1f ]", accel_ema[0], accel_ema[1], accel_ema[2]); - mavlink_log_info(mavlink_fd, str); - sprintf(str, "disp: [ %.1f %.1f %.1f ]", accel_disp[0], accel_disp[1], accel_disp[2]); - mavlink_log_info(mavlink_fd, str); if ( fabs(accel_ema[0] - accel_len) < accel_err_thr_raw && fabs(accel_ema[1]) < accel_err_thr_raw && fabs(accel_ema[2]) < accel_err_thr_raw ) @@ -316,13 +294,13 @@ int detect_orientation(int mavlink_fd, int sub_sensor_combined) { fabs(accel_ema[1] + accel_len) < accel_err_thr_raw && fabs(accel_ema[2]) < accel_err_thr_raw ) return 3; // [ 0, -g, 0 ] - if ( abs(accel_ema[0]) < accel_err_thr_raw && - abs(accel_ema[1]) < accel_err_thr_raw && - abs(accel_ema[2] - accel_len) < accel_err_thr_raw ) + if ( fabs(accel_ema[0]) < accel_err_thr_raw && + fabs(accel_ema[1]) < accel_err_thr_raw && + fabs(accel_ema[2] - accel_len) < accel_err_thr_raw ) return 4; // [ 0, 0, g ] - if ( abs(accel_ema[0]) < accel_err_thr_raw && - abs(accel_ema[1]) < accel_err_thr_raw && - abs(accel_ema[2] + accel_len) < accel_err_thr_raw ) + if ( fabs(accel_ema[0]) < accel_err_thr_raw && + fabs(accel_ema[1]) < accel_err_thr_raw && + fabs(accel_ema[2] + accel_len) < accel_err_thr_raw ) return 5; // [ 0, 0, -g ] mavlink_log_info(mavlink_fd, "ERROR: invalid orientation"); return -2; // Can't detect orientation From d9f9ecb084e862bd72528d118c570533deb6eccd Mon Sep 17 00:00:00 2001 From: marco Date: Sat, 27 Apr 2013 14:46:25 +0200 Subject: [PATCH 18/84] BLCtrl 2.0 testing - currently only 8 Bit resolution - ppm added --- apps/drivers/mkblctrl/mkblctrl.cpp | 36 +++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/apps/drivers/mkblctrl/mkblctrl.cpp b/apps/drivers/mkblctrl/mkblctrl.cpp index c14fdfd1d8..664271bee5 100644 --- a/apps/drivers/mkblctrl/mkblctrl.cpp +++ b/apps/drivers/mkblctrl/mkblctrl.cpp @@ -62,9 +62,9 @@ #include #include #include - #include #include +#include #include #include @@ -76,6 +76,7 @@ #include #include +#include #define I2C_BUS_SPEED 400000 #define UPDATE_RATE 400 @@ -83,7 +84,7 @@ #define BLCTRL_BASE_ADDR 0x29 #define BLCTRL_OLD 0 #define BLCTRL_NEW 1 -#define BLCTRL_MIN_VALUE -0.984F +#define BLCTRL_MIN_VALUE -0.920F #define MOTOR_STATE_PRESENT_MASK 0x80 #define MOTOR_STATE_ERROR_MASK 0x7F #define MOTOR_SPINUP_COUNTER 2500 @@ -494,6 +495,14 @@ MK::task_main() fds[0].events = POLLIN; fds[1].fd = _t_armed; fds[1].events = POLLIN; + + // rc input, published to ORB + struct rc_input_values rc_in; + orb_advert_t to_input_rc = 0; + + memset(&rc_in, 0, sizeof(rc_in)); + rc_in.input_source = RC_INPUT_SOURCE_PX4FMU_PPM; + log("starting"); long update_rate_in_us = 0; @@ -608,6 +617,27 @@ MK::task_main() ////up_pwm_servo_arm(aa.armed && !aa.lockdown); mk_servo_arm(aa.armed && !aa.lockdown); } + + // see if we have new PPM input data + if (ppm_last_valid_decode != rc_in.timestamp) { + // we have a new PPM frame. Publish it. + rc_in.channel_count = ppm_decoded_channels; + if (rc_in.channel_count > RC_INPUT_MAX_CHANNELS) { + rc_in.channel_count = RC_INPUT_MAX_CHANNELS; + } + for (uint8_t i=0; i Date: Sun, 28 Apr 2013 14:59:42 +0200 Subject: [PATCH 19/84] Re-enabled mixer --- src/modules/px4iofirmware/controls.c | 4 ++-- src/modules/px4iofirmware/module.mk | 14 +++++++------- src/modules/px4iofirmware/px4io.c | 2 +- src/modules/px4iofirmware/px4io.h | 4 ++-- src/modules/px4iofirmware/registers.c | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/modules/px4iofirmware/controls.c b/src/modules/px4iofirmware/controls.c index 25eeca3be5..dc36f6c934 100644 --- a/src/modules/px4iofirmware/controls.c +++ b/src/modules/px4iofirmware/controls.c @@ -288,8 +288,8 @@ controls_tick() { r_status_flags |= PX4IO_P_STATUS_FLAGS_OVERRIDE; /* mix new RC input control values to servos */ - //if (dsm_updated || sbus_updated || ppm_updated) - // mixer_tick(); + if (dsm_updated || sbus_updated || ppm_updated) + mixer_tick(); } else { r_status_flags &= ~PX4IO_P_STATUS_FLAGS_OVERRIDE; diff --git a/src/modules/px4iofirmware/module.mk b/src/modules/px4iofirmware/module.mk index 53d1ec2b9f..6379366f43 100644 --- a/src/modules/px4iofirmware/module.mk +++ b/src/modules/px4iofirmware/module.mk @@ -10,10 +10,10 @@ SRCS = adc.c \ sbus.c \ ../systemlib/up_cxxinitialize.c \ ../systemlib/hx_stream.c \ - ../systemlib/perf_counter.c - -# mixer.cpp \ -# ../systemlib/mixer/mixer.cpp \ -# ../systemlib/mixer/mixer_group.cpp \ -# ../systemlib/mixer/mixer_multirotor.cpp \ -# ../systemlib/mixer/mixer_simple.cpp \ \ No newline at end of file + ../systemlib/perf_counter.c \ + mixer.cpp \ + ../systemlib/mixer/mixer.cpp \ + ../systemlib/mixer/mixer_group.cpp \ + ../systemlib/mixer/mixer_multirotor.cpp \ + ../systemlib/mixer/mixer_simple.cpp \ + \ No newline at end of file diff --git a/src/modules/px4iofirmware/px4io.c b/src/modules/px4iofirmware/px4io.c index 6244b1551c..bc8dfc1167 100644 --- a/src/modules/px4iofirmware/px4io.c +++ b/src/modules/px4iofirmware/px4io.c @@ -207,7 +207,7 @@ user_start(int argc, char *argv[]) /* kick the mixer */ perf_begin(mixer_perf); - // mixer_tick(); + mixer_tick(); perf_end(mixer_perf); /* kick the control inputs */ diff --git a/src/modules/px4iofirmware/px4io.h b/src/modules/px4iofirmware/px4io.h index 3647842c0f..272cdb7bf4 100644 --- a/src/modules/px4iofirmware/px4io.h +++ b/src/modules/px4iofirmware/px4io.h @@ -148,8 +148,8 @@ extern struct sys_state_s system_state; /* * Mixer */ -//extern void mixer_tick(void); -//extern void mixer_handle_text(const void *buffer, size_t length); +extern void mixer_tick(void); +extern void mixer_handle_text(const void *buffer, size_t length); /** * Safety switch/LED. diff --git a/src/modules/px4iofirmware/registers.c b/src/modules/px4iofirmware/registers.c index 64a87a58bc..6c09def9ee 100644 --- a/src/modules/px4iofirmware/registers.c +++ b/src/modules/px4iofirmware/registers.c @@ -245,7 +245,7 @@ registers_set(uint8_t page, uint8_t offset, const uint16_t *values, unsigned num /* handle text going to the mixer parser */ case PX4IO_PAGE_MIXERLOAD: - //mixer_handle_text(values, num_values * sizeof(*values)); + mixer_handle_text(values, num_values * sizeof(*values)); break; default: From 4109874fc84339e3ee8a794b17d8bdd131313c51 Mon Sep 17 00:00:00 2001 From: Anton Babushkin Date: Sun, 28 Apr 2013 18:04:54 +0400 Subject: [PATCH 20/84] Reset offsets/scales before calibration and use prescaled values in m/s^2 instead of raw values. --- apps/commander/accelerometer_calibration.c | 128 ++++++++++++--------- apps/commander/accelerometer_calibration.h | 3 - 2 files changed, 76 insertions(+), 55 deletions(-) diff --git a/apps/commander/accelerometer_calibration.c b/apps/commander/accelerometer_calibration.c index f607b6da69..1807369080 100644 --- a/apps/commander/accelerometer_calibration.c +++ b/apps/commander/accelerometer_calibration.c @@ -78,6 +78,13 @@ #include #include +void do_accel_calibration(int status_pub, struct vehicle_status_s *status, int mavlink_fd); +int do_accel_calibration_mesurements(int mavlink_fd, float accel_offs[3], float accel_scale[3]); +int detect_orientation(int mavlink_fd, int sub_sensor_combined); +int read_accelerometer_avg(int sensor_combined_sub, float accel_avg[3], int samples_num); +int mat_invert3(float src[3][3], float dst[3][3]); +int calculate_calibration_values(float accel_ref[6][3], float accel_T[3][3], float accel_offs[3], float g); + void do_accel_calibration(int status_pub, struct vehicle_status_s *status, int mavlink_fd) { /* announce change */ mavlink_log_info(mavlink_fd, "accel calibration started"); @@ -85,14 +92,16 @@ void do_accel_calibration(int status_pub, struct vehicle_status_s *status, int m status->flag_preflight_accel_calibration = true; state_machine_publish(status_pub, status, mavlink_fd); - float accel_offs_scaled[3]; + /* measure and calculate offsets & scales */ + float accel_offs[3]; float accel_scale[3]; - int res = do_accel_calibration_mesurements(mavlink_fd, accel_offs_scaled, accel_scale); + int res = do_accel_calibration_mesurements(mavlink_fd, accel_offs, accel_scale); + if (res == OK) { /* measurements complete successfully, set parameters */ - if (param_set(param_find("SENS_ACC_XOFF"), &(accel_offs_scaled[0])) - || param_set(param_find("SENS_ACC_YOFF"), &(accel_offs_scaled[1])) - || param_set(param_find("SENS_ACC_ZOFF"), &(accel_offs_scaled[2])) + if (param_set(param_find("SENS_ACC_XOFF"), &(accel_offs[0])) + || param_set(param_find("SENS_ACC_YOFF"), &(accel_offs[1])) + || param_set(param_find("SENS_ACC_ZOFF"), &(accel_offs[2])) || param_set(param_find("SENS_ACC_XSCALE"), &(accel_scale[0])) || param_set(param_find("SENS_ACC_YSCALE"), &(accel_scale[1])) || param_set(param_find("SENS_ACC_ZSCALE"), &(accel_scale[2]))) { @@ -101,11 +110,11 @@ void do_accel_calibration(int status_pub, struct vehicle_status_s *status, int m int fd = open(ACCEL_DEVICE_PATH, 0); struct accel_scale ascale = { - accel_offs_scaled[0], + accel_offs[0], accel_scale[0], - accel_offs_scaled[1], + accel_offs[1], accel_scale[1], - accel_offs_scaled[2], + accel_offs[2], accel_scale[2], }; @@ -139,12 +148,30 @@ void do_accel_calibration(int status_pub, struct vehicle_status_s *status, int m state_machine_publish(status_pub, status, mavlink_fd); } -int do_accel_calibration_mesurements(int mavlink_fd, float accel_offs_scaled[3], float accel_scale[3]) { +int do_accel_calibration_mesurements(int mavlink_fd, float accel_offs[3], float accel_scale[3]) { const int samples_num = 2500; - int16_t accel_raw_ref[6][3]; + float accel_ref[6][3]; bool data_collected[6] = { false, false, false, false, false, false }; const char *orientation_strs[6] = { "x+", "x-", "y+", "y-", "z+", "z-" }; + /* reset existing calibration */ + int fd = open(ACCEL_DEVICE_PATH, 0); + struct accel_scale ascale_null = { + 0.0f, + 1.0f, + 0.0f, + 1.0f, + 0.0f, + 1.0f, + }; + int ioctl_res = ioctl(fd, ACCELIOCSSCALE, (long unsigned int)&ascale_null); + close(fd); + + if (OK != ioctl_res) { + warn("ERROR: failed to set scale / offsets for accel"); + return ERROR; + } + int sensor_combined_sub = orb_subscribe(ORB_ID(sensor_combined)); while (true) { bool done = true; @@ -167,8 +194,8 @@ int do_accel_calibration_mesurements(int mavlink_fd, float accel_offs_scaled[3], sprintf(str, "meas started: %s", orientation_strs[orient]); mavlink_log_info(mavlink_fd, str); - read_accelerometer_raw_avg(sensor_combined_sub, &(accel_raw_ref[orient][0]), samples_num); - str_ptr = sprintf(str, "meas result for %s: [ %i %i %i ]", orientation_strs[orient], accel_raw_ref[orient][0], accel_raw_ref[orient][1], accel_raw_ref[orient][2]); + read_accelerometer_avg(sensor_combined_sub, &(accel_ref[orient][0]), samples_num); + str_ptr = sprintf(str, "meas result for %s: [ %.2f %.2f %.2f ]", orientation_strs[orient], accel_ref[orient][0], accel_ref[orient][1], accel_ref[orient][2]); mavlink_log_info(mavlink_fd, str); data_collected[orient] = true; tune_confirm(); @@ -176,20 +203,20 @@ int do_accel_calibration_mesurements(int mavlink_fd, float accel_offs_scaled[3], close(sensor_combined_sub); /* calculate offsets and rotation+scale matrix */ - int16_t accel_offs[3]; float accel_T[3][3]; - int res = calculate_calibration_values(accel_raw_ref, accel_T, accel_offs, CONSTANTS_ONE_G); + int res = calculate_calibration_values(accel_ref, accel_T, accel_offs, CONSTANTS_ONE_G); if (res != 0) { mavlink_log_info(mavlink_fd, "ERROR: calibration values calc error"); return ERROR; } - /* convert raw accel offset to scaled and transform matrix to scales - * rotation part of transform matrix is not used by now */ + /* convert accel transform matrix to scales, + * rotation part of transform matrix is not used by now + */ for (int i = 0; i < 3; i++) { - accel_offs_scaled[i] = accel_offs[i] * accel_T[i][i]; accel_scale[i] = accel_T[i][i]; } + return OK; } @@ -233,8 +260,8 @@ int detect_orientation(int mavlink_fd, int sub_sensor_combined) { t_prev = t; float w = dt / ema_len; for (int i = 0; i < 3; i++) { - accel_ema[i] = accel_ema[i] * (1.0f - w) + sensor.accelerometer_raw[i] * w; - float d = (float) sensor.accelerometer_raw[i] - accel_ema[i]; + accel_ema[i] = accel_ema[i] * (1.0f - w) + sensor.accelerometer_m_s2[i] * w; + float d = (float) sensor.accelerometer_m_s2[i] - accel_ema[i]; d = d * d; accel_disp[i] = accel_disp[i] * (1.0f - w); if (d > accel_disp[i]) @@ -273,9 +300,11 @@ int detect_orientation(int mavlink_fd, int sub_sensor_combined) { return -3; } if (t > t_timeout) { + mavlink_log_info(mavlink_fd, "ERROR: timeout"); return -1; } } + float accel_len = sqrt(accel_len2); float accel_err_thr_raw = accel_len * accel_err_thr; if ( fabs(accel_ema[0] - accel_len) < accel_err_thr_raw && @@ -302,56 +331,47 @@ int detect_orientation(int mavlink_fd, int sub_sensor_combined) { fabs(accel_ema[1]) < accel_err_thr_raw && fabs(accel_ema[2] + accel_len) < accel_err_thr_raw ) return 5; // [ 0, 0, -g ] + mavlink_log_info(mavlink_fd, "ERROR: invalid orientation"); + return -2; // Can't detect orientation } /* * Read specified number of accelerometer samples, calculate average and dispersion. */ -int read_accelerometer_raw_avg(int sensor_combined_sub, int16_t accel_avg[3], int samples_num) { +int read_accelerometer_avg(int sensor_combined_sub, float accel_avg[3], int samples_num) { struct pollfd fds[1] = { { .fd = sensor_combined_sub, .events = POLLIN } }; int count = 0; - int32_t accel_sum[3] = { 0, 0, 0 }; + float accel_sum[3] = { 0.0f, 0.0f, 0.0f }; + while (count < samples_num) { int poll_ret = poll(fds, 1, 1000); if (poll_ret == 1) { struct sensor_combined_s sensor; orb_copy(ORB_ID(sensor_combined), sensor_combined_sub, &sensor); - for (int i = 0; i < 3; i++) { - accel_sum[i] += sensor.accelerometer_raw[i]; - } + for (int i = 0; i < 3; i++) + accel_sum[i] += sensor.accelerometer_m_s2[i]; count++; } else { return ERROR; } } - for (int i = 0; i < 3; i++) { - accel_avg[i] = (accel_sum[i] + count / 2) / count; - } - /* calculate dispersion */ - return OK; -} -/* - * Convert raw values from accelerometers to m/s^2. - */ -void acceleration_raw_to_m_s2(float accel_corr[3], int16_t accel_raw[3], - float accel_T[3][3], int16_t accel_offs[3]) { for (int i = 0; i < 3; i++) { - accel_corr[i] = 0.0f; - for (int j = 0; j < 3; j++) { - accel_corr[i] += accel_T[i][j] * (accel_raw[j] - accel_offs[j]); - } + accel_avg[i] = accel_sum[i] / count; } + + return OK; } int mat_invert3(float src[3][3], float dst[3][3]) { float det = src[0][0] * (src[1][1] * src[2][2] - src[1][2] * src[2][1]) - - src[0][1] * (src[1][0] * src[2][2] - src[1][2] * src[2][0]) + - src[0][2] * (src[1][0] * src[2][1] - src[1][1] * src[2][0]); + src[0][1] * (src[1][0] * src[2][2] - src[1][2] * src[2][0]) + + src[0][2] * (src[1][0] * src[2][1] - src[1][1] * src[2][0]); if (det == 0.0) - return -1; // Singular matrix + return ERROR; // Singular matrix + dst[0][0] = (src[1][1] * src[2][2] - src[1][2] * src[2][1]) / det; dst[1][0] = (src[1][2] * src[2][0] - src[1][0] * src[2][2]) / det; dst[2][0] = (src[1][0] * src[2][1] - src[1][1] * src[2][0]) / det; @@ -361,34 +381,38 @@ int mat_invert3(float src[3][3], float dst[3][3]) { dst[0][2] = (src[0][1] * src[1][2] - src[0][2] * src[1][1]) / det; dst[1][2] = (src[0][2] * src[1][0] - src[0][0] * src[1][2]) / det; dst[2][2] = (src[0][0] * src[1][1] - src[0][1] * src[1][0]) / det; - return 0; + + return OK; } -int calculate_calibration_values(int16_t accel_raw_ref[6][3], - float accel_T[3][3], int16_t accel_offs[3], float g) { - /* calculate raw offsets */ +int calculate_calibration_values(float accel_ref[6][3], float accel_T[3][3], float accel_offs[3], float g) { + /* calculate offsets */ for (int i = 0; i < 3; i++) { - accel_offs[i] = (int16_t) (((int32_t) (accel_raw_ref[i * 2][i]) - + (int32_t) (accel_raw_ref[i * 2 + 1][i])) / 2); + accel_offs[i] = (accel_ref[i * 2][i] + accel_ref[i * 2 + 1][i]) / 2; } + /* fill matrix A for linear equations system*/ float mat_A[3][3]; memset(mat_A, 0, sizeof(mat_A)); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { - float a = (accel_raw_ref[i * 2][j] - accel_offs[j]); + float a = accel_ref[i * 2][j] - accel_offs[j]; mat_A[i][j] = a; } } + /* calculate inverse matrix for A */ float mat_A_inv[3][3]; - mat_invert3(mat_A, mat_A_inv); + if (mat_invert3(mat_A, mat_A_inv) != OK) + return ERROR; + + /* copy results to accel_T */ for (int i = 0; i < 3; i++) { - /* copy results to accel_T */ for (int j = 0; j < 3; j++) { /* simplify matrices mult because b has only one non-zero element == g at index i */ accel_T[j][i] = mat_A_inv[j][i] * g; } } - return 0; + + return OK; } diff --git a/apps/commander/accelerometer_calibration.h b/apps/commander/accelerometer_calibration.h index acf45b6b6e..c0169c2a13 100644 --- a/apps/commander/accelerometer_calibration.h +++ b/apps/commander/accelerometer_calibration.h @@ -12,8 +12,5 @@ #include void do_accel_calibration(int status_pub, struct vehicle_status_s *status, int mavlink_fd); -int detect_orientation(int mavlink_fd, int sub_sensor_combined); -int mat_invert3(float src[3][3], float dst[3][3]); -int calculate_calibration_values(int16_t accel_raw_ref[6][3], float accel_T[3][3], int16_t accel_offs[3], float g); #endif /* ACCELEROMETER_CALIBRATION_H_ */ From 525cc1a37c0c03edbda1ecbf9fdbc00f1b1bf0f8 Mon Sep 17 00:00:00 2001 From: Lorenz Meier Date: Sun, 28 Apr 2013 18:21:06 +0200 Subject: [PATCH 21/84] Added docs --- Documentation/control_flow.graffle | 16650 +++++++++++++++++++++++++++ 1 file changed, 16650 insertions(+) create mode 100644 Documentation/control_flow.graffle diff --git a/Documentation/control_flow.graffle b/Documentation/control_flow.graffle new file mode 100644 index 0000000000..2535231108 --- /dev/null +++ b/Documentation/control_flow.graffle @@ -0,0 +1,16650 @@ + + + + + ApplicationVersion + + com.omnigroup.OmniGraffle + 139.16.0.171715 + + CreationDate + 2013-02-22 17:51:02 +0000 + Creator + Lorenz Meier + GraphDocumentVersion + 8 + GuidesLocked + NO + GuidesVisible + YES + ImageCounter + 1 + LinksVisible + NO + MagnetsVisible + NO + MasterSheets + + ModificationDate + 2013-04-20 15:38:47 +0000 + Modifier + Lorenz Meier + NotesVisible + NO + OriginVisible + NO + PageBreaks + YES + PrintInfo + + NSBottomMargin + + float + 41 + + NSHorizonalPagination + + coded + BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG + + NSLeftMargin + + float + 18 + + NSPaperName + + string + iso-a3 + + NSPaperSize + + size + {842, 1191} + + NSPrintReverseOrientation + + int + 0 + + NSRightMargin + + float + 18 + + NSTopMargin + + float + 18 + + + ReadOnly + NO + Sheets + + + ActiveLayerIndex + 0 + AutoAdjust + + BackgroundGraphic + + Bounds + {{0, 0}, {806, 1132}} + Class + SolidGraphic + ID + 2 + Style + + shadow + + Draws + NO + + stroke + + Draws + NO + + + + BaseZoom + 0 + CanvasOrigin + {0, 0} + ColumnAlign + 1 + ColumnSpacing + 36 + DisplayScale + 1 0/72 in = 1.0000 in + GraphicsList + + + Bounds + {{320.41170773935767, 646.55758982070449}, {100, 24}} + Class + ShapedGraphic + FitText + YES + Flow + Resize + FontInfo + + Color + + w + 0 + + Font + Helvetica + Size + 12 + + ID + 46 + Line + + ID + 45 + Position + 0.49247664213180542 + RotationType + 0 + + Shape + Rectangle + Style + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 limited / checked} + + Wrap + NO + + + Class + LineGraphic + Head + + ID + 44 + + ID + 45 + Points + + {283.47949897905681, 658.66217570036315} + {459.99996984645378, 658.44980851233595} + + Style + + stroke + + HeadArrow + FilledArrow + Legacy + + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 29 + + + + Bounds + {{460.49996948242188, 640.30001831054688}, {248.00003051757812, 36}} + Class + ShapedGraphic + FontInfo + + Font + Helvetica + Size + 12 + + ID + 44 + Shape + Rectangle + Style + + stroke + + CornerRadius + 9 + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\i\fs24 \cf0 ACTUATOR_CONTROLS_EFFECTIVE_0} + + + + Bounds + {{324, 353.1875}, {120, 28}} + Class + ShapedGraphic + FitText + YES + Flow + Resize + ID + 43 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Align + 0 + Pad + 0 + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;\red68\green147\blue53;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural + +\f0\fs24 \cf2 MAVLink:\ +'MANUAL_CONTROL'} + VerticalPad + 0 + + Wrap + NO + + + Bounds + {{324, 174.5}, {129, 28}} + Class + ShapedGraphic + FitText + YES + Flow + Resize + ID + 42 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Align + 0 + Pad + 0 + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;\red68\green147\blue53;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural + +\f0\fs24 \cf2 MAVLink:\ +'RC_CHANNELS_RAW'} + VerticalPad + 0 + + Wrap + NO + + + Bounds + {{114.97958374023438, 786}, {191, 14}} + Class + ShapedGraphic + FitText + YES + Flow + Resize + ID + 40 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Pad + 0 + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;\red68\green147\blue53;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf2 MAVLink: 'SERVO_OUTPUT_RAW'} + VerticalPad + 0 + + Wrap + NO + + + Bounds + {{528.5, 689}, {112, 14}} + Class + ShapedGraphic + FitText + YES + Flow + Resize + ID + 39 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Pad + 0 + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;\red68\green147\blue53;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf2 MAVLink: 'ctrl eff 0-3'} + VerticalPad + 0 + + Wrap + NO + + + Class + LineGraphic + Head + + ID + 11 + + ID + 38 + Points + + {584.52245687751122, 125.49999965650382} + {584.56069426576869, 157.00000090441219} + + Style + + stroke + + HeadArrow + FilledArrow + Legacy + + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 37 + + + + Bounds + {{448.5, 89}, {272, 36}} + Class + ShapedGraphic + FontInfo + + Font + Helvetica + Size + 12 + + ID + 37 + Shape + Rectangle + Style + + stroke + + CornerRadius + 9 + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\i\fs24 \cf0 VEHICLE_GLOBAL_POSITION_SETPOINT /\ +VEHICLE_LOCAL_POSITION_SETPOINT} + + + + Class + LineGraphic + Head + + ID + 27 + + ID + 34 + Points + + {210.47275259888471, 495.87499981747118} + {210.43193555768113, 543.06250166479344} + + Style + + stroke + + HeadArrow + FilledArrow + Legacy + + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 10 + + + + Bounds + {{108, 737.9375}, {205, 36}} + Class + ShapedGraphic + FontInfo + + Font + Helvetica + Size + 12 + + ID + 33 + Shape + Rectangle + Style + + stroke + + CornerRadius + 9 + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\i\fs24 \cf0 ACTUATOR_OUTPUTS} + + + + Class + LineGraphic + Head + + ID + 29 + + ID + 32 + Points + + {210.46968123779743, 580.06249992316259} + {210.44442316539605, 627.25000030102035} + + Style + + stroke + + HeadArrow + FilledArrow + Legacy + + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 27 + + + + Class + LineGraphic + Head + + ID + 33 + + ID + 30 + Points + + {210.48620562018775, 690.25} + {210.49612530146715, 737.4375} + + Style + + stroke + + HeadArrow + FilledArrow + Legacy + + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 29 + + + + Bounds + {{137.97958374023438, 627.75}, {145, 62}} + Class + ShapedGraphic + FontInfo + + Font + Helvetica + Size + 12 + + ID + 29 + Shape + RoundRect + Style + + fill + + Color + + b + 1 + g + 0.814996 + r + 0.627106 + + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 Actuator Mixer} + VerticalPad + 0 + + + + Bounds + {{107.97958374023438, 543.5625}, {205, 36}} + Class + ShapedGraphic + FontInfo + + Font + Helvetica + Size + 12 + + ID + 27 + Shape + Rectangle + Style + + stroke + + CornerRadius + 9 + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\i\fs24 \cf0 ACTUATOR_CONTROLS_0} + + + + Bounds + {{394.22506405270201, 452.15000309396282}, {89, 24}} + Class + ShapedGraphic + FitText + YES + Flow + Resize + FontInfo + + Color + + w + 0 + + Font + Helvetica + Size + 12 + + ID + 25 + Line + + ID + 22 + Position + 0.5900501012802124 + RotationType + 0 + + Shape + Rectangle + Style + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 if in auto mode} + + Wrap + NO + + + Bounds + {{152.49994329565658, 397.00120984204113}, {116, 24}} + Class + ShapedGraphic + FitText + YES + Flow + Resize + FontInfo + + Color + + w + 0 + + Font + Helvetica + Size + 12 + + ID + 24 + Line + + ID + 17 + Position + 0.49406537413597107 + RotationType + 0 + + Shape + Rectangle + Style + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 if in stabilized mode} + + Wrap + NO + + + Class + LineGraphic + Head + + ID + 21 + + ID + 23 + OrthogonalBarAutomatic + + OrthogonalBarPoint + {0, 0} + OrthogonalBarPosition + -1 + Points + + {584.49994992834695, 220} + {584.4997453697481, 348.6875000000008} + + Style + + stroke + + HeadArrow + FilledArrow + Legacy + + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 11 + + + + Class + LineGraphic + Head + + ID + 10 + + ID + 22 + OrthogonalBarAutomatic + + OrthogonalBarPoint + {0, 0} + OrthogonalBarPosition + 33.206413269042969 + Points + + {583.83119320765968, 385.68717359526977} + {581, 464} + {283.49994000956832, 464.30111342104294} + + Style + + stroke + + HeadArrow + FilledArrow + Legacy + + LineType + 2 + Pattern + 2 + TailArrow + 0 + + + Tail + + ID + 21 + + + + Bounds + {{482, 349.1875}, {205, 36}} + Class + ShapedGraphic + FontInfo + + Font + Helvetica + Size + 12 + + ID + 21 + Shape + Rectangle + Style + + stroke + + CornerRadius + 9 + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\i\fs24 \cf0 VEHICLE_ATTITUDE_SETPOINT} + + + + Class + LineGraphic + Head + + ID + 10 + + ID + 17 + Points + + {210.49997491180866, 385.6875} + {210.49991091996927, 432.875} + + Style + + stroke + + HeadArrow + FilledArrow + Legacy + + LineType + 1 + Pattern + 2 + TailArrow + 0 + + + Tail + + ID + 6 + + + + Class + LineGraphic + Head + + ID + 5 + + ID + 16 + Points + + {283.49999999999511, 270.00001907176534} + {339.50000000000028, 270.00001907176534} + + Style + + stroke + + HeadArrow + FilledArrow + Legacy + + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 9 + + + + Class + LineGraphic + Head + + ID + 6 + + ID + 15 + Points + + {210.49998770563047, 301.5} + {210.49998770563047, 348.6875} + + Style + + stroke + + HeadArrow + FilledArrow + Legacy + + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 9 + + + + Class + LineGraphic + Head + + ID + 9 + + ID + 13 + Points + + {210.49171354592596, 207} + {210.49498558851923, 238.4999999999998} + + Style + + stroke + + HeadArrow + FilledArrow + Legacy + + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 4 + + + + Class + LineGraphic + Head + + ID + 4 + + ID + 12 + Points + + {210.49498558851246, 138.5000000000002} + {210.48997117702493, 170.00000000001342} + + Style + + stroke + + HeadArrow + FilledArrow + Legacy + + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 8 + + + + Bounds + {{512, 157.5}, {145, 62}} + Class + ShapedGraphic + FontInfo + + Font + Helvetica + Size + 12 + + ID + 11 + Shape + RoundRect + Style + + fill + + Color + + b + 0.999136 + g + 0.808554 + r + 0.587078 + + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 Position Controller} + VerticalPad + 0 + + + + Bounds + {{138, 433.375}, {145, 62}} + Class + ShapedGraphic + FontInfo + + Font + Helvetica + Size + 12 + + ID + 10 + Shape + RoundRect + Style + + fill + + Color + + b + 1 + g + 0.814996 + r + 0.627106 + + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 Attitude Controller} + VerticalPad + 0 + + + + Bounds + {{138, 239}, {145, 62}} + Class + ShapedGraphic + FontInfo + + Font + Helvetica + Size + 12 + + ID + 9 + Shape + RoundRect + Style + + fill + + Color + + b + 0.366082 + g + 0.639788 + r + 1 + + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 RC scaling and function mapping} + VerticalPad + 0 + + + + Bounds + {{138, 76}, {145, 62}} + Class + ShapedGraphic + FontInfo + + Font + Helvetica + Size + 12 + + ID + 8 + Shape + RoundRect + Style + + fill + + Color + + b + 0.324773 + g + 0.632962 + r + 0.99252 + + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 RC Input\ +PX4IO or PX4FMU} + VerticalPad + 0 + + + + Bounds + {{108, 349.1875}, {205, 36}} + Class + ShapedGraphic + FontInfo + + Font + Helvetica + Size + 12 + + ID + 6 + Shape + Rectangle + Style + + stroke + + CornerRadius + 9 + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\i\fs24 \cf0 MANUAL_CONTROL_SETPOINT} + + + + Bounds + {{340, 252}, {115, 36}} + Class + ShapedGraphic + FontInfo + + Font + Helvetica + Size + 12 + + ID + 5 + Shape + Rectangle + Style + + stroke + + CornerRadius + 9 + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\i\fs24 \cf0 RC_CHANNELS} + + + + Bounds + {{108, 170.5}, {204.97958374023438, 36}} + Class + ShapedGraphic + FontInfo + + Font + Helvetica + Size + 12 + + ID + 4 + Shape + Rectangle + Style + + stroke + + CornerRadius + 9 + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\i\fs24 \cf0 INPUT_RC} + + + + GridInfo + + HPages + 1 + KeepToScale + + Layers + + + Lock + NO + Name + Layer 1 + Print + YES + View + YES + + + LayoutInfo + + Animate + NO + circoMinDist + 18 + circoSeparation + 0.0 + layoutEngine + dot + neatoSeparation + 0.0 + twopiSeparation + 0.0 + + Orientation + 2 + PrintOnePage + + RowAlign + 1 + RowSpacing + 36 + SheetTitle + Canvas 1 + UniqueID + 1 + VPages + 1 + + + ActiveLayerIndex + 0 + AutoAdjust + + BackgroundGraphic + + Bounds + {{0, 0}, {806, 1132}} + Class + SolidGraphic + ID + 2 + Style + + shadow + + Draws + NO + + stroke + + Draws + NO + + + + BaseZoom + 0 + CanvasOrigin + {0, 0} + ColumnAlign + 1 + ColumnSpacing + 36 + DisplayScale + 1 0/72 in = 1.0000 in + GraphicsList + + + Bounds + {{129, 170}, {83, 44}} + Class + ShapedGraphic + ID + 4 + Shape + Rectangle + Style + + stroke + + CornerRadius + 9 + + + + + GridInfo + + HPages + 1 + KeepToScale + + Layers + + + Lock + NO + Name + Layer 1 + Print + YES + View + YES + + + LayoutInfo + + Animate + NO + circoMinDist + 18 + circoSeparation + 0.0 + layoutEngine + dot + neatoSeparation + 0.0 + twopiSeparation + 0.0 + + Orientation + 2 + PrintOnePage + + RowAlign + 1 + RowSpacing + 36 + SheetTitle + Remote Control + UniqueID + 5 + VPages + 1 + + + ActiveLayerIndex + 0 + AutoAdjust + + BackgroundGraphic + + Bounds + {{0, 0}, {806, 1132}} + Class + SolidGraphic + ID + 2 + Style + + shadow + + Draws + NO + + stroke + + Draws + NO + + + + BaseZoom + 0 + CanvasOrigin + {0, 0} + ColumnAlign + 1 + ColumnSpacing + 36 + DisplayScale + 1 0/72 in = 1.0000 in + GraphicsList + + + Class + Group + Graphics + + + Bounds + {{575.98995971679688, 379}, {47, 14}} + Class + ShapedGraphic + FitText + YES + Flow + Resize + ID + 1124 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Pad + 0 + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\b\fs24 \cf0 QUAD +\b0 X} + VerticalPad + 0 + + Wrap + NO + + + Class + Group + Graphics + + + Bounds + {{576.13064904528869, 216.6250047923653}, {50.666667938232422, 36}} + Class + ShapedGraphic + ID + 1126 + Rotation + 270 + Shape + HorizontalTriangle + Style + + fill + + Color + + b + 0.13195 + g + 0.165669 + r + 1 + + + + Text + + VerticalPad + 0 + + + + Bounds + {{565.46398168220912, 200.5990128790099}, {72, 72}} + Class + ShapedGraphic + ID + 1127 + Shape + Rectangle + Style + + stroke + + CornerRadius + 9 + + + + + ID + 1125 + Rotation + 315 + + + Class + Group + Graphics + + + Bounds + {{684.97877057518497, 320.1208883952101}, {24, 24}} + Class + ShapedGraphic + ID + 1129 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 4} + VerticalPad + 0 + + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1131 + Points + + {744.59415627118847, 308.1935744741462} + {742.38444757998036, 309.34262299357425} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{656.69108999710829, 361.8760779997491}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1132 + Rotation + 45 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{646.29122523639319, 281.66198172978545}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1133 + Rotation + 135 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{643.54122523639319, 278.91198172978545}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1134 + Rotation + 135 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1130 + Rotation + 315 + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1136 + Points + + {649.54722336322868, 356.21791362626482} + {651.75693205443667, 355.0688651068366} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{721.45028963730863, 284.03541010066203}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1137 + Rotation + 225 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{646.35015439802385, 281.24950637062551}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1138 + Rotation + 315 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{643.60015439802385, 278.49950637062551}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1139 + Rotation + 315 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1135 + Rotation + 315 + + + Bounds + {{646.0670873832953, 281.20919655324775}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1140 + Rotation + 315 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.234512 + g + 0.673128 + r + 0.148947 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + + + ID + 1128 + Rotation + 315 + + + Class + Group + Graphics + + + Bounds + {{494.01518801866729, 320.05486147948341}, {24, 24}} + Class + ShapedGraphic + ID + 1142 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 2} + VerticalPad + 0 + + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1144 + Points + + {458.75335031844725, 307.77399956263616} + {460.96305900965541, 308.92304808206421} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{530.65641659252742, 361.45650308823895}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1145 + Rotation + 135 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{455.55628135324292, 281.24240681827519}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1146 + Rotation + 45 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{452.80628135324292, 278.49240681827519}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1147 + Rotation + 45 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1143 + Rotation + 225 + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1149 + Points + + {553.44673702887792, 356.15188491228344} + {551.23702833767004, 355.00283639285527} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{465.54367075479814, 283.96938138668088}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1150 + Rotation + 315 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{455.14380599408253, 281.1834776566443}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1151 + Rotation + 225 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{452.39380599408253, 278.4334776566443}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1152 + Rotation + 225 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1148 + Rotation + 225 + VFlip + YES + + + Bounds + {{455.10349617670488, 281.1431681805102}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1153 + Rotation + 225 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.673128 + g + 0.534129 + r + 0.217952 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + ID + 1141 + Rotation + 315 + + + Class + Group + Graphics + + + Bounds + {{684.74305392865585, 129.32699556949493}, {24, 24}} + Class + ShapedGraphic + ID + 1155 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 1} + VerticalPad + 0 + + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1157 + Points + + {649.48121622843564, 117.04613365264774} + {651.69092491964352, 118.19518217207589} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{721.38428250251582, 170.72863717825052}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1158 + Rotation + 135 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{646.28414726323126, 90.514540908286847}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1159 + Rotation + 45 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{643.53414726323126, 87.764540908286847}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1160 + Rotation + 45 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1156 + Rotation + 225 + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1162 + Points + + {744.17460293886643, 165.42401900229501} + {741.96489424765866, 164.27497048286693} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{656.27153666478659, 93.241515476692427}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1163 + Rotation + 315 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{645.87167190407115, 90.455611746655876}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1164 + Rotation + 225 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{643.12167190407115, 87.705611746655876}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1165 + Rotation + 225 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1161 + Rotation + 225 + VFlip + YES + + + Bounds + {{645.83136208669339, 90.415302270521892}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1166 + Rotation + 225 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.673128 + g + 0.534129 + r + 0.217952 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + ID + 1154 + Rotation + 315 + + + Class + Group + Graphics + + + Bounds + {{494.00811680064464, 129.15022794494948}, {24, 24}} + Class + ShapedGraphic + ID + 1168 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 3} + VerticalPad + 0 + + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1170 + Points + + {553.62350249664826, 117.22291402388569} + {551.41379380544015, 118.37196254331369} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{465.72043622256808, 170.9054175494887}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1171 + Rotation + 45 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{455.32057146185286, 90.691321279524772}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1172 + Rotation + 135 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{452.57057146185286, 87.941321279524772}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1173 + Rotation + 135 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1169 + Rotation + 315 + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1175 + Points + + {458.57656958868847, 165.24725317600405} + {460.78627827989641, 164.09820465657594} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{530.47963586276819, 93.064749650401353}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1176 + Rotation + 225 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{455.37950062348352, 90.278845920365001}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1177 + Rotation + 315 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{452.62950062348352, 87.528845920365001}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1178 + Rotation + 315 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1174 + Rotation + 315 + + + Bounds + {{455.09643360875504, 90.238536102987126}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1179 + Rotation + 315 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.234512 + g + 0.673128 + r + 0.148947 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + + + ID + 1167 + Rotation + 315 + + + Bounds + {{547.25939156789127, 219.8035943432547}, {8, 134}} + Class + ShapedGraphic + ID + 1180 + Rotation + 225 + Shape + Rectangle + + + Bounds + {{647.66855809291212, 119.39442062517122}, {8, 134}} + Class + ShapedGraphic + ID + 1181 + Rotation + 225 + Shape + Rectangle + + + Bounds + {{647.66855089985006, 219.80357636059938}, {8, 134}} + Class + ShapedGraphic + ID + 1182 + Rotation + 315 + Shape + Rectangle + + + Bounds + {{547.20046240626141, 119.33550225313491}, {8, 134}} + Class + ShapedGraphic + ID + 1183 + Rotation + 315 + Shape + Rectangle + + + ID + 1123 + + + Bounds + {{287.14883422851562, 373}, {46, 14}} + Class + ShapedGraphic + FitText + YES + Flow + Resize + ID + 1121 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Pad + 0 + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\b\fs24 \cf0 QUAD +\b0 +} + VerticalPad + 0 + + Wrap + NO + + + Class + Group + Graphics + + + Class + Group + Graphics + + + Bounds + {{252.93672553699014, 864.96332065264312}, {24, 24}} + Class + ShapedGraphic + ID + 1186 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 6} + VerticalPad + 0 + + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1188 + Points + + {248.68672172228349, 826.3749926090228} + {249.43672172228361, 828.7499926090228} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{252.68672172228372, 918.12499260902291}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1189 + Rotation + 180 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{214.43672172228372, 826.3749926090228}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1190 + Rotation + 90 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{211.68672172228372, 823.6249926090228}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1191 + Rotation + 90 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1187 + Rotation + 270 + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1193 + Points + + {281.43672680854809, 927.54165927568897} + {280.6867268085482, 925.1666592756892} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{261.43672680854797, 817.2916592756892}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1194 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{214.18672680854797, 826.0416592756892}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1195 + Rotation + 270 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{211.43672680854797, 823.2916592756892}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1196 + Rotation + 270 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1192 + Rotation + 270 + VFlip + YES + + + Bounds + {{214.02503832182103, 826.05162629068673}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1197 + Rotation + 270 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.673128 + g + 0.534129 + r + 0.217952 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + ID + 1185 + + + Class + Group + Graphics + + + Bounds + {{255.93671290080545, 636.38001505533919}, {24, 24}} + Class + ShapedGraphic + ID + 1199 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 5} + VerticalPad + 0 + + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1201 + Points + + {251.6867090860988, 597.79168701171886} + {252.43670908609892, 600.16668701171886} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{255.68670908609903, 689.54168701171898}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1202 + Rotation + 180 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{217.43670908609903, 597.79168701171886}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1203 + Rotation + 90 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{214.68670908609903, 595.04168701171886}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1204 + Rotation + 90 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1200 + Rotation + 270 + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1206 + Points + + {284.43671417236339, 698.95835367838504} + {283.68671417236351, 696.58335367838527} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{264.43671417236328, 588.70835367838527}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1207 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{217.18671417236328, 597.45835367838527}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1208 + Rotation + 270 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{214.43671417236328, 594.70835367838527}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1209 + Rotation + 270 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1205 + Rotation + 270 + VFlip + YES + + + Bounds + {{217.02502568563636, 597.46832069338279}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1210 + Rotation + 270 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.673128 + g + 0.534129 + r + 0.217952 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + ID + 1198 + + + Class + Group + Graphics + + + Bounds + {{480.49999872844216, 864.96333555380545}, {24, 24}} + Class + ShapedGraphic + ID + 1212 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 4} + VerticalPad + 0 + + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1214 + Points + + {476.24999491373552, 826.37500751018513} + {476.99999491373563, 828.75000751018513} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{480.24999491373575, 918.12500751018524}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1215 + Rotation + 180 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{441.99999491373575, 826.37500751018513}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1216 + Rotation + 90 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{439.24999491373575, 823.62500751018513}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1217 + Rotation + 90 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1213 + Rotation + 270 + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1219 + Points + + {509.00000000000011, 927.5416741768513} + {508.25000000000023, 925.16667417685153} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{489, 817.29167417685153}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1220 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{441.75, 826.04167417685153}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1221 + Rotation + 270 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{439, 823.29167417685153}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1222 + Rotation + 270 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1218 + Rotation + 270 + VFlip + YES + + + Bounds + {{441.58831151327308, 826.05164119184906}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1223 + Rotation + 270 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.673128 + g + 0.534129 + r + 0.217952 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + ID + 1211 + + + Class + Group + Graphics + + + Bounds + {{480.49999872844216, 636.38001505533896}, {24, 24}} + Class + ShapedGraphic + ID + 1225 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 3} + VerticalPad + 0 + + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1227 + Points + + {476.24999491373552, 597.79168701171864} + {476.99999491373563, 600.16668701171864} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{480.24999491373575, 689.54168701171875}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1228 + Rotation + 180 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{441.99999491373575, 597.79168701171864}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1229 + Rotation + 90 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{439.24999491373575, 595.04168701171864}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1230 + Rotation + 90 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1226 + Rotation + 270 + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1232 + Points + + {509.00000000000011, 698.95835367838481} + {508.25000000000023, 696.58335367838504} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{489, 588.70835367838504}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1233 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{441.75, 597.45835367838504}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1234 + Rotation + 270 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{439, 594.70835367838504}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1235 + Rotation + 270 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1231 + Rotation + 270 + VFlip + YES + + + Bounds + {{441.58831151327308, 597.46832069338257}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1236 + Rotation + 270 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.673128 + g + 0.534129 + r + 0.217952 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + ID + 1224 + + + Bounds + {{452.7625732421875, 947.72591400146473}, {45, 14}} + Class + ShapedGraphic + FitText + YES + Flow + Resize + ID + 1237 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Pad + 0 + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\b\fs24 \cf0 OCTO +\b0 +} + VerticalPad + 0 + + Wrap + NO + + + Class + Group + Graphics + + + Bounds + {{353.51001119036124, 739.42163658141953}, {50.666667938232422, 36}} + Class + ShapedGraphic + ID + 1239 + Rotation + 270 + Shape + HorizontalTriangle + Style + + fill + + Color + + b + 0.13195 + g + 0.165669 + r + 1 + + + + Text + + VerticalPad + 0 + + + + Bounds + {{342.8433593880041, 726.66665752440122}, {72, 72}} + Class + ShapedGraphic + ID + 1240 + Rotation + 45 + Shape + Rectangle + Style + + stroke + + CornerRadius + 9 + + + + + ID + 1238 + + + Class + Group + Graphics + + + Bounds + {{366.83836873372331, 916.58333714803678}, {24, 24}} + Class + ShapedGraphic + ID + 1242 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 2} + VerticalPad + 0 + + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1244 + Points + + {429.42669677734398, 945.3333333333303} + {427.05169677734398, 944.58333333333019} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{320.42669677734375, 924.08333333333019}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1245 + Rotation + 90 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{327.92669677734398, 878.08333333333019}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1246 + Rotation + 180 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{325.17669677734398, 875.33333333333019}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1247 + Rotation + 180 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1243 + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1249 + Points + + {328.26003011067723, 912.08333841959472} + {330.63503011067723, 912.83333841959472} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{421.26003011067723, 914.83333841959472}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1250 + Rotation + 270 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{328.26003011067723, 877.83333841959472}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1251 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{325.51003011067723, 875.08333841959472}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1252 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1248 + + + Bounds + {{327.92668660481695, 877.67164993286758}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1253 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.234512 + g + 0.673128 + r + 0.148947 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + + + ID + 1241 + + + Class + Group + Graphics + + + Bounds + {{205.66167195637968, 750.54168065389615}, {24, 24}} + Class + ShapedGraphic + ID + 1255 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 7} + VerticalPad + 0 + + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1257 + Points + + {268.25000000000023, 779.29167683918968} + {265.87500000000023, 778.54167683918956} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{159.24999999999994, 758.04167683918956}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1258 + Rotation + 90 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{166.75, 712.04167683918956}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1259 + Rotation + 180 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{164, 709.29167683918956}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1260 + Rotation + 180 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1256 + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1262 + Points + + {167.08333333333348, 746.0416819254541} + {169.45833333333348, 746.7916819254541} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{260.08333333333348, 748.7916819254541}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1263 + Rotation + 270 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{167.08333333333348, 711.7916819254541}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1264 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{164.33333333333348, 709.0416819254541}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1265 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1261 + + + Bounds + {{166.74998982747337, 711.62999343872696}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1266 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.234512 + g + 0.673128 + r + 0.148947 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + + + ID + 1254 + + + Class + Group + Graphics + + + Bounds + {{528.01506551106706, 750.54168065389615}, {24, 24}} + Class + ShapedGraphic + ID + 1268 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 8} + VerticalPad + 0 + + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1270 + Points + + {590.60339355468773, 779.29167683918968} + {588.22839355468773, 778.54167683918956} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{481.6033935546875, 758.04167683918956}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1271 + Rotation + 90 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{489.10339355468773, 712.04167683918956}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1272 + Rotation + 180 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{486.35339355468773, 709.29167683918956}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1273 + Rotation + 180 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1269 + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1275 + Points + + {489.43672688802098, 746.0416819254541} + {491.81172688802098, 746.7916819254541} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{582.43672688802098, 748.7916819254541}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1276 + Rotation + 270 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{489.43672688802098, 711.7916819254541}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1277 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{486.68672688802098, 709.0416819254541}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1278 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1274 + + + Bounds + {{489.10338338216064, 711.62999343872696}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1279 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.234512 + g + 0.673128 + r + 0.148947 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + + + ID + 1267 + + + Bounds + {{306.14882584901056, 766.45459545146662}, {8, 134}} + Class + ShapedGraphic + ID + 1280 + Rotation + 225 + Shape + Rectangle + + + Bounds + {{468.3533935546875, 695.66666666666504}, {8, 134}} + Class + ShapedGraphic + ID + 1281 + Rotation + 270 + Shape + Rectangle + + + Bounds + {{440.55795213074884, 760.88380015384382}, {8, 134}} + Class + ShapedGraphic + ID + 1282 + Rotation + 135 + Shape + Rectangle + + + Class + Group + Graphics + + + Bounds + {{366.83834838867119, 584.49999872844194}, {24, 24}} + Class + ShapedGraphic + ID + 1284 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 1} + VerticalPad + 0 + + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1286 + Points + + {429.42667643229174, 613.24999491373558} + {427.05167643229174, 612.49999491373546} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{320.42667643229152, 591.99999491373546}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1287 + Rotation + 90 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{327.92667643229174, 545.99999491373546}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1288 + Rotation + 180 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{325.17667643229174, 543.24999491373546}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1289 + Rotation + 180 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1285 + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1291 + Points + + {328.26000976562511, 579.99999999999977} + {330.63500976562511, 580.74999999999977} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{421.260009765625, 582.74999999999977}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1292 + Rotation + 270 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{328.26000976562523, 545.74999999999977}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1293 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{325.51000976562523, 542.99999999999977}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1294 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1290 + + + Bounds + {{327.92666625976494, 545.58831151327263}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1295 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.234512 + g + 0.673128 + r + 0.148947 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + + + ID + 1283 + + + Bounds + {{281.3533935546875, 695.66666666666504}, {8, 134}} + Class + ShapedGraphic + ID + 1296 + Rotation + 270 + Shape + Rectangle + + + Bounds + {{442.5579845556756, 629.04542696963983}, {8, 134}} + Class + ShapedGraphic + ID + 1297 + Rotation + 225 + Shape + Rectangle + + + Bounds + {{374.84336344400776, 790.58333841959472}, {8, 134}} + Class + ShapedGraphic + ID + 1298 + Shape + Rectangle + + + Bounds + {{374.84335708617891, 600.24999491373535}, {8, 134}} + Class + ShapedGraphic + ID + 1299 + Shape + Rectangle + + + Bounds + {{309.12873002381525, 629.45457637798029}, {8, 134}} + Class + ShapedGraphic + ID + 1300 + Rotation + 135 + Shape + Rectangle + + + ID + 1184 + + + Class + Group + Graphics + + + Class + Group + Graphics + + + Bounds + {{181.15661763567644, 222.11968549092626}, {50.666667938232422, 36}} + Class + ShapedGraphic + ID + 1024 + Rotation + 270 + Shape + HorizontalTriangle + Style + + fill + + Color + + b + 0.13195 + g + 0.165669 + r + 1 + + + + Text + + VerticalPad + 0 + + + + Bounds + {{170.4899658333193, 209.364706433908}, {72, 72}} + Class + ShapedGraphic + ID + 1025 + Rotation + 45 + Shape + Rectangle + Style + + stroke + + CornerRadius + 9 + + + + + ID + 1023 + + + Class + Group + Graphics + + + Bounds + {{194.48495483398159, 368.44802729289523}, {24, 24}} + Class + ShapedGraphic + ID + 1027 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 4} + VerticalPad + 0 + + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1029 + Points + + {257.0732828776022, 397.19802347818882} + {254.69828287760208, 396.4480234781887} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{148.07328287760188, 375.9480234781887}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1030 + Rotation + 90 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{155.57328287760205, 329.9480234781887}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1031 + Rotation + 180 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{152.82328287760205, 327.1980234781887}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1032 + Rotation + 180 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1028 + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1034 + Points + + {155.90661621093548, 363.94802856445312} + {158.28161621093548, 364.69802856445312} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{248.90661621093545, 366.69802856445312}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1035 + Rotation + 270 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{155.90661621093548, 329.69802856445312}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1036 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{153.15661621093548, 326.94802856445312}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1037 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1033 + + + Bounds + {{155.57327270507534, 329.53634007772598}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1038 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.234512 + g + 0.673128 + r + 0.148947 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + + + ID + 1026 + + + Class + Group + Graphics + + + Bounds + {{59.499998728441994, 233.36969502765339}, {24, 24}} + Class + ShapedGraphic + ID + 1040 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 2} + VerticalPad + 0 + + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1042 + Points + + {55.249994913735321, 194.78136698403296} + {55.999994913735435, 197.1563669840329} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{59.249994913735435, 286.53136698403307}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1043 + Rotation + 180 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{20.999994913735549, 194.78136698403301}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1044 + Rotation + 90 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{18.249994913735549, 192.03136698403301}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1045 + Rotation + 90 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1041 + Rotation + 270 + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1047 + Points + + {87.999999999999915, 295.9480336506993} + {87.250000000000028, 293.57303365069941} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{67.999999999999915, 185.69803365069959}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1048 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{20.749999999999915, 194.44803365069947}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1049 + Rotation + 270 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{17.999999999999915, 191.69803365069947}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1050 + Rotation + 270 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1046 + Rotation + 270 + VFlip + YES + + + Bounds + {{20.588311513272686, 194.45800066569694}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1051 + Rotation + 270 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.673128 + g + 0.534129 + r + 0.217952 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + ID + 1039 + + + Class + Group + Graphics + + + Bounds + {{329.22993342082486, 233.36969502765339}, {24, 24}} + Class + ShapedGraphic + ID + 1053 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 1} + VerticalPad + 0 + + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1055 + Points + + {324.97992960611816, 194.7813669840329} + {325.72992960611828, 197.15636698403287} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{328.97992960611828, 286.53136698403307}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1056 + Rotation + 180 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{290.72992960611839, 194.78136698403301}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1057 + Rotation + 90 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{287.97992960611839, 192.03136698403301}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1058 + Rotation + 90 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1054 + Rotation + 270 + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1060 + Points + + {357.72993469238281, 295.9480336506993} + {356.97993469238293, 293.57303365069941} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{337.72993469238281, 185.69803365069953}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1061 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{290.47993469238281, 194.44803365069947}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1062 + Rotation + 270 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{287.72993469238281, 191.69803365069947}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1063 + Rotation + 270 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1059 + Rotation + 270 + VFlip + YES + + + Bounds + {{290.31824620565556, 194.45800066569686}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1064 + Rotation + 270 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.673128 + g + 0.534129 + r + 0.217952 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + ID + 1052 + + + Class + Group + Graphics + + + Bounds + {{194.48495483398159, 92.448027292895233}, {24, 24}} + Class + ShapedGraphic + ID + 1066 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 3} + VerticalPad + 0 + + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1068 + Points + + {257.0732828776022, 121.19802347818882} + {254.69828287760208, 120.4480234781887} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{148.07328287760188, 99.948023478188702}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1069 + Rotation + 90 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{155.57328287760205, 53.948023478188688}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1070 + Rotation + 180 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{152.82328287760205, 51.198023478188688}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1071 + Rotation + 180 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1067 + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1073 + Points + + {155.90661621093548, 87.948028564453111} + {158.28161621093548, 88.698028564453111} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{248.90661621093545, 90.698028564453111}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1074 + Rotation + 270 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{155.90661621093548, 53.698028564453111}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1075 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{153.15661621093548, 50.948028564453111}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1076 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1072 + + + Bounds + {{155.57327270507534, 53.536340077725967}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1077 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.234512 + g + 0.673128 + r + 0.148947 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + + + ID + 1065 + + + Bounds + {{131.48995971679412, 178.36470031738281}, {8, 134}} + Class + ShapedGraphic + ID + 1078 + Rotation + 270 + Shape + Rectangle + + + Bounds + {{273.48996988932043, 178.36469523111947}, {8, 134}} + Class + ShapedGraphic + ID + 1079 + Rotation + 270 + Shape + Rectangle + + + Bounds + {{202.48996988932029, 249.36468505859375}, {8, 134}} + Class + ShapedGraphic + ID + 1080 + Shape + Rectangle + + + Bounds + {{202.48995971679412, 107.28136189778644}, {8, 134}} + Class + ShapedGraphic + ID + 1081 + Shape + Rectangle + + + ID + 1022 + + + GridInfo + + HPages + 1 + KeepToScale + + Layers + + + Lock + NO + Name + Layer 1 + Print + YES + View + YES + + + LayoutInfo + + Animate + NO + circoMinDist + 18 + circoSeparation + 0.0 + layoutEngine + dot + neatoSeparation + 0.0 + twopiSeparation + 0.0 + + Orientation + 2 + PrintOnePage + + RowAlign + 1 + RowSpacing + 36 + SheetTitle + Rotor Assignments + UniqueID + 2 + VPages + 1 + + + ActiveLayerIndex + 0 + AutoAdjust + + BackgroundGraphic + + Bounds + {{0, 0}, {806, 1132}} + Class + SolidGraphic + ID + 2 + Style + + shadow + + Draws + NO + + stroke + + Draws + NO + + + + BaseZoom + 0 + CanvasOrigin + {0, 0} + ColumnAlign + 1 + ColumnSpacing + 36 + DisplayScale + 1 0/72 in = 1.0000 in + GraphicsList + + + Bounds + {{479, 926}, {45, 14}} + Class + ShapedGraphic + FitText + YES + Flow + Resize + ID + 1210 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Pad + 0 + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\b\fs24 \cf0 HEXA +\b0 X} + VerticalPad + 0 + + Wrap + NO + + + Class + Group + Graphics + + + Class + Group + Graphics + + + Bounds + {{323.13577025880016, 749.76557170439401}, {50.666667938232422, 36}} + Class + ShapedGraphic + ID + 1124 + Rotation + 270 + Shape + HorizontalTriangle + Style + + fill + + Color + + b + 0.13195 + g + 0.165669 + r + 1 + + + + Text + + VerticalPad + 0 + + + + Bounds + {{312.46911845644303, 737.01059264737569}, {72, 72}} + Class + ShapedGraphic + ID + 1125 + Rotation + 45 + Shape + Rectangle + Style + + stroke + + CornerRadius + 9 + + + + + ID + 1123 + + + Class + Group + Graphics + + + Bounds + {{407.17230315305846, 883.72204834096681}, {24, 24}} + Class + ShapedGraphic + ID + 1127 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 4} + VerticalPad + 0 + + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1129 + Points + + {379.80522301611819, 860.03627302756399} + {381.64224206895665, 861.71808336155198} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{432.69752786153174, 932.25483880979243}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1130 + Rotation + 150 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{368.7196421785618, 844.9870622696244}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1131 + Rotation + 60 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{365.9696421785618, 842.2370622696244}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1132 + Rotation + 60 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1128 + Rotation + 240 + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1134 + Points + + {458.75089272822612, 931.27417383395721} + {456.91387367538789, 929.59236349996911} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{389.85858788281303, 840.55560805172911}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1135 + Rotation + 330 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{368.33647356578285, 844.82338459189691}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1136 + Rotation + 240 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{365.58647356578285, 842.07338459189691}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1137 + Rotation + 240 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1133 + Rotation + 240 + VFlip + YES + + + Bounds + {{368.26061274159781, 844.81035428333826}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1138 + Rotation + 240 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.673128 + g + 0.534129 + r + 0.217952 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + ID + 1126 + Rotation + 330 + + + Class + Group + Graphics + + + Bounds + {{267.75726457856609, 881.27816449485533}, {24, 24}} + Class + ShapedGraphic + ID + 1140 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 6} + VerticalPad + 0 + + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1142 + Points + + {331.94303989196902, 882.48992268280176} + {329.51122955798087, 883.02790362996325} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{230.47447410974044, 913.3476178373885}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1143 + Rotation + 60 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{228.99225064990861, 842.82550352035832}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1144 + Rotation + 150 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{226.24225064990861, 840.07550352035832}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1145 + Rotation + 150 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1141 + Rotation + 330 + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1147 + Points + + {227.70513908557558, 904.27791574513662} + {230.13694941956365, 903.73993479797491} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{313.17370486780385, 854.92022059054989}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1148 + Rotation + 240 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{229.15592832763582, 842.44233490757972}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1149 + Rotation + 330 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{226.40592832763582, 839.69233490757972}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1150 + Rotation + 330 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1146 + Rotation + 330 + + + Bounds + {{228.84558214533197, 842.36647408339456}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1151 + Rotation + 330 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.234512 + g + 0.673128 + r + 0.148947 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + + + ID + 1139 + Rotation + 330 + + + Class + Group + Graphics + + + Bounds + {{474.97119637474935, 761.64314519248808}, {24, 24}} + Class + ShapedGraphic + ID + 1153 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 1} + VerticalPad + 0 + + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1155 + Points + + {539.15697168815223, 762.85490338043462} + {536.72516135416413, 763.39288432759611} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{437.68840590592367, 793.71259853502136}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1156 + Rotation + 60 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{436.20618244609187, 723.19048421799118}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1157 + Rotation + 150 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{433.45618244609187, 720.44048421799118}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1158 + Rotation + 150 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1154 + Rotation + 330 + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1160 + Points + + {434.91907088175884, 784.64289644276937} + {437.35088121574688, 784.10491549560766} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{520.38763666398711, 735.28520128818252}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1161 + Rotation + 240 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{436.36986012381902, 722.80731560521247}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1162 + Rotation + 330 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{433.61986012381902, 720.05731560521247}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1163 + Rotation + 330 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1159 + Rotation + 330 + + + Bounds + {{436.05951394151521, 722.73145478102731}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1164 + Rotation + 330 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.234512 + g + 0.673128 + r + 0.148947 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + + + ID + 1152 + Rotation + 330 + + + Class + Group + Graphics + + + Bounds + {{197.82245308809811, 760.38763453076365}, {24, 24}} + Class + ShapedGraphic + ID + 1166 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 2} + VerticalPad + 0 + + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1168 + Points + + {170.45537295115798, 736.70185921736106} + {172.29239200399638, 738.38366955134893} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{223.34767779657142, 808.92042499958939}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1169 + Rotation + 150 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{159.36979211360145, 721.65264845942124}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1170 + Rotation + 60 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{156.61979211360145, 718.90264845942124}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1171 + Rotation + 60 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1167 + Rotation + 240 + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1173 + Points + + {249.4010426632658, 807.93976002375393} + {247.56402361042768, 806.25794968976606} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{180.50873781785265, 717.22119424152584}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1174 + Rotation + 330 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{158.98662350082267, 721.48897078169387}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1175 + Rotation + 240 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{156.23662350082267, 718.73897078169387}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1176 + Rotation + 240 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1172 + Rotation + 240 + VFlip + YES + + + Bounds + {{158.91076267663743, 721.47594047313521}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1177 + Rotation + 240 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.673128 + g + 0.534129 + r + 0.217952 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + ID + 1165 + Rotation + 330 + + + Class + Group + Graphics + + + Bounds + {{405.7864385681853, 642.051622339657}, {24, 24}} + Class + ShapedGraphic + ID + 1179 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 5} + VerticalPad + 0 + + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1181 + Points + + {378.41935843124503, 618.36584702625407} + {380.25637748408349, 620.04765736024217} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{431.31166327665852, 690.58441280848263}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1182 + Rotation + 150 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{367.33377759368858, 603.3166362683146}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1183 + Rotation + 60 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{364.58377759368858, 600.5666362683146}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1184 + Rotation + 60 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1180 + Rotation + 240 + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1186 + Points + + {457.36502814335307, 689.6037478326474} + {455.52800909051496, 687.92193749865953} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{388.47272329793987, 598.8851820504193}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1187 + Rotation + 330 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{366.95060898090981, 603.15295859058722}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1188 + Rotation + 240 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{364.20060898090981, 600.40295859058722}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1189 + Rotation + 240 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1185 + Rotation + 240 + VFlip + YES + + + Bounds + {{366.87474815672459, 603.13992828202845}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1190 + Rotation + 240 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.673128 + g + 0.534129 + r + 0.217952 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + ID + 1178 + Rotation + 330 + + + Bounds + {{416.05401025695778, 706.97194681357246}, {8, 134}} + Class + ShapedGraphic + ID + 1191 + Rotation + 270 + Shape + Rectangle + + + Bounds + {{273.20840928884093, 706.24568349439642}, {8, 134}} + Class + ShapedGraphic + ID + 1192 + Rotation + 270 + Shape + Rectangle + + + Bounds + {{309.23428435411637, 768.64435011115415}, {8, 134}} + Class + ShapedGraphic + ID + 1193 + Rotation + 30 + Shape + Rectangle + + + Bounds + {{380.02813770004576, 644.57328454142464}, {8, 134}} + Class + ShapedGraphic + ID + 1194 + Rotation + 30 + Shape + Rectangle + + + Class + Group + Graphics + + + Bounds + {{268.61421230672084, 643.49244485638758}, {24, 24}} + Class + ShapedGraphic + ID + 1196 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 3} + VerticalPad + 0 + + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1198 + Points + + {332.79998762012377, 644.70420304433412} + {330.36817728613562, 645.24218399149561} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{231.33142183789516, 675.56189819892086}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1199 + Rotation + 60 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{229.84919837806336, 605.03978388189068}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1200 + Rotation + 150 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{227.09919837806336, 602.28978388189068}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1201 + Rotation + 150 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1197 + Rotation + 330 + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1203 + Points + + {228.56208681373033, 666.49219610666887} + {230.99389714771837, 665.95421515950716} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{314.03065259595854, 617.13450095208213}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1204 + Rotation + 240 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{230.01287605579051, 604.65661526911197}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1205 + Rotation + 330 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{227.26287605579051, 601.90661526911197}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1206 + Rotation + 330 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1202 + Rotation + 330 + + + Bounds + {{229.7025298734867, 604.58075444492681}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1207 + Rotation + 330 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.234512 + g + 0.673128 + r + 0.148947 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + + + ID + 1195 + Rotation + 330 + + + Bounds + {{380.57688435489479, 768.55104482376805}, {8, 134}} + Class + ShapedGraphic + ID + 1208 + Rotation + 330 + Shape + Rectangle + + + Bounds + {{309.53521396482506, 645.50328259865807}, {8, 134}} + Class + ShapedGraphic + ID + 1209 + Rotation + 330 + Shape + Rectangle + + + ID + 1122 + Rotation + 330 + + + Bounds + {{431, 450}, {44, 14}} + Class + ShapedGraphic + FitText + YES + Flow + Resize + ID + 1121 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Pad + 0 + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\b\fs24 \cf0 HEXA +\b0 +} + VerticalPad + 0 + + Wrap + NO + + + Class + Group + Graphics + + + Class + Group + Graphics + + + Bounds + {{326.15660523791308, 258.95613225301122}, {50.666667938232422, 36}} + Class + ShapedGraphic + ID + 320 + Rotation + 270 + Shape + HorizontalTriangle + Style + + fill + + Color + + b + 0.13195 + g + 0.165669 + r + 1 + + + + Text + + VerticalPad + 0 + + + + Bounds + {{315.48995343555595, 246.20115319599296}, {72, 72}} + Class + ShapedGraphic + ID + 321 + Rotation + 45 + Shape + Rectangle + Style + + stroke + + CornerRadius + 9 + + + + + ID + 319 + + + Class + Group + Graphics + + + Bounds + {{339.36497966449247, 411.82398351031941}, {24, 24}} + Class + ShapedGraphic + ID + 323 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 2} + VerticalPad + 0 + + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 325 + Points + + {335.11497584978588, 373.23565546669897} + {335.86497584978599, 375.61065546669897} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{339.11497584978599, 464.98565546669914}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 326 + Rotation + 180 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{300.86497584978611, 373.23565546669909}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 327 + Rotation + 90 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{298.11497584978611, 370.48565546669909}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 328 + Rotation + 90 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 324 + Rotation + 270 + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 330 + Points + + {367.86498093605042, 474.40232213336532} + {367.11498093605053, 472.02732213336543} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{347.86498093605042, 364.15232213336554}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 331 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{300.61498093605042, 372.90232213336543}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 332 + Rotation + 270 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{297.86498093605042, 370.15232213336543}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 333 + Rotation + 270 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 329 + Rotation + 270 + VFlip + YES + + + Bounds + {{300.45329244932327, 372.91228914836296}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 334 + Rotation + 270 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.673128 + g + 0.534129 + r + 0.217952 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + ID + 322 + + + Class + Group + Graphics + + + Bounds + {{219.84995651245046, 339.99999872844211}, {24, 24}} + Class + ShapedGraphic + ID + 336 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 3} + VerticalPad + 0 + + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 338 + Points + + {282.43828455607104, 368.74999491373569} + {280.06328455607098, 367.99999491373558} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{173.43828455607076, 347.49999491373558}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 339 + Rotation + 90 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{180.93828455607093, 301.49999491373558}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 340 + Rotation + 180 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{178.18828455607093, 298.74999491373558}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 341 + Rotation + 180 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 337 + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 343 + Points + + {181.27161788940435, 335.5} + {183.64661788940435, 336.25} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{274.2716178894043, 338.25}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 344 + Rotation + 270 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{181.27161788940435, 301.25}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 345 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{178.52161788940435, 298.5}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 346 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 342 + + + Bounds + {{180.93827438354421, 301.08831151327286}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 347 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.234512 + g + 0.673128 + r + 0.148947 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + + + ID + 335 + + + Class + Group + Graphics + + + Bounds + {{459.11999511718477, 339.99999872844211}, {24, 24}} + Class + ShapedGraphic + ID + 349 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 6} + VerticalPad + 0 + + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 351 + Points + + {521.70832316080532, 368.74999491373569} + {519.33332316080532, 367.99999491373558} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{412.70832316080504, 347.49999491373558}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 352 + Rotation + 90 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{420.20832316080521, 301.49999491373558}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 353 + Rotation + 180 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{417.45832316080521, 298.74999491373558}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 354 + Rotation + 180 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 350 + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 356 + Points + + {420.54165649413864, 335.5} + {422.91665649413864, 336.25} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{513.54165649413858, 338.25}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 357 + Rotation + 270 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{420.54165649413864, 301.25}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 358 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{417.79165649413864, 298.5}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 359 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 355 + + + Bounds + {{420.20831298827852, 301.08831151327286}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 360 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.234512 + g + 0.673128 + r + 0.148947 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + + + ID + 348 + + + Class + Group + Graphics + + + Bounds + {{219.72989813487507, 200.33832295734095}, {24, 24}} + Class + ShapedGraphic + ID + 362 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 5} + VerticalPad + 0 + + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 364 + Points + + {215.47989432016846, 161.74999491372051} + {216.22989432016857, 164.12499491372046} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{219.47989432016857, 253.49999491372063}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 365 + Rotation + 180 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{181.22989432016868, 161.74999491372057}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 366 + Rotation + 90 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{178.47989432016868, 158.99999491372057}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 367 + Rotation + 90 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 363 + Rotation + 270 + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 369 + Points + + {248.22989940643305, 262.91666158038686} + {247.47989940643316, 260.54166158038697} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{228.22989940643305, 152.66666158038709}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 370 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{180.97989940643305, 161.41666158038697}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 371 + Rotation + 270 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{178.22989940643305, 158.66666158038697}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 372 + Rotation + 270 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 368 + Rotation + 270 + VFlip + YES + + + Bounds + {{180.81821091970582, 161.42662859538444}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 373 + Rotation + 270 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.673128 + g + 0.534129 + r + 0.217952 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + ID + 361 + + + Class + Group + Graphics + + + Bounds + {{458.99999872844205, 201.83832295734095}, {24, 24}} + Class + ShapedGraphic + ID + 375 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 4} + VerticalPad + 0 + + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 377 + Points + + {454.74999491373541, 163.24999491372051} + {455.49999491373552, 165.62499491372046} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{458.74999491373552, 254.99999491372063}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 378 + Rotation + 180 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{420.49999491373563, 163.24999491372057}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 379 + Rotation + 90 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{417.74999491373563, 160.49999491372057}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 380 + Rotation + 90 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 376 + Rotation + 270 + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 382 + Points + + {487.5, 264.41666158038686} + {486.75000000000011, 262.04166158038697} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{467.5, 154.16666158038709}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 383 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{420.25, 162.91666158038697}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 384 + Rotation + 270 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{417.5, 160.16666158038697}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 385 + Rotation + 270 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 381 + Rotation + 270 + VFlip + YES + + + Bounds + {{420.0883115132728, 162.92662859538444}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 386 + Rotation + 270 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.673128 + g + 0.534129 + r + 0.217952 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + ID + 374 + + + Bounds + {{409.00361117886365, 251.82615622621091}, {8, 134}} + Class + ShapedGraphic + ID + 387 + Rotation + 300 + Shape + Rectangle + + + Bounds + {{285.65882358120746, 179.77439325790914}, {8, 134}} + Class + ShapedGraphic + ID + 388 + Rotation + 300 + Shape + Rectangle + + + Bounds + {{285.65881327292152, 251.82616124293514}, {8, 134}} + Class + ShapedGraphic + ID + 389 + Rotation + 60 + Shape + Rectangle + + + Bounds + {{409.00362148715112, 179.77439325790914}, {8, 134}} + Class + ShapedGraphic + ID + 390 + Rotation + 60 + Shape + Rectangle + + + Class + Group + Graphics + + + Bounds + {{339.48495483398165, 134.49999872844211}, {24, 24}} + Class + ShapedGraphic + ID + 392 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 1} + VerticalPad + 0 + + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 394 + Points + + {402.0732828776022, 163.24999491373569} + {399.69828287760214, 162.49999491373558} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{293.07328287760191, 141.99999491373558}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 395 + Rotation + 90 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{300.57328287760208, 95.999994913735577}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 396 + Rotation + 180 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{297.82328287760208, 93.249994913735577}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 397 + Rotation + 180 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 393 + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 399 + Points + + {300.90661621093551, 130} + {303.28161621093551, 130.75} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{393.90661621093545, 132.75}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 400 + Rotation + 270 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{300.90661621093551, 95.75}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 401 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{298.15661621093551, 93}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 402 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 398 + + + Bounds + {{300.5732727050754, 95.588311513272842}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 403 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.234512 + g + 0.673128 + r + 0.148947 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + + + ID + 391 + + + Bounds + {{347.48996988932038, 287.41665649414062}, {8, 134}} + Class + ShapedGraphic + ID + 404 + Shape + Rectangle + + + Bounds + {{347.4899597167942, 145.33333333333331}, {8, 134}} + Class + ShapedGraphic + ID + 405 + Shape + Rectangle + + + ID + 318 + + + GridInfo + + HPages + 1 + KeepToScale + + Layers + + + Lock + NO + Name + Layer 1 + Print + YES + View + YES + + + LayoutInfo + + Animate + NO + circoMinDist + 18 + circoSeparation + 0.0 + layoutEngine + dot + neatoSeparation + 0.0 + twopiSeparation + 0.0 + + Orientation + 2 + PrintOnePage + + RowAlign + 1 + RowSpacing + 36 + SheetTitle + Rotor Assignment 2 + UniqueID + 3 + VPages + 1 + + + ActiveLayerIndex + 0 + AutoAdjust + + BackgroundGraphic + + Bounds + {{0, 0}, {806, 1132}} + Class + SolidGraphic + ID + 2 + Style + + shadow + + Draws + NO + + stroke + + Draws + NO + + + + BaseZoom + 0 + CanvasOrigin + {0, 0} + ColumnAlign + 1 + ColumnSpacing + 36 + DisplayScale + 1 0/72 in = 1.0000 in + GraphicsList + + + Class + Group + Graphics + + + Class + Group + Graphics + + + Bounds + {{317.51000800051321, 240.42163882949882}, {50.666667938232422, 36}} + Class + ShapedGraphic + ID + 1417 + Rotation + 270 + Shape + HorizontalTriangle + Style + + fill + + Color + + b + 0.13195 + g + 0.165669 + r + 1 + + + + Text + + VerticalPad + 0 + + + + Bounds + {{306.84335619815613, 227.6666597724805}, {72, 72}} + Class + ShapedGraphic + ID + 1418 + Rotation + 45 + Shape + Rectangle + Style + + stroke + + CornerRadius + 9 + + + + + ID + 1416 + + + Class + Group + Graphics + + + Class + Group + Graphics + + + Bounds + {{181.87174317649047, 313.76849034719959}, {24, 24}} + Class + ShapedGraphic + ID + 1421 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 6} + VerticalPad + 0 + + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1423 + Points + + {159.49938242361688, 285.249576623557} + {161.10116522486757, 287.15677793899749} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{201.23696348262672, 364.71920821881605}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1424 + Rotation + 157.5 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{143.41457890258161, 275.07218626448082}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1425 + Rotation + 67.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{140.66457890258161, 272.32218626448082}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1426 + Rotation + 67.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1422 + Rotation + 247.5 + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1428 + Points + + {228.47124867019181, 366.1825051496383} + {226.8694658689414, 364.27530383419804} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{170.73366761118237, 268.21287355437971}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1429 + Rotation + 337.5 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{143.05605219122737, 274.85989550871483}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1430 + Rotation + 247.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{140.30605219122737, 272.10989550871483}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1431 + Rotation + 247.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1427 + Rotation + 247.5 + VFlip + YES + + + Bounds + {{142.96005354220407, 274.85679605657162}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1432 + Rotation + 247.5 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.673128 + g + 0.534129 + r + 0.217952 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + ID + 1420 + Rotation + 337.5 + + + Class + Group + Graphics + + + Bounds + {{272.11841406704639, 103.73309829351469}, {24, 24}} + Class + ShapedGraphic + ID + 1434 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 5} + VerticalPad + 0 + + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1436 + Points + + {249.74605331417285, 75.214184569872145} + {251.34783611542343, 77.121385885312606} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{291.48363437318255, 154.68381616513099}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1437 + Rotation + 157.5 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{233.66124979313764, 65.036794210795819}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1438 + Rotation + 67.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{230.91124979313764, 62.286794210795819}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1439 + Rotation + 67.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1435 + Rotation + 247.5 + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1441 + Points + + {318.71791956074799, 156.14711309595339} + {317.11613675949758, 154.23991178051318} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{260.98033850173846, 58.177481500694711}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1442 + Rotation + 337.5 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{233.30272308178348, 64.824503455029671}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1443 + Rotation + 247.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{230.55272308178348, 62.074503455029671}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1444 + Rotation + 247.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1440 + Rotation + 247.5 + VFlip + YES + + + Bounds + {{233.20672443276007, 64.821404002886837}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1445 + Rotation + 247.5 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.673128 + g + 0.534129 + r + 0.217952 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + ID + 1433 + Rotation + 337.5 + + + Class + Group + Graphics + + + Bounds + {{392.11278792691934, 400.85319857921803}, {24, 24}} + Class + ShapedGraphic + ID + 1447 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 4} + VerticalPad + 0 + + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1449 + Points + + {369.74042717404592, 372.33428485557562} + {371.34220997529656, 374.24148617101616} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{411.47800823305562, 451.80391645083449}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1450 + Rotation + 157.5 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{353.65562365301071, 362.15689449649926}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1451 + Rotation + 67.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{350.90562365301071, 359.40689449649926}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1452 + Rotation + 67.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1448 + Rotation + 247.5 + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1454 + Points + + {438.71229342062088, 453.26721338165692} + {437.11051061937059, 451.36001206621654} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{380.97471236161118, 355.29758178639815}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1455 + Rotation + 337.5 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{353.29709694165621, 361.94460374073327}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1456 + Rotation + 247.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{350.54709694165621, 359.19460374073327}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1457 + Rotation + 247.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1453 + Rotation + 247.5 + VFlip + YES + + + Bounds + {{353.20109829263305, 361.94150428859024}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1458 + Rotation + 247.5 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.673128 + g + 0.534129 + r + 0.217952 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + ID + 1446 + Rotation + 337.5 + + + Class + Group + Graphics + + + Bounds + {{479.58783759318999, 189.66974728965576}, {24, 24}} + Class + ShapedGraphic + ID + 1460 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 3} + VerticalPad + 0 + + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1462 + Points + + {457.21547665220845, 161.15083366194582} + {458.81725945345897, 163.05803497738634} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{498.95305771121809, 240.62046525720473}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1463 + Rotation + 157.5 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{441.13067313117307, 150.9734433028697}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1464 + Rotation + 67.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{438.38067313117307, 148.2234433028697}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1465 + Rotation + 67.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1461 + Rotation + 247.5 + VFlip + YES + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1467 + Points + + {526.18734328198354, 242.08376201128482} + {524.58556048073308, 240.17656069584442} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{468.44976222297396, 144.11413041602617}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1468 + Rotation + 337.5 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + Bounds + {{440.77214680301904, 150.76115237036112}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1469 + Rotation + 247.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + Bounds + {{438.02214680301904, 148.01115237036112}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1470 + Rotation + 247.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + VFlip + YES + + + ID + 1466 + Rotation + 247.5 + VFlip + YES + + + Bounds + {{440.67614795890404, 150.75805299902771}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1471 + Rotation + 247.5 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.673128 + g + 0.534129 + r + 0.217952 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + VFlip + YES + + + ID + 1459 + Rotation + 337.5 + + + Bounds + {{324.9947377700048, 478.76189426912856}, {46, 14}} + Class + ShapedGraphic + FitText + YES + Flow + Resize + ID + 1472 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Pad + 0 + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\b\fs24 \cf0 OCTO +\b0 X} + VerticalPad + 0 + + Wrap + NO + + + Class + Group + Graphics + + + Bounds + {{267.24952227247923, 404.95559172255122}, {24, 24}} + Class + ShapedGraphic + ID + 1474 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 2} + VerticalPad + 0 + + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1476 + Points + + {332.396988909622, 413.07125181593568} + {329.91576246001244, 413.28721548361688} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{226.49295677281663, 431.38573061302958}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1477 + Rotation + 67.5 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{228.4458262787623, 366.49842726410935}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1478 + Rotation + 157.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{225.6958262787623, 363.74842726410935}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1479 + Rotation + 157.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1475 + Rotation + 337.5 + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1481 + Points + + {226.20695455654064, 421.06707636999505} + {228.68818100615007, 420.8511127023138} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{316.11098669334581, 384.25259757290121}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1482 + Rotation + 247.5 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{228.65811718740025, 366.13990092182132}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1483 + Rotation + 337.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{225.90811718740025, 363.38990092182132}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1484 + Rotation + 337.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1480 + Rotation + 337.5 + + + Bounds + {{228.33784007224426, 366.04390208826476}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1485 + Rotation + 337.5 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.234512 + g + 0.673128 + r + 0.148947 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + + + ID + 1473 + Rotation + 337.5 + + + Class + Group + Graphics + + + Bounds + {{181.88306202487647, 189.87345220332375}, {24, 24}} + Class + ShapedGraphic + ID + 1487 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 7} + VerticalPad + 0 + + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1489 + Points + + {247.03052866201915, 197.98911229670802} + {244.5493022124096, 198.20507596438921} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{141.12649652521372, 216.30359109380208}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1490 + Rotation + 67.5 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{143.07936603115925, 151.41628774488177}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1491 + Rotation + 157.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{140.32936603115925, 148.66628774488177}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1492 + Rotation + 157.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1488 + Rotation + 337.5 + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1494 + Points + + {140.84049430893771, 205.98493685076758} + {143.32172075854714, 205.76897318308625} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{230.74452644574279, 169.17045805367366}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1495 + Rotation + 247.5 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{143.29165693979732, 151.05776140259383}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1496 + Rotation + 337.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{140.54165693979732, 148.30776140259383}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1497 + Rotation + 337.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1493 + Rotation + 337.5 + + + Bounds + {{142.97137982464162, 150.96176256903718}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1498 + Rotation + 337.5 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.234512 + g + 0.673128 + r + 0.148947 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + + + ID + 1486 + Rotation + 337.5 + + + Class + Group + Graphics + + + Bounds + {{479.69876456560792, 313.23275528336626}, {24, 24}} + Class + ShapedGraphic + ID + 1500 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 8} + VerticalPad + 0 + + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1502 + Points + + {544.84623120275069, 321.34841537675055} + {542.36500475314142, 321.56437904443163} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{438.94219906594537, 339.66289417384445}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1503 + Rotation + 67.5 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{440.89506857189104, 274.77559082492428}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1504 + Rotation + 157.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{438.14506857189104, 272.02559082492428}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1505 + Rotation + 157.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1501 + Rotation + 337.5 + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1507 + Points + + {438.65619684966936, 329.34423993081015} + {441.13742329927879, 329.12827626312878} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{528.56022898647439, 292.52976113371614}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1508 + Rotation + 247.5 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{441.107359480529, 274.41706448263619}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1509 + Rotation + 337.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{438.357359480529, 271.66706448263619}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1510 + Rotation + 337.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1506 + Rotation + 337.5 + + + Bounds + {{440.78708236537307, 274.3210656490798}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1511 + Rotation + 337.5 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.234512 + g + 0.673128 + r + 0.148947 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + + + ID + 1499 + Rotation + 337.5 + + + Bounds + {{248.28852278518417, 235.77792148758147}, {8, 134}} + Class + ShapedGraphic + ID + 1512 + Rotation + 247.5 + Shape + Rectangle + + + Bounds + {{425.23537052568395, 232.45140364934065}, {8, 134}} + Class + ShapedGraphic + ID + 1513 + Rotation + 292.50006103515625 + Shape + Rectangle + + + Bounds + {{374.59821460510483, 282.06732351898592}, {8, 134}} + Class + ShapedGraphic + ID + 1514 + Rotation + 157.5 + Shape + Rectangle + + + Class + Group + Graphics + + + Bounds + {{394.33229525377027, 98.150584482954116}, {24, 24}} + Class + ShapedGraphic + ID + 1516 + Shape + Circle + Style + + shadow + + Draws + NO + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 1} + VerticalPad + 0 + + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1518 + Points + + {459.47976189091298, 106.26624457633855} + {456.99853544130355, 106.48220824401977} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{353.57572975410767, 124.58072337343253}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1519 + Rotation + 67.5 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{355.52859926005328, 59.693420024512235}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1520 + Rotation + 157.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{352.77859926005328, 56.943420024512235}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1521 + Rotation + 157.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1517 + Rotation + 337.5 + + + Class + Group + Graphics + + + Class + LineGraphic + ID + 1523 + Points + + {353.28972753783154, 114.26206913039776} + {355.77095398744109, 114.04610546271654} + + Style + + stroke + + HeadArrow + 0 + Legacy + + TailArrow + 0 + + + + + Bounds + {{443.19375967463657, 77.447590333303964}, {16, 18.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1524 + Rotation + 247.5 + Shape + HorizontalTriangle + Style + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{355.74089016869129, 59.33489368222402}, {101.5, 101.5}} + Class + ShapedGraphic + HFlip + YES + ID + 1525 + Rotation + 337.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + Bounds + {{352.99089016869129, 56.58489368222402}, {107, 107}} + Class + ShapedGraphic + HFlip + YES + ID + 1526 + Rotation + 337.5 + Shape + AdjustableArc + ShapeData + + endAngle + 72 + startAngle + 281 + + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + + Text + + VerticalPad + 0 + + TextRelativeArea + {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} + + + ID + 1522 + Rotation + 337.5 + + + Bounds + {{355.42061305353548, 59.238894848667528}, {101.82337649086284, 101.82337649086284}} + Class + ShapedGraphic + ID + 1527 + Rotation + 337.5 + Shape + Circle + Style + + fill + + Color + + a + 0.78 + b + 0.234512 + g + 0.673128 + r + 0.148947 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + + + ID + 1515 + Rotation + 337.5 + + + Bounds + {{252.46989794607327, 160.88960179706885}, {8, 134}} + Class + ShapedGraphic + ID + 1528 + Rotation + 292.50006103515625 + Shape + Rectangle + + + Bounds + {{426.89836479441431, 161.02992820772749}, {8, 134}} + Class + ShapedGraphic + ID + 1529 + Rotation + 247.5 + Shape + Rectangle + + + Bounds + {{302.52032988683095, 284.35823469264687}, {8, 134}} + Class + ShapedGraphic + ID + 1530 + Rotation + 22.500026702880859 + Shape + Rectangle + + + Bounds + {{375.35774119930903, 108.51315184010758}, {8, 134}} + Class + ShapedGraphic + ID + 1531 + Rotation + 22.500026702880859 + Shape + Rectangle + + + Bounds + {{303.4692327942559, 110.3467678696648}, {8, 134}} + Class + ShapedGraphic + ID + 1532 + Rotation + 157.5 + Shape + Rectangle + + + ID + 1419 + Rotation + 45 + + + ID + 1415 + + + GridInfo + + HPages + 1 + KeepToScale + + Layers + + + Lock + NO + Name + Layer 1 + Print + YES + View + YES + + + LayoutInfo + + Animate + NO + circoMinDist + 18 + circoSeparation + 0.0 + layoutEngine + dot + neatoSeparation + 0.0 + twopiSeparation + 0.0 + + Orientation + 2 + PrintOnePage + + RowAlign + 1 + RowSpacing + 36 + SheetTitle + Rotor Assignment 3 + UniqueID + 4 + VPages + 1 + + + SmartAlignmentGuidesActive + YES + SmartDistanceGuidesActive + YES + UseEntirePage + + WindowInfo + + CurrentSheet + 4 + ExpandedCanvases + + + name + Canvas 1 + + + Frame + {{96, 56}, {1043, 822}} + ListView + + OutlineWidth + 142 + RightSidebar + + ShowRuler + + Sidebar + + SidebarWidth + 120 + VisibleRegion + {{-51, -33}, {908, 683}} + Zoom + 1 + ZoomValues + + + Canvas 1 + 1 + 0.5 + + + Rotor Assignments + 1 + 4 + + + Rotor Assignment 2 + 1 + 4 + + + Rotor Assignment 3 + 1 + 1 + + + Remote Control + 1 + 1 + + + + + From edf96fc8085510765c503350d29c96a2789bdbc0 Mon Sep 17 00:00:00 2001 From: px4dev Date: Sun, 28 Apr 2013 12:47:34 -0700 Subject: [PATCH 22/84] Remove some naked command invocations. --- makefiles/module.mk | 2 +- makefiles/setup.mk | 2 ++ makefiles/upload.mk | 13 ++++++++----- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/makefiles/module.mk b/makefiles/module.mk index 86810627b2..59c67f574d 100644 --- a/makefiles/module.mk +++ b/makefiles/module.mk @@ -153,7 +153,7 @@ $(MODULE_COMMAND_FILES): exclude = $(dir $@)COMMAND.$(command).* $(MODULE_COMMAND_FILES): $(GLOBAL_DEPS) @$(REMOVE) -f $(exclude) @$(MKDIR) -p $(dir $@) - @echo "CMD: $(command)" + @$(ECHO) "CMD: $(command)" $(Q) $(TOUCH) $@ endif diff --git a/makefiles/setup.mk b/makefiles/setup.mk index 8072ec7915..1111930937 100644 --- a/makefiles/setup.mk +++ b/makefiles/setup.mk @@ -72,6 +72,8 @@ export TOUCH = touch export MKDIR = mkdir export ECHO = echo export UNZIP_CMD = unzip +export PYTHON = python +export OPENOCD = openocd # # Host-specific paths, hacks and fixups diff --git a/makefiles/upload.mk b/makefiles/upload.mk index f23d6ae41a..5ef92728fe 100644 --- a/makefiles/upload.mk +++ b/makefiles/upload.mk @@ -25,7 +25,10 @@ endif all: upload-$(METHOD)-$(BOARD) upload-serial-px4fmu: $(BUNDLE) $(UPLOADER) - @python -u $(UPLOADER) --port $(SERIAL_PORTS) $(BUNDLE) + $(Q) $(PYTHON) -u $(UPLOADER) --port $(SERIAL_PORTS) $(BUNDLE) + +upload-serial-px4fmuv2: $(BUNDLE) $(UPLOADER) + $(Q) $(PYTHON) -u $(UPLOADER) --port $(SERIAL_PORTS) $(BUNDLE) # # JTAG firmware uploading with OpenOCD @@ -33,9 +36,9 @@ upload-serial-px4fmu: $(BUNDLE) $(UPLOADER) JTAGCONFIG ?= interface/olimex-jtag-tiny.cfg upload-jtag-px4fmu: all - @echo Attempting to flash PX4FMU board via JTAG - @openocd -f $(JTAGCONFIG) -f ../Bootloader/stm32f4x.cfg -c init -c "reset halt" -c "flash write_image erase nuttx/nuttx" -c "flash write_image erase ../Bootloader/px4fmu_bl.elf" -c "reset run" -c shutdown + @$(ECHO) Attempting to flash PX4FMU board via JTAG + $(Q) $(OPENOCD) -f $(JTAGCONFIG) -f ../Bootloader/stm32f4x.cfg -c init -c "reset halt" -c "flash write_image erase nuttx/nuttx" -c "flash write_image erase ../Bootloader/px4fmu_bl.elf" -c "reset run" -c shutdown upload-jtag-px4io: all - @echo Attempting to flash PX4IO board via JTAG - @openocd -f $(JTAGCONFIG) -f ../Bootloader/stm32f1x.cfg -c init -c "reset halt" -c "flash write_image erase nuttx/nuttx" -c "flash write_image erase ../Bootloader/px4io_bl.elf" -c "reset run" -c shutdown + @$(ECHO) Attempting to flash PX4IO board via JTAG + $(Q) $(OPENOCD) -f $(JTAGCONFIG) -f ../Bootloader/stm32f1x.cfg -c init -c "reset halt" -c "flash write_image erase nuttx/nuttx" -c "flash write_image erase ../Bootloader/px4io_bl.elf" -c "reset run" -c shutdown From 8d3a738b7011ab77bab7ac89c5314fdc7c663890 Mon Sep 17 00:00:00 2001 From: px4dev Date: Sun, 28 Apr 2013 13:00:32 -0700 Subject: [PATCH 23/84] Remove some trash files. --- src/modules/position_estimator/.context | 0 src/modules/uORB/.context | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/modules/position_estimator/.context delete mode 100644 src/modules/uORB/.context diff --git a/src/modules/position_estimator/.context b/src/modules/position_estimator/.context deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/modules/uORB/.context b/src/modules/uORB/.context deleted file mode 100644 index e69de29bb2..0000000000 From ca5dcc11a7754d38e3b5f63bcb708e106fb2a3cd Mon Sep 17 00:00:00 2001 From: marco Date: Mon, 29 Apr 2013 18:32:30 +0200 Subject: [PATCH 24/84] BLCtrl 2.0 testing - currently only 8 Bit resolution - motor detection and px4 mode as default --- apps/drivers/mkblctrl/mkblctrl.cpp | 83 ++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 28 deletions(-) diff --git a/apps/drivers/mkblctrl/mkblctrl.cpp b/apps/drivers/mkblctrl/mkblctrl.cpp index 664271bee5..bcdb80b5d0 100644 --- a/apps/drivers/mkblctrl/mkblctrl.cpp +++ b/apps/drivers/mkblctrl/mkblctrl.cpp @@ -121,6 +121,7 @@ public: int set_motor_test(bool motortest); int set_px4mode(int px4mode); int set_frametype(int frametype); + unsigned int mk_check_for_blctrl(unsigned int count, unsigned int showOutput); private: static const unsigned _max_actuators = MAX_MOTORS; @@ -176,7 +177,6 @@ private: int gpio_ioctl(file *filp, int cmd, unsigned long arg); int mk_servo_arm(bool status); - int mk_check_for_blctrl(unsigned int count); int mk_servo_set(unsigned int chan, float val); int mk_servo_set_test(unsigned int chan, float val); int mk_servo_test(unsigned int chan); @@ -350,11 +350,11 @@ MK::set_mode(Mode mode) switch (mode) { case MODE_2PWM: if(_num_outputs == 4) { - debug("MODE_QUAD"); + //debug("MODE_QUAD"); } else if(_num_outputs == 6) { - debug("MODE_HEXA"); + //debug("MODE_HEXA"); } else if(_num_outputs == 8) { - debug("MODE_OCTO"); + //debug("MODE_OCTO"); } //up_pwm_servo_init(0x3); up_pwm_servo_deinit(); @@ -363,11 +363,11 @@ MK::set_mode(Mode mode) case MODE_4PWM: if(_num_outputs == 4) { - debug("MODE_QUADRO"); + //debug("MODE_QUADRO"); } else if(_num_outputs == 6) { - debug("MODE_HEXA"); + //debug("MODE_HEXA"); } else if(_num_outputs == 8) { - debug("MODE_OCTO"); + //debug("MODE_OCTO"); } //up_pwm_servo_init(0xf); up_pwm_servo_deinit(); @@ -447,8 +447,13 @@ MK::set_motor_count(unsigned count) memcpy(&addrTranslator, &blctrlAddr_px4, sizeof(blctrlAddr_px4)); } - /* check for connected blctrls */ - mk_check_for_blctrl(_num_outputs); + if(_num_outputs == 4) { + fprintf(stderr, "[mkblctrl] Quadrocopter Mode (4)\n"); + } else if(_num_outputs == 6) { + fprintf(stderr, "[mkblctrl] Hexacopter Mode (6)\n"); + } else if(_num_outputs == 8) { + fprintf(stderr, "[mkblctrl] Octocopter Mode (8)\n"); + } return OK; } @@ -502,7 +507,6 @@ MK::task_main() memset(&rc_in, 0, sizeof(rc_in)); rc_in.input_source = RC_INPUT_SOURCE_PX4FMU_PPM; - log("starting"); long update_rate_in_us = 0; @@ -666,10 +670,10 @@ MK::mk_servo_arm(bool status) } -int -MK::mk_check_for_blctrl(unsigned int count) +unsigned int +MK::mk_check_for_blctrl(unsigned int count, unsigned int showOutput) { - _retries = 10; + _retries = 50; uint8_t foundMotorCount = 0; for(unsigned i=0; iset_frametype(frametype); + /* motortest if enabled */ + g_mk->set_motor_test(motortest); + + /* (re)set count of used motors */ - g_mk->set_motor_count(motorcount); + ////g_mk->set_motor_count(motorcount); + /* count used motors */ + + do { + if(g_mk->mk_check_for_blctrl(8, 0) != 0) { + shouldStop = 3; + } else { + shouldStop++; + } + sleep(1); + } while ( shouldStop != 3); + + g_mk->set_motor_count(g_mk->mk_check_for_blctrl(8, 1)); /* (re)set the PWM output mode */ g_mk->set_mode(servo_mode); - /* motortest if enabled */ - g_mk->set_motor_test(motortest); if ((servo_mode != MK::MODE_NONE) && (update_rate != 0)) g_mk->set_pwm_rate(update_rate); @@ -1335,15 +1359,19 @@ mkblctrl_main(int argc, char *argv[]) int motorcount = 0; int bus = 1; bool motortest = false; - int px4mode = MAPPING_MK; + int px4mode = MAPPING_PX4; int frametype = FRAME_PLUS; // + plus is default + new_mode = PORT_FULL_PWM; + motorcount = 8; + /* * Mode switches. * * XXX use getopt? */ for (int i = 1; i < argc; i++) { /* argv[0] is "mk" */ + /* if (!strcmp(argv[i], "mode_quad")) { new_mode = PORT_FULL_PWM; motorcount = 4; @@ -1354,8 +1382,10 @@ mkblctrl_main(int argc, char *argv[]) new_mode = PORT_FULL_PWM; motorcount = 8; } + */ /* look for the optional update rate for the supported modes */ + /* if (strcmp(argv[i], "-u") == 0 || strcmp(argv[i], "--update-rate") == 0) { if (argc > i + 1) { pwm_update_rate_in_hz = atoi(argv[i + 1]); @@ -1365,6 +1395,7 @@ mkblctrl_main(int argc, char *argv[]) } } + */ /* look for the optional i2c bus parameter */ if (strcmp(argv[i], "-b") == 0 || strcmp(argv[i], "--bus") == 0) { if (argc > i + 1) { @@ -1376,9 +1407,10 @@ mkblctrl_main(int argc, char *argv[]) } /* look for the optional frame parameter */ - if (strcmp(argv[i], "-f") == 0 || strcmp(argv[i], "--frame") == 0) { + if (strcmp(argv[i], "-mkmode") == 0 || strcmp(argv[i], "--mkmode") == 0) { if (argc > i + 1) { if(strcmp(argv[i + 1], "+") == 0 || strcmp(argv[i + 1], "x") == 0 || strcmp(argv[i + 1], "X") == 0) { + px4mode = MAPPING_MK; if(strcmp(argv[i + 1], "+") == 0) { frametype = FRAME_PLUS; } else { @@ -1388,16 +1420,11 @@ mkblctrl_main(int argc, char *argv[]) errx(1, "only + or x for frametype supported !"); } } else { - errx(1, "missing argument for frametype (-f)"); + errx(1, "missing argument for mkmode (-mkmode)"); return 1; } } - /* look for the optional geometry parameter */ - if (strcmp(argv[i], "-px4mode") == 0) { - px4mode = MAPPING_PX4; - } - /* look for the optional test parameter */ if (strcmp(argv[i], "-t") == 0) { motortest = true; @@ -1407,7 +1434,7 @@ mkblctrl_main(int argc, char *argv[]) if(new_mode == PORT_MODE_UNSET) { fprintf(stderr, "mkblctrl: unrecognised command, try:\n"); - fprintf(stderr, " mode_quad, mode_hexa, mode_octo [-b i2c_bus_number] [-u update_rate_in_hz] [-t motortest] [-px4mode] [-f frame{+/x}]\n"); + fprintf(stderr, " [-mkmode frame{+/x}] [-b i2c_bus_number] [-t motortest]\n"); exit(1); } From 130c7a353055da628518f6de1bbd58c855fad5bd Mon Sep 17 00:00:00 2001 From: marco Date: Mon, 29 Apr 2013 19:56:50 +0200 Subject: [PATCH 25/84] BLCtrl 2.0 testing - currently only 8 Bit resolution - motor detection and px4 mode as default - with safety shutdown --- apps/drivers/mkblctrl/mkblctrl.cpp | 42 +++++------------------------- 1 file changed, 6 insertions(+), 36 deletions(-) diff --git a/apps/drivers/mkblctrl/mkblctrl.cpp b/apps/drivers/mkblctrl/mkblctrl.cpp index bcdb80b5d0..057ee2128d 100644 --- a/apps/drivers/mkblctrl/mkblctrl.cpp +++ b/apps/drivers/mkblctrl/mkblctrl.cpp @@ -311,9 +311,6 @@ MK::init(unsigned motors) /* reset GPIOs */ gpio_reset(); - /* check for connected blctrls */ - //mk_check_for_blctrl(_num_outputs); - /* start the IO interface task */ _task = task_spawn("mkblctrl", SCHED_DEFAULT, @@ -717,16 +714,13 @@ MK::mk_check_for_blctrl(unsigned int count, unsigned int showOutput) for(unsigned i=0; i< count; i++) { fprintf(stderr, "[mkblctrl] blctrl[%i] : found=%i\tversion=%i\tcurrent=%i\tmaxpwm=%i\ttemperature=%i\n", i,Motor[i].State, Motor[i].Version, Motor[i].Current, Motor[i].MaxPWM, Motor[i].Temperature); } + + if(foundMotorCount == 0) { + _task_should_exit = true; + } } return foundMotorCount; - /* - if(foundMotorCount == count) { - return true; - } else { - return false; - } - */ } @@ -1302,12 +1296,12 @@ mk_new_mode(PortMode new_mode, int update_rate, int motorcount, bool motortest, do { if(g_mk->mk_check_for_blctrl(8, 0) != 0) { - shouldStop = 3; + shouldStop = 4; } else { shouldStop++; } sleep(1); - } while ( shouldStop != 3); + } while ( shouldStop < 3); g_mk->set_motor_count(g_mk->mk_check_for_blctrl(8, 1)); @@ -1371,31 +1365,7 @@ mkblctrl_main(int argc, char *argv[]) * XXX use getopt? */ for (int i = 1; i < argc; i++) { /* argv[0] is "mk" */ - /* - if (!strcmp(argv[i], "mode_quad")) { - new_mode = PORT_FULL_PWM; - motorcount = 4; - } else if (!strcmp(argv[i], "mode_hexa")) { - new_mode = PORT_FULL_PWM; - motorcount = 6; - } else if (!strcmp(argv[i], "mode_octo")) { - new_mode = PORT_FULL_PWM; - motorcount = 8; - } - */ - /* look for the optional update rate for the supported modes */ - /* - if (strcmp(argv[i], "-u") == 0 || strcmp(argv[i], "--update-rate") == 0) { - if (argc > i + 1) { - pwm_update_rate_in_hz = atoi(argv[i + 1]); - } else { - errx(1, "missing argument for update rate (-u)"); - return 1; - } - } - - */ /* look for the optional i2c bus parameter */ if (strcmp(argv[i], "-b") == 0 || strcmp(argv[i], "--bus") == 0) { if (argc > i + 1) { From ee4a93d668540dea3b7b33eafb94a888f802f466 Mon Sep 17 00:00:00 2001 From: marco Date: Mon, 29 Apr 2013 20:42:06 +0200 Subject: [PATCH 26/84] BLCtrl 2.0 testing - currently only 8 Bit resolution - motor detection and px4 mode as default - with safety shutdown - fix --- apps/drivers/mkblctrl/mkblctrl.cpp | 89 ++++++++++++++++-------------- 1 file changed, 48 insertions(+), 41 deletions(-) diff --git a/apps/drivers/mkblctrl/mkblctrl.cpp b/apps/drivers/mkblctrl/mkblctrl.cpp index 057ee2128d..e70bd16945 100644 --- a/apps/drivers/mkblctrl/mkblctrl.cpp +++ b/apps/drivers/mkblctrl/mkblctrl.cpp @@ -121,7 +121,7 @@ public: int set_motor_test(bool motortest); int set_px4mode(int px4mode); int set_frametype(int frametype); - unsigned int mk_check_for_blctrl(unsigned int count, unsigned int showOutput); + unsigned int mk_check_for_blctrl(unsigned int count, bool showOutput); private: static const unsigned _max_actuators = MAX_MOTORS; @@ -412,47 +412,54 @@ MK::set_frametype(int frametype) int MK::set_motor_count(unsigned count) { - _num_outputs = count; + if(count > 0) { - if(_px4mode == MAPPING_MK) { - if(_frametype == FRAME_PLUS) { - fprintf(stderr, "[mkblctrl] addresstanslator for Mikrokopter addressing used. Frametype: +\n"); - } else if(_frametype == FRAME_X) { - fprintf(stderr, "[mkblctrl] addresstanslator for Mikrokopter addressing used. Frametype: X\n"); + _num_outputs = count; + + if(_px4mode == MAPPING_MK) { + if(_frametype == FRAME_PLUS) { + fprintf(stderr, "[mkblctrl] addresstanslator for Mikrokopter addressing used. Frametype: +\n"); + } else if(_frametype == FRAME_X) { + fprintf(stderr, "[mkblctrl] addresstanslator for Mikrokopter addressing used. Frametype: X\n"); + } + if(_num_outputs == 4) { + if(_frametype == FRAME_PLUS) { + memcpy(&addrTranslator, &blctrlAddr_quad_plus, sizeof(blctrlAddr_quad_plus)); + } else if(_frametype == FRAME_X) { + memcpy(&addrTranslator, &blctrlAddr_quad_x, sizeof(blctrlAddr_quad_x)); + } + } else if(_num_outputs == 6) { + if(_frametype == FRAME_PLUS) { + memcpy(&addrTranslator, &blctrlAddr_hexa_plus, sizeof(blctrlAddr_hexa_plus)); + } else if(_frametype == FRAME_X) { + memcpy(&addrTranslator, &blctrlAddr_hexa_x, sizeof(blctrlAddr_hexa_x)); + } + } else if(_num_outputs == 8) { + if(_frametype == FRAME_PLUS) { + memcpy(&addrTranslator, &blctrlAddr_octo_plus, sizeof(blctrlAddr_octo_plus)); + } else if(_frametype == FRAME_X) { + memcpy(&addrTranslator, &blctrlAddr_octo_x, sizeof(blctrlAddr_octo_x)); + } + } + } else { + fprintf(stderr, "[mkblctrl] PX4 native addressing used.\n"); + memcpy(&addrTranslator, &blctrlAddr_px4, sizeof(blctrlAddr_px4)); } + if(_num_outputs == 4) { - if(_frametype == FRAME_PLUS) { - memcpy(&addrTranslator, &blctrlAddr_quad_plus, sizeof(blctrlAddr_quad_plus)); - } else if(_frametype == FRAME_X) { - memcpy(&addrTranslator, &blctrlAddr_quad_x, sizeof(blctrlAddr_quad_x)); - } - } else if(_num_outputs == 6) { - if(_frametype == FRAME_PLUS) { - memcpy(&addrTranslator, &blctrlAddr_hexa_plus, sizeof(blctrlAddr_hexa_plus)); - } else if(_frametype == FRAME_X) { - memcpy(&addrTranslator, &blctrlAddr_hexa_x, sizeof(blctrlAddr_hexa_x)); - } - } else if(_num_outputs == 8) { - if(_frametype == FRAME_PLUS) { - memcpy(&addrTranslator, &blctrlAddr_octo_plus, sizeof(blctrlAddr_octo_plus)); - } else if(_frametype == FRAME_X) { - memcpy(&addrTranslator, &blctrlAddr_octo_x, sizeof(blctrlAddr_octo_x)); - } + fprintf(stderr, "[mkblctrl] Quadrocopter Mode (4)\n"); + } else if(_num_outputs == 6) { + fprintf(stderr, "[mkblctrl] Hexacopter Mode (6)\n"); + } else if(_num_outputs == 8) { + fprintf(stderr, "[mkblctrl] Octocopter Mode (8)\n"); } + + return OK; + } else { - fprintf(stderr, "[mkblctrl] PX4 native addressing used.\n"); - memcpy(&addrTranslator, &blctrlAddr_px4, sizeof(blctrlAddr_px4)); + return -1; } - if(_num_outputs == 4) { - fprintf(stderr, "[mkblctrl] Quadrocopter Mode (4)\n"); - } else if(_num_outputs == 6) { - fprintf(stderr, "[mkblctrl] Hexacopter Mode (6)\n"); - } else if(_num_outputs == 8) { - fprintf(stderr, "[mkblctrl] Octocopter Mode (8)\n"); - } - - return OK; } int @@ -668,7 +675,7 @@ MK::mk_servo_arm(bool status) unsigned int -MK::mk_check_for_blctrl(unsigned int count, unsigned int showOutput) +MK::mk_check_for_blctrl(unsigned int count, bool showOutput) { _retries = 50; uint8_t foundMotorCount = 0; @@ -709,13 +716,13 @@ MK::mk_check_for_blctrl(unsigned int count, unsigned int showOutput) } } - if(showOutput == 1) { + if(showOutput) { fprintf(stderr, "[mkblctrl] MotorsFound: %i\n",foundMotorCount); - for(unsigned i=0; i< count; i++) { + for(unsigned i=0; i< foundMotorCount; i++) { fprintf(stderr, "[mkblctrl] blctrl[%i] : found=%i\tversion=%i\tcurrent=%i\tmaxpwm=%i\ttemperature=%i\n", i,Motor[i].State, Motor[i].Version, Motor[i].Current, Motor[i].MaxPWM, Motor[i].Temperature); } - if(foundMotorCount == 0) { + if(foundMotorCount != 4 && foundMotorCount != 6 && foundMotorCount != 8) { _task_should_exit = true; } } @@ -1295,7 +1302,7 @@ mk_new_mode(PortMode new_mode, int update_rate, int motorcount, bool motortest, /* count used motors */ do { - if(g_mk->mk_check_for_blctrl(8, 0) != 0) { + if(g_mk->mk_check_for_blctrl(8, false) != 0) { shouldStop = 4; } else { shouldStop++; @@ -1303,7 +1310,7 @@ mk_new_mode(PortMode new_mode, int update_rate, int motorcount, bool motortest, sleep(1); } while ( shouldStop < 3); - g_mk->set_motor_count(g_mk->mk_check_for_blctrl(8, 1)); + g_mk->set_motor_count(g_mk->mk_check_for_blctrl(8, true)); /* (re)set the PWM output mode */ g_mk->set_mode(servo_mode); From ddf1b27697dd5edd8e8282c24ad35cb938dbf3c8 Mon Sep 17 00:00:00 2001 From: Simon Wilks Date: Thu, 2 May 2013 07:10:23 +0200 Subject: [PATCH 27/84] Added a config for quads with a wide arm config. --- ROMFS/Makefile | 3 ++- apps/systemlib/mixer/mixer.h | 1 + apps/systemlib/mixer/mixer_multirotor.cpp | 11 +++++++++++ apps/systemlib/mixer/multi_tables | 9 ++++++++- 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/ROMFS/Makefile b/ROMFS/Makefile index 11a4650fa6..ecd15d5e27 100644 --- a/ROMFS/Makefile +++ b/ROMFS/Makefile @@ -32,7 +32,8 @@ ROMFS_FSSPEC := $(SRCROOT)/scripts/rcS~init.d/rcS \ $(SRCROOT)/mixers/FMU_RET.mix~mixers/FMU_ERT.mix \ $(SRCROOT)/mixers/FMU_quad_x.mix~mixers/FMU_quad_x.mix \ $(SRCROOT)/mixers/FMU_quad_+.mix~mixers/FMU_quad_+.mix \ - $(SRCROOT)/mixers/FMU_quad_v.mix~mixers/FMU_quad_v.mix \ + $(SRCROOT)/mixers/FMU_quad_v.mix~mixers/FMU_quad_v.mix \ + $(SRCROOT)/mixers/FMU_quad_v.mix~mixers/FMU_quad_w.mix \ $(SRCROOT)/mixers/FMU_hex_x.mix~mixers/FMU_hex_x.mix \ $(SRCROOT)/mixers/FMU_hex_+.mix~mixers/FMU_hex_+.mix \ $(SRCROOT)/mixers/FMU_octo_x.mix~mixers/FMU_octo_x.mix \ diff --git a/apps/systemlib/mixer/mixer.h b/apps/systemlib/mixer/mixer.h index 40d37fce2b..bbfa130a9d 100644 --- a/apps/systemlib/mixer/mixer.h +++ b/apps/systemlib/mixer/mixer.h @@ -419,6 +419,7 @@ public: QUAD_X = 0, /**< quad in X configuration */ QUAD_PLUS, /**< quad in + configuration */ QUAD_V, /**< quad in V configuration */ + QUAD_WIDE, /**< quad in wide configuration */ HEX_X, /**< hex in X configuration */ HEX_PLUS, /**< hex in + configuration */ OCTA_X, diff --git a/apps/systemlib/mixer/mixer_multirotor.cpp b/apps/systemlib/mixer/mixer_multirotor.cpp index d79811c0ff..8ded0b05c1 100644 --- a/apps/systemlib/mixer/mixer_multirotor.cpp +++ b/apps/systemlib/mixer/mixer_multirotor.cpp @@ -88,6 +88,12 @@ const MultirotorMixer::Rotor _config_quad_v[] = { { 0.927184, 0.374607, -1.00 }, { -0.694658, -0.719340, -1.00 }, }; +const MultirotorMixer::Rotor _config_quad_wide[] = { + { -0.927184, 0.374607, 1.00 }, + { 0.777146, -0.629320, 1.00 }, + { 0.927184, 0.374607, -1.00 }, + { -0.777146, -0.629320, -1.00 }, +}; const MultirotorMixer::Rotor _config_hex_x[] = { { -1.000000, 0.000000, -1.00 }, { 1.000000, 0.000000, 1.00 }, @@ -128,6 +134,7 @@ const MultirotorMixer::Rotor *_config_index[MultirotorMixer::Geometry::MAX_GEOME &_config_quad_x[0], &_config_quad_plus[0], &_config_quad_v[0], + &_config_quad_wide[0], &_config_hex_x[0], &_config_hex_plus[0], &_config_octa_x[0], @@ -137,6 +144,7 @@ const unsigned _config_rotor_count[MultirotorMixer::Geometry::MAX_GEOMETRY] = { 4, /* quad_x */ 4, /* quad_plus */ 4, /* quad_v */ + 4, /* quad_wide */ 6, /* hex_x */ 6, /* hex_plus */ 8, /* octa_x */ @@ -195,6 +203,9 @@ MultirotorMixer::from_text(Mixer::ControlCallback control_cb, uintptr_t cb_handl } else if (!strcmp(geomname, "4v")) { geometry = MultirotorMixer::QUAD_V; + } else if (!strcmp(geomname, "4w")) { + geometry = MultirotorMixer::QUAD_WIDE; + } else if (!strcmp(geomname, "6+")) { geometry = MultirotorMixer::HEX_PLUS; diff --git a/apps/systemlib/mixer/multi_tables b/apps/systemlib/mixer/multi_tables index 19a8239a6d..683c630409 100755 --- a/apps/systemlib/mixer/multi_tables +++ b/apps/systemlib/mixer/multi_tables @@ -27,6 +27,13 @@ set quad_v { 136 CW } +set quad_wide { + 68 CCW + -129 CCW + -68 CW + 129 CW +} + set hex_x { 90 CW -90 CCW @@ -67,7 +74,7 @@ set octa_plus { 90 CW } -set tables {quad_x quad_plus quad_v hex_x hex_plus octa_x octa_plus} +set tables {quad_x quad_plus quad_v quad_wide hex_x hex_plus octa_x octa_plus} proc factors {a d} { puts [format "\t{ %9.6f, %9.6f, %5.2f }," [rcos [expr $a + 90]] [rcos $a] [expr -$d]]} From d9da4352d590401ec5caeef926cf25109da393e9 Mon Sep 17 00:00:00 2001 From: Simon Wilks Date: Thu, 2 May 2013 07:13:07 +0200 Subject: [PATCH 28/84] Makefile correction. --- ROMFS/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROMFS/Makefile b/ROMFS/Makefile index ecd15d5e27..e776684212 100644 --- a/ROMFS/Makefile +++ b/ROMFS/Makefile @@ -33,7 +33,7 @@ ROMFS_FSSPEC := $(SRCROOT)/scripts/rcS~init.d/rcS \ $(SRCROOT)/mixers/FMU_quad_x.mix~mixers/FMU_quad_x.mix \ $(SRCROOT)/mixers/FMU_quad_+.mix~mixers/FMU_quad_+.mix \ $(SRCROOT)/mixers/FMU_quad_v.mix~mixers/FMU_quad_v.mix \ - $(SRCROOT)/mixers/FMU_quad_v.mix~mixers/FMU_quad_w.mix \ + $(SRCROOT)/mixers/FMU_quad_w.mix~mixers/FMU_quad_w.mix \ $(SRCROOT)/mixers/FMU_hex_x.mix~mixers/FMU_hex_x.mix \ $(SRCROOT)/mixers/FMU_hex_+.mix~mixers/FMU_hex_+.mix \ $(SRCROOT)/mixers/FMU_octo_x.mix~mixers/FMU_octo_x.mix \ From 1dbbdcfa48f8acbf4bed5c160ab3acd0cf293127 Mon Sep 17 00:00:00 2001 From: Simon Wilks Date: Thu, 2 May 2013 08:41:02 +0200 Subject: [PATCH 29/84] Add the missing mixer file. --- ROMFS/mixers/FMU_quad_w.mix | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 ROMFS/mixers/FMU_quad_w.mix diff --git a/ROMFS/mixers/FMU_quad_w.mix b/ROMFS/mixers/FMU_quad_w.mix new file mode 100644 index 0000000000..81b4af30b2 --- /dev/null +++ b/ROMFS/mixers/FMU_quad_w.mix @@ -0,0 +1,6 @@ +Multirotor mixer for PX4FMU +=========================== + +This file defines a single mixer for a quadrotor with a wide configuration. All controls are mixed 100%. + +R: 4w 10000 10000 10000 0 From b9b75a24045da332644ce397d2777d9d554ff39f Mon Sep 17 00:00:00 2001 From: Lorenz Meier Date: Thu, 2 May 2013 22:35:16 +0200 Subject: [PATCH 30/84] Hotfix: Provide a FMU + IO on quad start script --- ROMFS/Makefile | 3 +- ROMFS/scripts/rc.IO_QUAD | 107 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 ROMFS/scripts/rc.IO_QUAD diff --git a/ROMFS/Makefile b/ROMFS/Makefile index 11a4650fa6..5ff079a930 100644 --- a/ROMFS/Makefile +++ b/ROMFS/Makefile @@ -24,6 +24,7 @@ ROMFS_FSSPEC := $(SRCROOT)/scripts/rcS~init.d/rcS \ $(SRCROOT)/scripts/rc.FMU_quad_x~init.d/rc.FMU_quad_x \ $(SRCROOT)/scripts/rc.usb~init.d/rc.usb \ $(SRCROOT)/scripts/rc.hil~init.d/rc.hil \ + $(SRCROOT)/scripts/rc.IO_QUAD~scripts/rc.IO_QUAD \ $(SRCROOT)/mixers/FMU_pass.mix~mixers/FMU_pass.mix \ $(SRCROOT)/mixers/FMU_Q.mix~mixers/FMU_Q.mix \ $(SRCROOT)/mixers/FMU_X5.mix~mixers/FMU_X5.mix \ @@ -32,7 +33,7 @@ ROMFS_FSSPEC := $(SRCROOT)/scripts/rcS~init.d/rcS \ $(SRCROOT)/mixers/FMU_RET.mix~mixers/FMU_ERT.mix \ $(SRCROOT)/mixers/FMU_quad_x.mix~mixers/FMU_quad_x.mix \ $(SRCROOT)/mixers/FMU_quad_+.mix~mixers/FMU_quad_+.mix \ - $(SRCROOT)/mixers/FMU_quad_v.mix~mixers/FMU_quad_v.mix \ + $(SRCROOT)/mixers/FMU_quad_v.mix~mixers/FMU_quad_v.mix \ $(SRCROOT)/mixers/FMU_hex_x.mix~mixers/FMU_hex_x.mix \ $(SRCROOT)/mixers/FMU_hex_+.mix~mixers/FMU_hex_+.mix \ $(SRCROOT)/mixers/FMU_octo_x.mix~mixers/FMU_octo_x.mix \ diff --git a/ROMFS/scripts/rc.IO_QUAD b/ROMFS/scripts/rc.IO_QUAD new file mode 100644 index 0000000000..287cb0483b --- /dev/null +++ b/ROMFS/scripts/rc.IO_QUAD @@ -0,0 +1,107 @@ +#!nsh + +# Disable USB and autostart +set USB no +set MODE quad + +# +# Start the ORB (first app to start) +# +uorb start + +# +# Load microSD params +# +echo "[init] loading microSD params" +param select /fs/microsd/parameters +if [ -f /fs/microsd/parameters ] +then + param load /fs/microsd/parameters +fi + +# +# Force some key parameters to sane values +# MAV_TYPE 1 = fixed wing, 2 = quadrotor, 13 = hexarotor +# see https://pixhawk.ethz.ch/mavlink/ +# +param set MAV_TYPE 2 + +# +# Check if PX4IO Firmware should be upgraded (from Andrew Tridgell) +# +if [ -f /fs/microsd/px4io.bin ] +then + echo "PX4IO Firmware found. Checking Upgrade.." + if cmp /fs/microsd/px4io.bin /fs/microsd/px4io.bin.current + then + echo "No newer version, skipping upgrade." + else + echo "Loading /fs/microsd/px4io.bin" + if px4io update /fs/microsd/px4io.bin > /fs/microsd/px4io_update.log + then + cp /fs/microsd/px4io.bin /fs/microsd/px4io.bin.current + echo "Flashed /fs/microsd/px4io.bin OK" >> /fs/microsd/px4io_update.log + else + echo "Failed flashing /fs/microsd/px4io.bin" >> /fs/microsd/px4io_update.log + echo "Failed to upgrade PX4IO firmware - check if PX4IO is in bootloader mode" + fi + fi +fi + +# +# Start MAVLink (depends on orb) +# +mavlink start -d /dev/ttyS1 -b 57600 +usleep 5000 + +# +# Start the commander (depends on orb, mavlink) +# +commander start + +# +# Start PX4IO interface (depends on orb, commander) +# +px4io start + +# +# Allow PX4IO to recover from midair restarts. +# this is very unlikely, but quite safe and robust. +px4io recovery + +# +# Start the sensors (depends on orb, px4io) +# +sh /etc/init.d/rc.sensors + +# +# Start GPS interface (depends on orb) +# +gps start + +# +# Start the attitude estimator (depends on orb) +# +attitude_estimator_ekf start + +# +# Load mixer and start controllers (depends on px4io) +# +mixer load /dev/pwm_output /etc/mixers/FMU_quad_+.mix +multirotor_att_control start + +# +# Start logging +# +#sdlog start -s 4 + +# +# Start system state +# +if blinkm start +then + echo "using BlinkM for state indication" + blinkm systemstate +else + echo "no BlinkM found, OK." +fi \ No newline at end of file From 6e8c1148d5fb6567974f3e5464e45637dc6ce68b Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 4 May 2013 11:42:31 +1000 Subject: [PATCH 31/84] build: allow absolute paths for module sources --- makefiles/module.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefiles/module.mk b/makefiles/module.mk index 59c67f574d..0fe6f0ffec 100644 --- a/makefiles/module.mk +++ b/makefiles/module.mk @@ -183,7 +183,7 @@ module: $(MODULE_OBJ) $(MODULE_COMMAND_FILES) # Locate sources (allows relative source paths in module.mk) # define SRC_SEARCH - $(abspath $(firstword $(wildcard $(MODULE_SRC)/$1) MISSING_$1)) + $(abspath $(firstword $(wildcard $1) $(wildcard $(MODULE_SRC)/$1) MISSING_$1)) endef ABS_SRCS ?= $(foreach src,$(SRCS),$(call SRC_SEARCH,$(src))) From aa9275c29ce90644448f0260d782ea68f21eacc7 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 4 May 2013 11:42:56 +1000 Subject: [PATCH 32/84] build: allow additional flags to be passed via EXTRAFLAGS this allows for flags needed for the APM build --- makefiles/toolchain_gnu-arm-eabi.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/makefiles/toolchain_gnu-arm-eabi.mk b/makefiles/toolchain_gnu-arm-eabi.mk index 5e6a5bf04b..32a2773732 100644 --- a/makefiles/toolchain_gnu-arm-eabi.mk +++ b/makefiles/toolchain_gnu-arm-eabi.mk @@ -189,7 +189,7 @@ DEP_INCLUDES = $(subst .o,.d,$(OBJS)) define COMPILE @$(ECHO) "CC: $1" @$(MKDIR) -p $(dir $2) - $(Q) $(CC) -MD -c $(CFLAGS) $(abspath $1) -o $2 + $(Q) $(CC) -MD -c $(CFLAGS) $(EXTRAFLAGS) $(abspath $1) -o $2 endef # Compile C++ source $1 to $2 @@ -198,7 +198,7 @@ endef define COMPILEXX @$(ECHO) "CXX: $1" @$(MKDIR) -p $(dir $2) - $(Q) $(CXX) -MD -c $(CXXFLAGS) $(abspath $1) -o $2 + $(Q) $(CXX) -MD -c $(CXXFLAGS) $(EXTRAFLAGS) $(abspath $1) -o $2 endef # Assemble $1 into $2 @@ -206,7 +206,7 @@ endef define ASSEMBLE @$(ECHO) "AS: $1" @$(MKDIR) -p $(dir $2) - $(Q) $(CC) -c $(AFLAGS) $(abspath $1) -o $2 + $(Q) $(CC) -c $(AFLAGS) $(EXTRAFLAGS) $(abspath $1) -o $2 endef # Produce partially-linked $1 from files in $2 From d0122dccfc28869414f0e9cd2cb1d9f131c3fd20 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 4 May 2013 18:44:37 +1000 Subject: [PATCH 33/84] hmc5883: fixed use of onboard I2C compass --- src/drivers/hmc5883/hmc5883.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/drivers/hmc5883/hmc5883.cpp b/src/drivers/hmc5883/hmc5883.cpp index c406a7588a..78eda327c3 100644 --- a/src/drivers/hmc5883/hmc5883.cpp +++ b/src/drivers/hmc5883/hmc5883.cpp @@ -1225,19 +1225,25 @@ start() /* create the driver, attempt expansion bus first */ g_dev = new HMC5883(PX4_I2C_BUS_EXPANSION); + if (g_dev != nullptr && OK != g_dev->init()) { + delete g_dev; + g_dev = nullptr; + } + #ifdef PX4_I2C_BUS_ONBOARD /* if this failed, attempt onboard sensor */ - if (g_dev == nullptr) + if (g_dev == nullptr) { g_dev = new HMC5883(PX4_I2C_BUS_ONBOARD); + if (g_dev != nullptr && OK != g_dev->init()) { + goto fail; + } + } #endif if (g_dev == nullptr) goto fail; - if (OK != g_dev->init()) - goto fail; - /* set the poll rate to default, starts automatic data collection */ fd = open(MAG_DEVICE_PATH, O_RDONLY); From a627f6c0eba3cfb0471b0ff88652d85c6d7cb0ca Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 20 Mar 2013 11:06:33 +1100 Subject: [PATCH 34/84] otgfsdev: removed a DEBUGASSERT() that causes a crash on windows reconnect when windows reconnects to a ACM device, this assert sometimes triggered. The case it is looking for is handled further down. --- nuttx/arch/arm/src/stm32/stm32_otgfsdev.c | 1 - 1 file changed, 1 deletion(-) diff --git a/nuttx/arch/arm/src/stm32/stm32_otgfsdev.c b/nuttx/arch/arm/src/stm32/stm32_otgfsdev.c index 2c9ae4cacb..0fcd463e05 100644 --- a/nuttx/arch/arm/src/stm32/stm32_otgfsdev.c +++ b/nuttx/arch/arm/src/stm32/stm32_otgfsdev.c @@ -1512,7 +1512,6 @@ static inline void stm32_ep0out_receive(FAR struct stm32_ep_s *privep, int bcnt) DEBUGASSERT(privep && privep->ep.priv); priv = (FAR struct stm32_usbdev_s *)privep->ep.priv; - DEBUGASSERT(priv->ep0state == EP0STATE_SETUP_OUT); ullvdbg("EP0: bcnt=%d\n", bcnt); usbtrace(TRACE_READ(EP0), bcnt); From b06098a5406cf3269a313362b43d7f47b160933b Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 17 Apr 2013 21:19:19 +1000 Subject: [PATCH 35/84] libdtoa: fixed handling of NaN and Infinity otherwise we print thousands of 00000 characters --- nuttx/libc/stdio/lib_libdtoa.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/nuttx/libc/stdio/lib_libdtoa.c b/nuttx/libc/stdio/lib_libdtoa.c index 29f61fd76e..84e3ee50b7 100644 --- a/nuttx/libc/stdio/lib_libdtoa.c +++ b/nuttx/libc/stdio/lib_libdtoa.c @@ -43,6 +43,7 @@ /**************************************************************************** * Included Files ****************************************************************************/ +#include /**************************************************************************** * Pre-processor Definitions @@ -104,6 +105,13 @@ static void zeroes(FAR struct lib_outstream_s *obj, int nzeroes) * Private Functions ****************************************************************************/ +static void lib_dtoa_string(FAR struct lib_outstream_s *obj, const char *str) +{ + while (*str) { + obj->put(obj, *str++); + } +} + /**************************************************************************** * Name: lib_dtoa * @@ -138,8 +146,21 @@ static void lib_dtoa(FAR struct lib_outstream_s *obj, int fmt, int prec, int dsgn; /* Unused sign indicator */ int i; - /* Non-zero... positive or negative */ + /* special handling for NaN and Infinity */ + if (isnan(value)) { + lib_dtoa_string(obj, "NaN"); + return; + } + if (isinf(value)) { + if (value < 0.0d) { + obj->put(obj, '-'); + } + lib_dtoa_string(obj, "Infinity"); + return; + } + /* Non-zero... positive or negative */ + if (value < 0) { value = -value; From 421253e6db6c5e716c84ac505a8caef679ea97ee Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 21 Apr 2013 14:28:56 +1000 Subject: [PATCH 36/84] px4io: allow set of output rates above 400 and below 50 let the IO board decide if the rate is reasonable, and limit it there this fixes the rates on ArduCopter, which try for 490 --- src/drivers/px4io/px4io.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/drivers/px4io/px4io.cpp b/src/drivers/px4io/px4io.cpp index 4c2f1736f9..d8b5c51c43 100644 --- a/src/drivers/px4io/px4io.cpp +++ b/src/drivers/px4io/px4io.cpp @@ -1336,11 +1336,7 @@ PX4IO::ioctl(file *filep, int cmd, unsigned long arg) case PWM_SERVO_SET_UPDATE_RATE: /* set the requested alternate rate */ - if ((arg >= 50) && (arg <= 400)) { /* TODO: we could go higher for e.g. TurboPWM */ - ret = io_reg_set(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_PWM_ALTRATE, arg); - } else { - ret = -EINVAL; - } + ret = io_reg_set(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_PWM_ALTRATE, arg); break; case PWM_SERVO_SELECT_UPDATE_RATE: { From fc572906b7693d910ded443632e8608b200a7933 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 25 Apr 2013 20:11:25 +1000 Subject: [PATCH 37/84] px4io: ensure upload device is closed after use this should release it for PWM use --- src/drivers/px4io/uploader.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/drivers/px4io/uploader.cpp b/src/drivers/px4io/uploader.cpp index 9a67875e86..15524c3aeb 100644 --- a/src/drivers/px4io/uploader.cpp +++ b/src/drivers/px4io/uploader.cpp @@ -127,6 +127,8 @@ PX4IO_Uploader::upload(const char *filenames[]) if (ret != OK) { /* this is immediately fatal */ log("bootloader not responding"); + close(_io_fd); + _io_fd = -1; return -EIO; } @@ -145,18 +147,25 @@ PX4IO_Uploader::upload(const char *filenames[]) if (filename == NULL) { log("no firmware found"); + close(_io_fd); + _io_fd = -1; return -ENOENT; } struct stat st; if (stat(filename, &st) != 0) { log("Failed to stat %s - %d\n", filename, (int)errno); + close(_io_fd); + _io_fd = -1; return -errno; } fw_size = st.st_size; - if (_fw_fd == -1) + if (_fw_fd == -1) { + close(_io_fd); + _io_fd = -1; return -ENOENT; + } /* do the usual program thing - allow for failure */ for (unsigned retries = 0; retries < 1; retries++) { @@ -167,6 +176,8 @@ PX4IO_Uploader::upload(const char *filenames[]) if (ret != OK) { /* this is immediately fatal */ log("bootloader not responding"); + close(_io_fd); + _io_fd = -1; return -EIO; } } @@ -178,6 +189,8 @@ PX4IO_Uploader::upload(const char *filenames[]) log("found bootloader revision: %d", bl_rev); } else { log("found unsupported bootloader revision %d, exiting", bl_rev); + close(_io_fd); + _io_fd = -1; return OK; } } @@ -221,6 +234,8 @@ PX4IO_Uploader::upload(const char *filenames[]) } close(_fw_fd); + close(_io_fd); + _io_fd = -1; return ret; } From ff7712ca3e752141e54f3cbf15198a62429617f7 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 25 Apr 2013 20:13:03 +1000 Subject: [PATCH 38/84] pwm: added -m option this allows setting of the channel mask directly, which is useful for testing --- src/systemcmds/pwm/pwm.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/systemcmds/pwm/pwm.c b/src/systemcmds/pwm/pwm.c index de7a531993..08e6c88dfa 100644 --- a/src/systemcmds/pwm/pwm.c +++ b/src/systemcmds/pwm/pwm.c @@ -71,13 +71,14 @@ usage(const char *reason) warnx("%s", reason); errx(1, "usage:\n" - "pwm [-v] [-d ] [-u ] [-c ] [arm|disarm] [ ...]\n" + "pwm [-v] [-d ] [-u ] [-c ] [-m chanmask ] [arm|disarm] [ ...]\n" " -v Print information about the PWM device\n" " PWM output device (defaults to " PWM_OUTPUT_DEVICE_PATH ")\n" " PWM update rate for channels in \n" " Channel group that should update at the alternate rate (may be specified more than once)\n" " arm | disarm Arm or disarm the ouptut\n" " ... PWM output values in microseconds to assign to the PWM outputs\n" + " Directly supply alt rate channel mask\n" "\n" "When -c is specified, any channel groups not listed with -c will update at the default rate.\n" ); @@ -96,11 +97,12 @@ pwm_main(int argc, char *argv[]) int ret; char *ep; unsigned group; + int32_t set_mask = -1; if (argc < 2) usage(NULL); - while ((ch = getopt(argc, argv, "c:d:u:v")) != EOF) { + while ((ch = getopt(argc, argv, "c:d:u:vm:")) != EOF) { switch (ch) { case 'c': group = strtoul(optarg, &ep, 0); @@ -120,6 +122,12 @@ pwm_main(int argc, char *argv[]) usage("bad alt_rate value"); break; + case 'm': + set_mask = strtol(optarg, &ep, 0); + if (*ep != '\0') + usage("bad set_mask value"); + break; + case 'v': print_info = true; break; @@ -143,6 +151,13 @@ pwm_main(int argc, char *argv[]) err(1, "PWM_SERVO_SET_UPDATE_RATE (check rate for sanity)"); } + /* directly supplied channel mask */ + if (set_mask != -1) { + ret = ioctl(fd, PWM_SERVO_SELECT_UPDATE_RATE, set_mask); + if (ret != OK) + err(1, "PWM_SERVO_SELECT_UPDATE_RATE"); + } + /* assign alternate rate to channel groups */ if (alt_channels_set) { uint32_t mask = 0; From a153ee529f68e9b52805b8c77da1ec2bf0e54210 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 25 Apr 2013 22:22:16 +1000 Subject: [PATCH 39/84] libdtoa: don't print trailing zeros if no decimal is printed --- nuttx/libc/stdio/lib_libdtoa.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/nuttx/libc/stdio/lib_libdtoa.c b/nuttx/libc/stdio/lib_libdtoa.c index 84e3ee50b7..395a55b61b 100644 --- a/nuttx/libc/stdio/lib_libdtoa.c +++ b/nuttx/libc/stdio/lib_libdtoa.c @@ -145,6 +145,7 @@ static void lib_dtoa(FAR struct lib_outstream_s *obj, int fmt, int prec, int nchars; /* Number of characters to print */ int dsgn; /* Unused sign indicator */ int i; + bool done_decimal_point = false; /* special handling for NaN and Infinity */ if (isnan(value)) { @@ -199,6 +200,7 @@ static void lib_dtoa(FAR struct lib_outstream_s *obj, int fmt, int prec, if (prec > 0 || IS_ALTFORM(flags)) { obj->put(obj, '.'); + done_decimal_point = true; /* Always print at least one digit to the right of the decimal point. */ @@ -224,6 +226,7 @@ static void lib_dtoa(FAR struct lib_outstream_s *obj, int fmt, int prec, /* Print the decimal point */ obj->put(obj, '.'); + done_decimal_point = true; /* Print any leading zeros to the right of the decimal point */ @@ -270,6 +273,7 @@ static void lib_dtoa(FAR struct lib_outstream_s *obj, int fmt, int prec, /* Print the decimal point */ obj->put(obj, '.'); + done_decimal_point = true; /* Always print at least one digit to the right of the decimal * point. @@ -306,8 +310,9 @@ static void lib_dtoa(FAR struct lib_outstream_s *obj, int fmt, int prec, } /* Finally, print any trailing zeroes */ - - zeroes(obj, prec); + if (done_decimal_point) { + zeroes(obj, prec); + } /* Is this memory supposed to be freed or not? */ From 953acbe65014e2b2305c4338ca3711622fda3fdd Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 25 Apr 2013 22:22:45 +1000 Subject: [PATCH 40/84] libvsprintf: fixed handling of "%f" to print precision 6 --- nuttx/libc/stdio/lib_libvsprintf.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nuttx/libc/stdio/lib_libvsprintf.c b/nuttx/libc/stdio/lib_libvsprintf.c index 9a391610dc..3d26ff810e 100644 --- a/nuttx/libc/stdio/lib_libvsprintf.c +++ b/nuttx/libc/stdio/lib_libvsprintf.c @@ -1215,7 +1215,7 @@ int lib_vsprintf(FAR struct lib_outstream_s *obj, FAR const char *src, va_list a fmt = FMT_RJUST; width = 0; #ifdef CONFIG_LIBC_FLOATINGPOINT - trunc = 0; + trunc = 6; #endif #endif @@ -1245,6 +1245,9 @@ int lib_vsprintf(FAR struct lib_outstream_s *obj, FAR const char *src, va_list a { #ifndef CONFIG_NOPRINTF_FIELDWIDTH fmt = FMT_RJUST0; + if (IS_HASDOT(flags)) { + trunc = 0; + } #endif } #if 0 From 5b3844621ca1c0a6181e49166c5c12f3000f6802 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 28 Apr 2013 14:07:50 +1000 Subject: [PATCH 41/84] stdio: fixed build error for stdio on px4io --- nuttx/libc/stdio/lib_libvsprintf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nuttx/libc/stdio/lib_libvsprintf.c b/nuttx/libc/stdio/lib_libvsprintf.c index 3d26ff810e..2cc7950f7b 100644 --- a/nuttx/libc/stdio/lib_libvsprintf.c +++ b/nuttx/libc/stdio/lib_libvsprintf.c @@ -1245,9 +1245,11 @@ int lib_vsprintf(FAR struct lib_outstream_s *obj, FAR const char *src, va_list a { #ifndef CONFIG_NOPRINTF_FIELDWIDTH fmt = FMT_RJUST0; +#ifdef CONFIG_LIBC_FLOATINGPOINT if (IS_HASDOT(flags)) { trunc = 0; } +#endif #endif } #if 0 From 44015d69154062d42ecc3aa0c9b25d7019bd5a71 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 1 May 2013 15:06:13 +1000 Subject: [PATCH 42/84] px4io: return raw ADC value for current we don't know how to scale it as we have no info on what sensor is attached. As we are returning a uint16_t it is better to let the FMU sort it out or we'll just lose precision. --- src/modules/px4iofirmware/protocol.h | 4 +--- src/modules/px4iofirmware/registers.c | 16 ++++++++-------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/modules/px4iofirmware/protocol.h b/src/modules/px4iofirmware/protocol.h index 8d8b7e941b..b80551a077 100644 --- a/src/modules/px4iofirmware/protocol.h +++ b/src/modules/px4iofirmware/protocol.h @@ -115,7 +115,7 @@ #define PX4IO_P_STATUS_ALARMS_PWM_ERROR (1 << 6) /* PWM configuration or output was bad */ #define PX4IO_P_STATUS_VBATT 4 /* battery voltage in mV */ -#define PX4IO_P_STATUS_IBATT 5 /* battery current in cA */ +#define PX4IO_P_STATUS_IBATT 5 /* battery current (raw ADC) */ /* array of post-mix actuator outputs, -10000..10000 */ #define PX4IO_PAGE_ACTUATORS 2 /* 0..CONFIG_ACTUATOR_COUNT-1 */ @@ -155,8 +155,6 @@ #define PX4IO_P_SETUP_PWM_ALTRATE 4 /* 'high' PWM frame output rate in Hz */ #define PX4IO_P_SETUP_RELAYS 5 /* bitmask of relay/switch outputs, 0 = off, 1 = on */ #define PX4IO_P_SETUP_VBATT_SCALE 6 /* battery voltage correction factor (float) */ -#define PX4IO_P_SETUP_IBATT_SCALE 7 /* battery current scaling factor (float) */ -#define PX4IO_P_SETUP_IBATT_BIAS 8 /* battery current bias value */ #define PX4IO_P_SETUP_SET_DEBUG 9 /* debug level for IO board */ /* autopilot control values, -10000..10000 */ diff --git a/src/modules/px4iofirmware/registers.c b/src/modules/px4iofirmware/registers.c index 6c09def9ee..9f9c50048d 100644 --- a/src/modules/px4iofirmware/registers.c +++ b/src/modules/px4iofirmware/registers.c @@ -138,8 +138,6 @@ volatile uint16_t r_page_setup[] = [PX4IO_P_SETUP_PWM_ALTRATE] = 200, [PX4IO_P_SETUP_RELAYS] = 0, [PX4IO_P_SETUP_VBATT_SCALE] = 10000, - [PX4IO_P_SETUP_IBATT_SCALE] = 0, - [PX4IO_P_SETUP_IBATT_BIAS] = 0, [PX4IO_P_SETUP_SET_DEBUG] = 0, }; @@ -516,12 +514,14 @@ registers_get(uint8_t page, uint8_t offset, uint16_t **values, unsigned *num_val /* PX4IO_P_STATUS_IBATT */ { - unsigned counts = adc_measure(ADC_VBATT); - unsigned scaled = (counts * r_page_setup[PX4IO_P_SETUP_IBATT_SCALE]) / 10000; - int corrected = scaled + REG_TO_SIGNED(r_page_setup[PX4IO_P_SETUP_IBATT_BIAS]); - if (corrected < 0) - corrected = 0; - r_page_status[PX4IO_P_STATUS_IBATT] = corrected; + /* + note that we have no idea what sort of + current sensor is attached, so we just + return the raw 12 bit ADC value and let the + FMU sort it out, with user selectable + configuration for their sensor + */ + r_page_status[PX4IO_P_STATUS_IBATT] = adc_measure(ADC_IN5); } SELECT_PAGE(r_page_status); From af27101ffecf2ad4642b1ced23640ff133c7246f Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 2 May 2013 21:27:20 +1000 Subject: [PATCH 43/84] px4io: changed adc_measure() to return 0xffff on error, and lower timeout the timeout of 1ms was far too long, and could impact flight performance Returning 0xffff on error matches the FMU code, and allows bad values to be discarded --- src/modules/px4iofirmware/adc.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/modules/px4iofirmware/adc.c b/src/modules/px4iofirmware/adc.c index 670b8d635d..f744698be2 100644 --- a/src/modules/px4iofirmware/adc.c +++ b/src/modules/px4iofirmware/adc.c @@ -135,6 +135,9 @@ adc_init(void) return 0; } +/* + return one measurement, or 0xffff on error + */ uint16_t adc_measure(unsigned channel) { @@ -154,9 +157,10 @@ adc_measure(unsigned channel) while (!(rSR & ADC_SR_EOC)) { /* never spin forever - this will give a bogus result though */ - if (hrt_elapsed_time(&now) > 1000) { + if (hrt_elapsed_time(&now) > 100) { debug("adc timeout"); - break; + perf_end(adc_perf); + return 0xffff; } } @@ -165,4 +169,4 @@ adc_measure(unsigned channel) perf_end(adc_perf); return result; -} \ No newline at end of file +} From d7e04a361909fb65839fb8f2ab515ea17e5f6d77 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 2 May 2013 21:28:55 +1000 Subject: [PATCH 44/84] px4io: fixed voltage/current output and add discharged_mah calculation this integrates the current over time to calculate discharged_mah, and allows the scaling of the current and the bias to be set with the px4io command --- src/drivers/px4io/px4io.cpp | 70 ++++++++++++++++++++++++++++++------- 1 file changed, 58 insertions(+), 12 deletions(-) diff --git a/src/drivers/px4io/px4io.cpp b/src/drivers/px4io/px4io.cpp index d8b5c51c43..b4703839bf 100644 --- a/src/drivers/px4io/px4io.cpp +++ b/src/drivers/px4io/px4io.cpp @@ -108,6 +108,14 @@ public: */ int set_update_rate(int rate); + /** + * Set the battery current scaling and bias + * + * @param amp_per_volt + * @param amp_bias + */ + void set_battery_current_scaling(float amp_per_volt, float amp_bias); + /** * Print the current status of IO */ @@ -151,6 +159,10 @@ private: bool _primary_pwm_device; ///< true if we are the default PWM output + float _battery_amp_per_volt; + float _battery_amp_bias; + float _battery_mamphour_total; + uint64_t _battery_last_timestamp; /** * Trampoline to the worker task @@ -314,6 +326,10 @@ PX4IO::PX4IO() : _to_actuators_effective(0), _to_outputs(0), _to_battery(0), + _battery_amp_per_volt(90.0f/5.0f), // this matches the 3DR current sensor + _battery_amp_bias(0), + _battery_mamphour_total(0), + _battery_last_timestamp(0), _primary_pwm_device(false) { /* we need this potentially before it could be set in task_main */ @@ -884,11 +900,22 @@ PX4IO::io_get_status() /* voltage is scaled to mV */ battery_status.voltage_v = regs[2] / 1000.0f; - /* current scaling should be to cA in order to avoid limiting at 65A */ - battery_status.current_a = regs[3] / 100.f; + /* + regs[3] contains the raw ADC count, as 12 bit ADC + value, with full range being 3.3v + */ + battery_status.current_a = regs[3] * (3.3f/4096.0f) * _battery_amp_per_volt; + battery_status.current_a += _battery_amp_bias; - /* this requires integration over time - not currently implemented */ - battery_status.discharged_mah = -1.0f; + /* + integrate battery over time to get total mAh used + */ + if (_battery_last_timestamp != 0) { + _battery_mamphour_total += battery_status.current_a * + (battery_status.timestamp - _battery_last_timestamp) * 1.0e-3f / 3600; + } + battery_status.discharged_mah = _battery_mamphour_total; + _battery_last_timestamp = battery_status.timestamp; /* lazily publish the battery voltage */ if (_to_battery > 0) { @@ -1245,9 +1272,14 @@ PX4IO::print_status() ((alarms & PX4IO_P_STATUS_ALARMS_FMU_LOST) ? " FMU_LOST" : ""), ((alarms & PX4IO_P_STATUS_ALARMS_RC_LOST) ? " RC_LOST" : ""), ((alarms & PX4IO_P_STATUS_ALARMS_PWM_ERROR) ? " PWM_ERROR" : "")); - printf("vbatt %u ibatt %u\n", - io_reg_get(PX4IO_PAGE_STATUS, PX4IO_P_STATUS_VBATT), - io_reg_get(PX4IO_PAGE_STATUS, PX4IO_P_STATUS_IBATT)); + printf("vbatt %u ibatt %u vbatt scale %u\n", + io_reg_get(PX4IO_PAGE_STATUS, PX4IO_P_STATUS_VBATT), + io_reg_get(PX4IO_PAGE_STATUS, PX4IO_P_STATUS_IBATT), + io_reg_get(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_VBATT_SCALE)); + printf("amp_per_volt %.3f amp_offset %.3f mAhDischarged %.3f\n", + _battery_amp_per_volt, + _battery_amp_bias, + _battery_mamphour_total); printf("actuators"); for (unsigned i = 0; i < _max_actuators; i++) printf(" %u", io_reg_get(PX4IO_PAGE_ACTUATORS, i)); @@ -1288,10 +1320,6 @@ PX4IO::print_status() io_reg_get(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_PWM_DEFAULTRATE), io_reg_get(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_PWM_ALTRATE), io_reg_get(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_RELAYS)); - printf("vbatt scale %u ibatt scale %u ibatt bias %u\n", - io_reg_get(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_VBATT_SCALE), - io_reg_get(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_IBATT_SCALE), - io_reg_get(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_IBATT_BIAS)); printf("debuglevel %u\n", io_reg_get(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_SET_DEBUG)); printf("controls"); for (unsigned i = 0; i < _max_controls; i++) @@ -1521,6 +1549,12 @@ PX4IO::set_update_rate(int rate) return 0; } +void +PX4IO::set_battery_current_scaling(float amp_per_volt, float amp_bias) +{ + _battery_amp_per_volt = amp_per_volt; + _battery_amp_bias = amp_bias; +} extern "C" __EXPORT int px4io_main(int argc, char *argv[]); @@ -1658,6 +1692,18 @@ px4io_main(int argc, char *argv[]) exit(0); } + if (!strcmp(argv[1], "current")) { + if (g_dev != nullptr) { + if ((argc > 3)) { + g_dev->set_battery_current_scaling(atof(argv[2]), atof(argv[3])); + } else { + errx(1, "missing argument (apm_per_volt, amp_offset)"); + return 1; + } + } + exit(0); + } + if (!strcmp(argv[1], "recovery")) { if (g_dev != nullptr) { @@ -1785,5 +1831,5 @@ px4io_main(int argc, char *argv[]) monitor(); out: - errx(1, "need a command, try 'start', 'stop', 'status', 'test', 'monitor', 'debug', 'recovery', 'limit' or 'update'"); + errx(1, "need a command, try 'start', 'stop', 'status', 'test', 'monitor', 'debug', 'recovery', 'limit', 'current' or 'update'"); } From 5b75519925a46165b108f1a6d59b6325e1022adc Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 2 May 2013 21:29:30 +1000 Subject: [PATCH 45/84] px4io: handle errors from adc_measure() don't update the voltage/current values on error --- src/modules/px4iofirmware/registers.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/modules/px4iofirmware/registers.c b/src/modules/px4iofirmware/registers.c index 9f9c50048d..4f3addfea8 100644 --- a/src/modules/px4iofirmware/registers.c +++ b/src/modules/px4iofirmware/registers.c @@ -506,10 +506,12 @@ registers_get(uint8_t page, uint8_t offset, uint16_t **values, unsigned *num_val * Intercept corrected for best results @ 12V. */ unsigned counts = adc_measure(ADC_VBATT); - unsigned mV = (4150 + (counts * 46)) / 10 - 200; - unsigned corrected = (mV * r_page_setup[PX4IO_P_SETUP_VBATT_SCALE]) / 10000; + if (counts != 0xffff) { + unsigned mV = (4150 + (counts * 46)) / 10 - 200; + unsigned corrected = (mV * r_page_setup[PX4IO_P_SETUP_VBATT_SCALE]) / 10000; - r_page_status[PX4IO_P_STATUS_VBATT] = corrected; + r_page_status[PX4IO_P_STATUS_VBATT] = corrected; + } } /* PX4IO_P_STATUS_IBATT */ @@ -521,7 +523,10 @@ registers_get(uint8_t page, uint8_t offset, uint16_t **values, unsigned *num_val FMU sort it out, with user selectable configuration for their sensor */ - r_page_status[PX4IO_P_STATUS_IBATT] = adc_measure(ADC_IN5); + unsigned counts = adc_measure(ADC_IN5); + if (counts != 0xffff) { + r_page_status[PX4IO_P_STATUS_IBATT] = counts; + } } SELECT_PAGE(r_page_status); From 1c4fc6cfb0b5d417011df11a0c8705dc344077b8 Mon Sep 17 00:00:00 2001 From: marco Date: Sat, 4 May 2013 20:37:22 +0200 Subject: [PATCH 46/84] Help Parameter added and some small fixes. This Version was flown several Hours without any Problems. --- apps/drivers/mkblctrl/mkblctrl.cpp | 59 ++++++++++++++++-------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/apps/drivers/mkblctrl/mkblctrl.cpp b/apps/drivers/mkblctrl/mkblctrl.cpp index e70bd16945..3a735e26fb 100644 --- a/apps/drivers/mkblctrl/mkblctrl.cpp +++ b/apps/drivers/mkblctrl/mkblctrl.cpp @@ -1,6 +1,6 @@ /**************************************************************************** * - * Copyright (C) 2012 PX4 Development Team. All rights reserved. + * Copyright (C) 2012,2013 PX4 Development Team. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -219,7 +219,7 @@ struct MotorData_t // the following bytes must be exactly in that order! unsigned int Current; // in 0.1 A steps, read back from BL unsigned int MaxPWM; // read back from BL is less than 255 if BL is in current limit - unsigned int Temperature; // old BL-Ctrl will return a 255 here, the new version the temp. in °C + unsigned int Temperature; // old BL-Ctrl will return a 255 here, the new version the temp. in unsigned int RoundCount; }; @@ -1355,28 +1355,26 @@ extern "C" __EXPORT int mkblctrl_main(int argc, char *argv[]); int mkblctrl_main(int argc, char *argv[]) { - PortMode new_mode = PORT_MODE_UNSET; + PortMode port_mode = PORT_FULL_PWM; int pwm_update_rate_in_hz = UPDATE_RATE; - int motorcount = 0; + int motorcount = 8; int bus = 1; - bool motortest = false; int px4mode = MAPPING_PX4; int frametype = FRAME_PLUS; // + plus is default - - new_mode = PORT_FULL_PWM; - motorcount = 8; + bool motortest = false; + bool showHelp = false; + bool newMode = false; /* - * Mode switches. - * - * XXX use getopt? + * optional parameters */ - for (int i = 1; i < argc; i++) { /* argv[0] is "mk" */ + for (int i = 1; i < argc; i++) { /* look for the optional i2c bus parameter */ if (strcmp(argv[i], "-b") == 0 || strcmp(argv[i], "--bus") == 0) { if (argc > i + 1) { bus = atoi(argv[i + 1]); + newMode = true; } else { errx(1, "missing argument for i2c bus (-b)"); return 1; @@ -1388,6 +1386,7 @@ mkblctrl_main(int argc, char *argv[]) if (argc > i + 1) { if(strcmp(argv[i + 1], "+") == 0 || strcmp(argv[i + 1], "x") == 0 || strcmp(argv[i + 1], "X") == 0) { px4mode = MAPPING_MK; + newMode = true; if(strcmp(argv[i + 1], "+") == 0) { frametype = FRAME_PLUS; } else { @@ -1405,30 +1404,36 @@ mkblctrl_main(int argc, char *argv[]) /* look for the optional test parameter */ if (strcmp(argv[i], "-t") == 0) { motortest = true; + newMode = true; + } + + /* look for the optional -h --help parameter */ + if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { + showHelp == true; } } - if(new_mode == PORT_MODE_UNSET) { - fprintf(stderr, "mkblctrl: unrecognised command, try:\n"); - fprintf(stderr, " [-mkmode frame{+/x}] [-b i2c_bus_number] [-t motortest]\n"); + if(showHelp) { + fprintf(stderr, "mkblctrl: help:\n"); + fprintf(stderr, " [-mkmode frame{+/x}] [-b i2c_bus_number] [-t motortest] [-h / --help]\n"); exit(1); } - if (mk_start(bus, motorcount) != OK) - errx(1, "failed to start the MK-BLCtrl driver"); + + if (g_mk == nullptr) { + if (mk_start(bus, motorcount) != OK) { + errx(1, "failed to start the MK-BLCtrl driver"); + } else { + newMode = true; + } + } - /* was a new mode set? */ - if (new_mode != PORT_MODE_UNSET) { - - /* yes but it's the same mode */ - //if (new_mode == g_port_mode) - //return OK; - - /* switch modes */ - fprintf(stderr, "[mkblctrl] %iHz Update Rate\n",pwm_update_rate_in_hz); - return mk_new_mode(new_mode, pwm_update_rate_in_hz, motorcount, motortest, px4mode, frametype); + /* parameter set ? */ + if (newMode) { + /* switch parameter */ + return mk_new_mode(port_mode, pwm_update_rate_in_hz, motorcount, motortest, px4mode, frametype); } /* test, etc. here g*/ From 8c6abe717db1f50c5d4b89f18e27f89608a9a1b8 Mon Sep 17 00:00:00 2001 From: Lorenz Meier Date: Sun, 5 May 2013 11:24:31 +0200 Subject: [PATCH 47/84] Moved BLCTRL driver to new world --- makefiles/config_px4fmu_default.mk | 1 + {apps => src}/drivers/mkblctrl/mkblctrl.cpp | 0 .../Makefile => src/drivers/mkblctrl/module.mk | 10 ++++------ 3 files changed, 5 insertions(+), 6 deletions(-) rename {apps => src}/drivers/mkblctrl/mkblctrl.cpp (100%) rename apps/drivers/mkblctrl/Makefile => src/drivers/mkblctrl/module.mk (87%) diff --git a/makefiles/config_px4fmu_default.mk b/makefiles/config_px4fmu_default.mk index 043c8af40a..07f9bdbc32 100644 --- a/makefiles/config_px4fmu_default.mk +++ b/makefiles/config_px4fmu_default.mk @@ -28,6 +28,7 @@ MODULES += drivers/gps MODULES += drivers/hil MODULES += drivers/hott_telemetry MODULES += drivers/blinkm +MODULES += drivers/mkblctrl MODULES += modules/sensors # diff --git a/apps/drivers/mkblctrl/mkblctrl.cpp b/src/drivers/mkblctrl/mkblctrl.cpp similarity index 100% rename from apps/drivers/mkblctrl/mkblctrl.cpp rename to src/drivers/mkblctrl/mkblctrl.cpp diff --git a/apps/drivers/mkblctrl/Makefile b/src/drivers/mkblctrl/module.mk similarity index 87% rename from apps/drivers/mkblctrl/Makefile rename to src/drivers/mkblctrl/module.mk index b3be2c4687..3ac263b002 100644 --- a/apps/drivers/mkblctrl/Makefile +++ b/src/drivers/mkblctrl/module.mk @@ -1,6 +1,6 @@ ############################################################################ # -# Copyright (C) 2012 PX4 Development Team. All rights reserved. +# Copyright (c) 2012,2013 PX4 Development Team. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -35,10 +35,8 @@ # Interface driver for the Mikrokopter BLCtrl # -APPNAME = mkblctrl -PRIORITY = SCHED_PRIORITY_DEFAULT -STACKSIZE = 2048 +MODULE_COMMAND = mkblctrl -INCLUDES = $(TOPDIR)/arch/arm/src/stm32 $(TOPDIR)/arch/arm/src/common +SRCS = mkblctrl.cpp -include $(APPDIR)/mk/app.mk +INCLUDE_DIRS += $(TOPDIR)/arch/arm/src/stm32 $(TOPDIR)/arch/arm/src/common From bb94847511e76c34cf0fbebe874ed4fd6efe1c0c Mon Sep 17 00:00:00 2001 From: Lorenz Meier Date: Sun, 5 May 2013 11:43:29 +0200 Subject: [PATCH 48/84] Allowed parsing of floating point params from scripts --- src/systemcmds/param/param.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/systemcmds/param/param.c b/src/systemcmds/param/param.c index 56f5317e39..60e61d07b6 100644 --- a/src/systemcmds/param/param.c +++ b/src/systemcmds/param/param.c @@ -1,6 +1,6 @@ /**************************************************************************** * - * Copyright (C) 2012 PX4 Development Team. All rights reserved. + * Copyright (c) 2012, 2013 PX4 Development Team. All rights reserved. * Author: Lorenz Meier * * Redistribution and use in source and binary forms, with or without @@ -34,6 +34,7 @@ /** * @file param.c + * @author Lorenz Meier * * Parameter tool. */ @@ -262,7 +263,7 @@ do_set(const char* name, const char* val) switch (param_type(param)) { case PARAM_TYPE_INT32: if (!param_get(param, &i)) { - printf("old: %d", i); + printf("curr: %d", i); /* convert string */ char* end; @@ -276,14 +277,13 @@ do_set(const char* name, const char* val) case PARAM_TYPE_FLOAT: if (!param_get(param, &f)) { - printf("float values are not yet supported."); - // printf("old: %4.4f", (double)f); + printf("curr: %4.4f", (double)f); - // /* convert string */ - // char* end; - // f = strtof(val,&end); - // param_set(param, &f); - // printf(" -> new: %4.4f\n", f); + /* convert string */ + char* end; + f = strtod(val,&end); + param_set(param, &f); + printf(" -> new: %f\n", f); } From 3466006735123bfd27c94538d98af5b79f47d5a0 Mon Sep 17 00:00:00 2001 From: Lorenz Meier Date: Sun, 5 May 2013 12:57:21 +0200 Subject: [PATCH 49/84] GPS velocity update rate validation for u-blox, WIP --- apps/drivers/gps/gps.cpp | 11 ++- apps/drivers/gps/gps_helper.cpp | 27 +++++- apps/drivers/gps/gps_helper.h | 19 +++- apps/drivers/gps/mtk.cpp | 4 + apps/drivers/gps/mtk.h | 6 +- apps/drivers/gps/ubx.cpp | 162 +++++++++++++++++++------------- apps/drivers/gps/ubx.h | 76 ++++++++++----- 7 files changed, 203 insertions(+), 102 deletions(-) diff --git a/apps/drivers/gps/gps.cpp b/apps/drivers/gps/gps.cpp index e35bdb944a..7db2578160 100644 --- a/apps/drivers/gps/gps.cpp +++ b/apps/drivers/gps/gps.cpp @@ -285,6 +285,11 @@ GPS::task_main() unlock(); if (_Helper->configure(_baudrate) == 0) { unlock(); + + // GPS is obviously detected successfully, reset statistics + _Helper->reset_update_rates(); + warnx("module configuration successful"); + while (_Helper->receive(TIMEOUT_5HZ) > 0 && !_task_should_exit) { // lock(); /* opportunistic publishing - else invalid data would end up on the bus */ @@ -372,7 +377,11 @@ GPS::print_info() warnx("position lock: %dD, last update %4.2f seconds ago", (int)_report.fix_type, (double)((float)(hrt_absolute_time() - _report.timestamp_position) / 1000000.0f)); warnx("lat: %d, lon: %d, alt: %d", _report.lat, _report.lon, _report.alt); - warnx("update rate: %6.2f Hz", (double)_rate); + warnx("rate position: \t%6.2f Hz", (double)_Helper->get_position_update_rate()); + warnx("rate velocity: \t%6.2f Hz", (double)_Helper->get_velocity_update_rate()); + warnx("rate publication:\t%6.2f Hz", (double)_rate); + + _Helper->reset_update_rates(); } usleep(100000); diff --git a/apps/drivers/gps/gps_helper.cpp b/apps/drivers/gps/gps_helper.cpp index 9c1fad5691..b03cccb453 100644 --- a/apps/drivers/gps/gps_helper.cpp +++ b/apps/drivers/gps/gps_helper.cpp @@ -1,6 +1,6 @@ /**************************************************************************** * - * Copyright (C) 2008-2013 PX4 Development Team. All rights reserved. + * Copyright (C) 2012,2013 PX4 Development Team. All rights reserved. * Author: Thomas Gubler * Julian Oes * @@ -36,9 +36,32 @@ #include #include #include +#include #include "gps_helper.h" -/* @file gps_helper.cpp */ +/** + * @file gps_helper.cpp + */ + +float +GPS_Helper::get_position_update_rate() +{ + _rate_count_lat_lon / (((float)(hrt_absolute_time() - _interval_rate_start)) / 1000000.0f); +} + +float +GPS_Helper::get_velocity_update_rate() +{ + _rate_count_vel / (((float)(hrt_absolute_time() - _interval_rate_start)) / 1000000.0f); +} + +float +GPS_Helper::reset_update_rates() +{ + _rate_count_vel = 0; + _rate_count_lat_lon = 0; + _interval_rate_start = hrt_absolute_time(); +} int GPS_Helper::set_baudrate(const int &fd, unsigned baud) diff --git a/apps/drivers/gps/gps_helper.h b/apps/drivers/gps/gps_helper.h index f3d3bc40b3..7e456a6aae 100644 --- a/apps/drivers/gps/gps_helper.h +++ b/apps/drivers/gps/gps_helper.h @@ -1,6 +1,6 @@ /**************************************************************************** * - * Copyright (C) 2008-2013 PX4 Development Team. All rights reserved. + * Copyright (c) 2012, 2013 PX4 Development Team. All rights reserved. * Author: Thomas Gubler * Julian Oes * @@ -33,7 +33,9 @@ * ****************************************************************************/ -/* @file gps_helper.h */ +/** + * @file gps_helper.h + */ #ifndef GPS_HELPER_H #define GPS_HELPER_H @@ -44,9 +46,18 @@ class GPS_Helper { public: - virtual int configure(unsigned &baud) = 0; + virtual int configure(unsigned &baud) = 0; virtual int receive(unsigned timeout) = 0; - int set_baudrate(const int &fd, unsigned baud); + int set_baudrate(const int &fd, unsigned baud); + float get_position_update_rate(); + float get_velocity_update_rate(); + float reset_update_rates(); + +protected: + uint8_t _rate_count_lat_lon; + uint8_t _rate_count_vel; + + uint64_t _interval_rate_start; }; #endif /* GPS_HELPER_H */ diff --git a/apps/drivers/gps/mtk.cpp b/apps/drivers/gps/mtk.cpp index 4762bd503a..62941d74b3 100644 --- a/apps/drivers/gps/mtk.cpp +++ b/apps/drivers/gps/mtk.cpp @@ -263,6 +263,10 @@ MTK::handle_message(gps_mtk_packet_t &packet) _gps_position->time_gps_usec += timeinfo_conversion_temp * 1e3; _gps_position->timestamp_position = _gps_position->timestamp_time = hrt_absolute_time(); + // Position and velocity update always at the same time + _rate_count_vel++; + _rate_count_lat_lon++; + return; } diff --git a/apps/drivers/gps/mtk.h b/apps/drivers/gps/mtk.h index d4e390b01b..b5cfbf0a6d 100644 --- a/apps/drivers/gps/mtk.h +++ b/apps/drivers/gps/mtk.h @@ -87,14 +87,14 @@ class MTK : public GPS_Helper public: MTK(const int &fd, struct vehicle_gps_position_s *gps_position); ~MTK(); - int receive(unsigned timeout); - int configure(unsigned &baudrate); + int receive(unsigned timeout); + int configure(unsigned &baudrate); private: /** * Parse the binary MTK packet */ - int parse_char(uint8_t b, gps_mtk_packet_t &packet); + int parse_char(uint8_t b, gps_mtk_packet_t &packet); /** * Handle the package once it has arrived diff --git a/apps/drivers/gps/ubx.cpp b/apps/drivers/gps/ubx.cpp index c150f52715..e887e8f7c1 100644 --- a/apps/drivers/gps/ubx.cpp +++ b/apps/drivers/gps/ubx.cpp @@ -60,7 +60,8 @@ UBX::UBX(const int &fd, struct vehicle_gps_position_s *gps_position) : _fd(fd), _gps_position(gps_position), -_waiting_for_ack(false) +_waiting_for_ack(false), +_disable_cmd_counter(0) { decode_init(); } @@ -144,7 +145,7 @@ UBX::configure(unsigned &baudrate) cfg_rate_packet.timeRef = UBX_CFG_RATE_PAYLOAD_TIMEREF; send_config_packet(_fd, (uint8_t*)&cfg_rate_packet, sizeof(cfg_rate_packet)); - if (receive(UBX_CONFIG_TIMEOUT) < 0) { + if (wait_for_ack(UBX_CONFIG_TIMEOUT) < 0) { /* try next baudrate */ continue; } @@ -164,74 +165,41 @@ UBX::configure(unsigned &baudrate) cfg_nav5_packet.fixMode = UBX_CFG_NAV5_PAYLOAD_FIXMODE; send_config_packet(_fd, (uint8_t*)&cfg_nav5_packet, sizeof(cfg_nav5_packet)); - if (receive(UBX_CONFIG_TIMEOUT) < 0) { + if (wait_for_ack(UBX_CONFIG_TIMEOUT) < 0) { /* try next baudrate */ continue; } - type_gps_bin_cfg_msg_packet_t cfg_msg_packet; - memset(&cfg_msg_packet, 0, sizeof(cfg_msg_packet)); - - _clsID_needed = UBX_CLASS_CFG; - _msgID_needed = UBX_MESSAGE_CFG_MSG; - - cfg_msg_packet.clsID = UBX_CLASS_CFG; - cfg_msg_packet.msgID = UBX_MESSAGE_CFG_MSG; - cfg_msg_packet.length = UBX_CFG_MSG_LENGTH; - /* Choose fast 5Hz rate for all messages except SVINFO which is big and not important */ - cfg_msg_packet.rate[1] = UBX_CFG_MSG_PAYLOAD_RATE1_5HZ; - - cfg_msg_packet.msgClass_payload = UBX_CLASS_NAV; - cfg_msg_packet.msgID_payload = UBX_MESSAGE_NAV_POSLLH; - - send_config_packet(_fd, (uint8_t*)&cfg_msg_packet, sizeof(cfg_msg_packet)); - if (receive(UBX_CONFIG_TIMEOUT) < 0) { - /* try next baudrate */ - continue; - } - - cfg_msg_packet.msgClass_payload = UBX_CLASS_NAV; - cfg_msg_packet.msgID_payload = UBX_MESSAGE_NAV_TIMEUTC; - - send_config_packet(_fd, (uint8_t*)&cfg_msg_packet, sizeof(cfg_msg_packet)); - if (receive(UBX_CONFIG_TIMEOUT) < 0) { - /* try next baudrate */ - continue; - } - - cfg_msg_packet.msgClass_payload = UBX_CLASS_NAV; - cfg_msg_packet.msgID_payload = UBX_MESSAGE_NAV_SVINFO; - /* For satelites info 1Hz is enough */ - cfg_msg_packet.rate[1] = UBX_CFG_MSG_PAYLOAD_RATE1_1HZ; - - send_config_packet(_fd, (uint8_t*)&cfg_msg_packet, sizeof(cfg_msg_packet)); - if (receive(UBX_CONFIG_TIMEOUT) < 0) { - /* try next baudrate */ - continue; - } - - cfg_msg_packet.msgClass_payload = UBX_CLASS_NAV; - cfg_msg_packet.msgID_payload = UBX_MESSAGE_NAV_SOL; - - send_config_packet(_fd, (uint8_t*)&cfg_msg_packet, sizeof(cfg_msg_packet)); - if (receive(UBX_CONFIG_TIMEOUT) < 0) { - /* try next baudrate */ - continue; - } - - cfg_msg_packet.msgClass_payload = UBX_CLASS_NAV; - cfg_msg_packet.msgID_payload = UBX_MESSAGE_NAV_VELNED; - - send_config_packet(_fd, (uint8_t*)&cfg_msg_packet, sizeof(cfg_msg_packet)); - if (receive(UBX_CONFIG_TIMEOUT) < 0) { - /* try next baudrate */ - continue; - } -// cfg_msg_packet.msgClass_payload = UBX_CLASS_NAV; -// cfg_msg_packet.msgID_payload = UBX_MESSAGE_NAV_DOP; - -// cfg_msg_packet.msgClass_payload = UBX_CLASS_RXM; -// cfg_msg_packet.msgID_payload = UBX_MESSAGE_RXM_SVSI; + configure_message_rate(UBX_CLASS_NAV, UBX_MESSAGE_NAV_POSLLH, + UBX_CFG_MSG_PAYLOAD_RATE1_5HZ); + /* insist of receiving the ACK for this packet */ + // if (wait_for_ack(UBX_CONFIG_TIMEOUT) < 0) + // continue; + configure_message_rate(UBX_CLASS_NAV, UBX_MESSAGE_NAV_TIMEUTC, + UBX_CFG_MSG_PAYLOAD_RATE1_05HZ); + // /* insist of receiving the ACK for this packet */ + // if (wait_for_ack(UBX_CONFIG_TIMEOUT) < 0) + // continue; + configure_message_rate(UBX_CLASS_NAV, UBX_MESSAGE_NAV_SOL, + UBX_CFG_MSG_PAYLOAD_RATE1_05HZ); + // /* insist of receiving the ACK for this packet */ + // if (wait_for_ack(UBX_CONFIG_TIMEOUT) < 0) + // continue; + configure_message_rate(UBX_CLASS_NAV, UBX_MESSAGE_NAV_VELNED, + UBX_CFG_MSG_PAYLOAD_RATE1_5HZ); + // /* insist of receiving the ACK for this packet */ + // if (wait_for_ack(UBX_CONFIG_TIMEOUT) < 0) + // continue; + // configure_message_rate(UBX_CLASS_NAV, UBX_MESSAGE_NAV_DOP, + // 0); + // /* insist of receiving the ACK for this packet */ + // if (wait_for_ack(UBX_CONFIG_TIMEOUT) < 0) + // continue; + configure_message_rate(UBX_CLASS_NAV, UBX_MESSAGE_NAV_SVINFO, + 0); + // /* insist of receiving the ACK for this packet */ + // if (wait_for_ack(UBX_CONFIG_TIMEOUT) < 0) + // continue; _waiting_for_ack = false; return 0; @@ -239,6 +207,15 @@ UBX::configure(unsigned &baudrate) return -1; } +int +UBX::wait_for_ack(unsigned timeout) +{ + _waiting_for_ack = true; + int ret = receive(timeout); + _waiting_for_ack = false; + return ret; +} + int UBX::receive(unsigned timeout) { @@ -498,6 +475,8 @@ UBX::handle_message() _gps_position->eph_m = (float)packet->hAcc * 1e-3f; // from mm to m _gps_position->epv_m = (float)packet->vAcc * 1e-3f; // from mm to m + _rate_count_lat_lon++; + /* Add timestamp to finish the report */ _gps_position->timestamp_position = hrt_absolute_time(); /* only return 1 when new position is available */ @@ -653,6 +632,8 @@ UBX::handle_message() _gps_position->c_variance_rad = (float)packet->cAcc * M_DEG_TO_RAD_F * 1e-5f; _gps_position->vel_ned_valid = true; _gps_position->timestamp_velocity = hrt_absolute_time(); + + _rate_count_vel++; } break; @@ -693,6 +674,12 @@ UBX::handle_message() default: //we don't know the message warnx("UBX: Unknown message received: %d-%d\n",_message_class,_message_id); + if (_disable_cmd_counter++ == 0) { + // Don't attempt for every message to disable, some might not be disabled */ + warnx("Disabling message 0x%02x 0x%02x", (unsigned)_message_class, (unsigned)_message_id); + configure_message_rate(_message_class, _message_id, 0); + } + return ret; ret = -1; break; } @@ -736,6 +723,25 @@ UBX::add_checksum_to_message(uint8_t* message, const unsigned length) message[length-1] = ck_b; } +void +UBX::add_checksum(uint8_t* message, const unsigned length, uint8_t &ck_a, uint8_t &ck_b) +{ + for (unsigned i = 0; i < length; i++) { + ck_a = ck_a + message[i]; + ck_b = ck_b + ck_a; + } +} + +void +UBX::configure_message_rate(uint8_t msg_class, uint8_t msg_id, uint8_t rate) +{ + struct ubx_cfg_msg_rate msg; + msg.msg_class = msg_class; + msg.msg_id = msg_id; + msg.rate = rate; + send_message(CFG, UBX_CONFIG_STATE_RATE, &msg, sizeof(msg)); +} + void UBX::send_config_packet(const int &fd, uint8_t *packet, const unsigned length) { @@ -753,3 +759,27 @@ UBX::send_config_packet(const int &fd, uint8_t *packet, const unsigned length) if (ret != (int)length + (int)sizeof(sync_bytes)) // XXX is there a neater way to get rid of the unsigned signed warning? warnx("ubx: config write fail"); } + +void +UBX::send_message(uint8_t msg_class, uint8_t msg_id, void *msg, uint8_t size) +{ + struct ubx_header header; + uint8_t ck_a=0, ck_b=0; + header.sync1 = UBX_SYNC1; + header.sync2 = UBX_SYNC2; + header.msg_class = msg_class; + header.msg_id = msg_id; + header.length = size; + + add_checksum((uint8_t *)&header.msg_class, sizeof(header)-2, ck_a, ck_b); + add_checksum((uint8_t *)msg, size, ck_a, ck_b); + + // Configure receive check + _clsID_needed = msg_class; + _msgID_needed = msg_id; + + write(_fd, (const char *)&header, sizeof(header)); + write(_fd, (const char *)msg, size); + write(_fd, (const char *)&ck_a, 1); + write(_fd, (const char *)&ck_b, 1); +} diff --git a/apps/drivers/gps/ubx.h b/apps/drivers/gps/ubx.h index e3dd1c7ea9..a6cd0685de 100644 --- a/apps/drivers/gps/ubx.h +++ b/apps/drivers/gps/ubx.h @@ -65,11 +65,11 @@ #define UBX_MESSAGE_CFG_RATE 0x08 #define UBX_CFG_PRT_LENGTH 20 -#define UBX_CFG_PRT_PAYLOAD_PORTID 0x01 /**< UART1 */ -#define UBX_CFG_PRT_PAYLOAD_MODE 0x000008D0 /**< 0b0000100011010000: 8N1 */ -#define UBX_CFG_PRT_PAYLOAD_BAUDRATE 38400 /**< always choose 38400 as GPS baudrate */ -#define UBX_CFG_PRT_PAYLOAD_INPROTOMASK 0x01 /**< UBX in */ -#define UBX_CFG_PRT_PAYLOAD_OUTPROTOMASK 0x01 /**< UBX out */ +#define UBX_CFG_PRT_PAYLOAD_PORTID 0x01 /**< UART1 */ +#define UBX_CFG_PRT_PAYLOAD_MODE 0x000008D0 /**< 0b0000100011010000: 8N1 */ +#define UBX_CFG_PRT_PAYLOAD_BAUDRATE 38400 /**< always choose 38400 as GPS baudrate */ +#define UBX_CFG_PRT_PAYLOAD_INPROTOMASK 0x01 /**< UBX in */ +#define UBX_CFG_PRT_PAYLOAD_OUTPROTOMASK 0x01 /**< UBX out */ #define UBX_CFG_RATE_LENGTH 6 #define UBX_CFG_RATE_PAYLOAD_MEASRATE 200 /**< 200ms for 5Hz */ @@ -78,13 +78,14 @@ #define UBX_CFG_NAV5_LENGTH 36 -#define UBX_CFG_NAV5_PAYLOAD_MASK 0x0001 /**< only update dynamic model and fix mode */ +#define UBX_CFG_NAV5_PAYLOAD_MASK 0x0005 /**< XXX only update dynamic model and fix mode */ #define UBX_CFG_NAV5_PAYLOAD_DYNMODEL 7 /**< 0: portable, 2: stationary, 3: pedestrian, 4: automotive, 5: sea, 6: airborne <1g, 7: airborne <2g, 8: airborne <4g */ -#define UBX_CFG_NAV5_PAYLOAD_FIXMODE 2 /**< 1: 2D only, 2: 3D only, 3: Auto 2D/3D */ +#define UBX_CFG_NAV5_PAYLOAD_FIXMODE 2 /**< 1: 2D only, 2: 3D only, 3: Auto 2D/3D */ #define UBX_CFG_MSG_LENGTH 8 #define UBX_CFG_MSG_PAYLOAD_RATE1_5HZ 0x01 /**< {0x00, 0x01, 0x00, 0x00, 0x00, 0x00} the second entry is for UART1 */ #define UBX_CFG_MSG_PAYLOAD_RATE1_1HZ 0x05 /**< {0x00, 0x05, 0x00, 0x00, 0x00, 0x00} the second entry is for UART1 */ +#define UBX_CFG_MSG_PAYLOAD_RATE1_05HZ 10 #define UBX_MAX_PAYLOAD_LENGTH 500 @@ -92,6 +93,14 @@ /** the structures of the binary packets */ #pragma pack(push, 1) +struct ubx_header { + uint8_t sync1; + uint8_t sync2; + uint8_t msg_class; + uint8_t msg_id; + uint16_t length; +}; + typedef struct { uint32_t time_milliseconds; /**< GPS Millisecond Time of Week */ int32_t lon; /**< Longitude * 1e-7, deg */ @@ -274,11 +283,17 @@ typedef struct { uint16_t length; uint8_t msgClass_payload; uint8_t msgID_payload; - uint8_t rate[6]; + uint8_t rate; uint8_t ck_a; uint8_t ck_b; } type_gps_bin_cfg_msg_packet_t; +struct ubx_cfg_msg_rate { + uint8_t msg_class; + uint8_t msg_id; + uint8_t rate; +}; + // END the structures of the binary packets // ************ @@ -341,55 +356,64 @@ class UBX : public GPS_Helper public: UBX(const int &fd, struct vehicle_gps_position_s *gps_position); ~UBX(); - int receive(unsigned timeout); - int configure(unsigned &baudrate); + int receive(unsigned timeout); + int configure(unsigned &baudrate); private: /** * Parse the binary MTK packet */ - int parse_char(uint8_t b); + int parse_char(uint8_t b); /** * Handle the package once it has arrived */ - int handle_message(void); + int handle_message(void); /** * Reset the parse state machine for a fresh start */ - void decode_init(void); + void decode_init(void); /** * While parsing add every byte (except the sync bytes) to the checksum */ - void add_byte_to_checksum(uint8_t); + void add_byte_to_checksum(uint8_t); /** * Add the two checksum bytes to an outgoing message */ - void add_checksum_to_message(uint8_t* message, const unsigned length); + void add_checksum_to_message(uint8_t* message, const unsigned length); /** * Helper to send a config packet */ - void send_config_packet(const int &fd, uint8_t *packet, const unsigned length); + void send_config_packet(const int &fd, uint8_t *packet, const unsigned length); - int _fd; + void configure_message_rate(uint8_t msg_class, uint8_t msg_id, uint8_t rate); + + void send_message(uint8_t msg_class, uint8_t msg_id, void *msg, uint8_t size); + + void add_checksum(uint8_t* message, const unsigned length, uint8_t &ck_a, uint8_t &ck_b); + + int wait_for_ack(unsigned timeout); + + int _fd; struct vehicle_gps_position_s *_gps_position; ubx_config_state_t _config_state; - bool _waiting_for_ack; - uint8_t _clsID_needed; - uint8_t _msgID_needed; + bool _waiting_for_ack; + uint8_t _clsID_needed; + uint8_t _msgID_needed; ubx_decode_state_t _decode_state; - uint8_t _rx_buffer[RECV_BUFFER_SIZE]; - unsigned _rx_count; - uint8_t _rx_ck_a; - uint8_t _rx_ck_b; - ubx_message_class_t _message_class; + uint8_t _rx_buffer[RECV_BUFFER_SIZE]; + unsigned _rx_count; + uint8_t _rx_ck_a; + uint8_t _rx_ck_b; + ubx_message_class_t _message_class; ubx_message_id_t _message_id; - unsigned _payload_size; + unsigned _payload_size; + uint8_t _disable_cmd_counter; }; #endif /* UBX_H_ */ From 1f800edc7676a6ea13127746ce38787a1e98b935 Mon Sep 17 00:00:00 2001 From: Anton Babushkin Date: Sun, 5 May 2013 15:51:16 +0400 Subject: [PATCH 50/84] Still threshold increased to 0.1m/s^2, and orientation error threshold to 5m/s^2. Timeout increased to 30s. --- apps/commander/accelerometer_calibration.c | 66 +++++++++++----------- 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/apps/commander/accelerometer_calibration.c b/apps/commander/accelerometer_calibration.c index 1807369080..991145d73c 100644 --- a/apps/commander/accelerometer_calibration.c +++ b/apps/commander/accelerometer_calibration.c @@ -224,7 +224,7 @@ int do_accel_calibration_mesurements(int mavlink_fd, float accel_offs[3], float * Wait for vehicle become still and detect it's orientation. * * @return 0..5 according to orientation when vehicle is still and ready for measurements, - * ERROR if vehicle is not still after 10s or orientation error is more than 20% + * ERROR if vehicle is not still after 30s or orientation error is more than 5m/s^2 */ int detect_orientation(int mavlink_fd, int sub_sensor_combined) { struct sensor_combined_s sensor; @@ -235,17 +235,17 @@ int detect_orientation(int mavlink_fd, int sub_sensor_combined) { float accel_len2 = 0.0f; /* EMA time constant in seconds*/ float ema_len = 0.2f; - /* set "still" threshold to 0.005 m/s^2 */ - float still_thr2 = pow(0.05f / CONSTANTS_ONE_G, 2); - /* set accel error threshold to 30% of accel vector length */ - float accel_err_thr = 0.3f; + /* set "still" threshold to 0.1 m/s^2 */ + float still_thr2 = pow(0.1f, 2); + /* set accel error threshold to 5m/s^2 */ + float accel_err_thr = 5.0f; /* still time required in us */ int64_t still_time = 2000000; struct pollfd fds[1] = { { .fd = sub_sensor_combined, .events = POLLIN } }; hrt_abstime t_start = hrt_absolute_time(); - /* set deadline to 20s */ - hrt_abstime timeout = 20000000; + /* set timeout to 30s */ + hrt_abstime timeout = 30000000; hrt_abstime t_timeout = t_start + timeout; hrt_abstime t = t_start; hrt_abstime t_prev = t_start; @@ -267,11 +267,10 @@ int detect_orientation(int mavlink_fd, int sub_sensor_combined) { if (d > accel_disp[i]) accel_disp[i] = d; } - accel_len2 = accel_ema[0] * accel_ema[0] + accel_ema[1] * accel_ema[1] + accel_ema[2] * accel_ema[2]; - float still_thr_raw2 = still_thr2 * accel_len2; - if ( accel_disp[0] < still_thr_raw2 && - accel_disp[1] < still_thr_raw2 && - accel_disp[2] < still_thr_raw2 ) { + /* still detector with hysteresis */ + if ( accel_disp[0] < still_thr2 && + accel_disp[1] < still_thr2 && + accel_disp[2] < still_thr2 ) { /* is still now */ if (t_still == 0) { /* first time */ @@ -285,9 +284,9 @@ int detect_orientation(int mavlink_fd, int sub_sensor_combined) { break; } } - } else if ( accel_disp[0] > still_thr_raw2 * 2.0f || - accel_disp[1] > still_thr_raw2 * 2.0f || - accel_disp[2] > still_thr_raw2 * 2.0f) { + } else if ( accel_disp[0] > still_thr2 * 2.0f || + accel_disp[1] > still_thr2 * 2.0f || + accel_disp[2] > still_thr2 * 2.0f) { /* not still, reset still start time */ if (t_still != 0) { mavlink_log_info(mavlink_fd, "moving..."); @@ -306,30 +305,29 @@ int detect_orientation(int mavlink_fd, int sub_sensor_combined) { } float accel_len = sqrt(accel_len2); - float accel_err_thr_raw = accel_len * accel_err_thr; - if ( fabs(accel_ema[0] - accel_len) < accel_err_thr_raw && - fabs(accel_ema[1]) < accel_err_thr_raw && - fabs(accel_ema[2]) < accel_err_thr_raw ) + if ( fabs(accel_ema[0] - accel_len) < accel_err_thr && + fabs(accel_ema[1]) < accel_err_thr && + fabs(accel_ema[2]) < accel_err_thr ) return 0; // [ g, 0, 0 ] - if ( fabs(accel_ema[0] + accel_len) < accel_err_thr_raw && - fabs(accel_ema[1]) < accel_err_thr_raw && - fabs(accel_ema[2]) < accel_err_thr_raw ) + if ( fabs(accel_ema[0] + accel_len) < accel_err_thr && + fabs(accel_ema[1]) < accel_err_thr && + fabs(accel_ema[2]) < accel_err_thr ) return 1; // [ -g, 0, 0 ] - if ( fabs(accel_ema[0]) < accel_err_thr_raw && - fabs(accel_ema[1] - accel_len) < accel_err_thr_raw && - fabs(accel_ema[2]) < accel_err_thr_raw ) + if ( fabs(accel_ema[0]) < accel_err_thr && + fabs(accel_ema[1] - accel_len) < accel_err_thr && + fabs(accel_ema[2]) < accel_err_thr ) return 2; // [ 0, g, 0 ] - if ( fabs(accel_ema[0]) < accel_err_thr_raw && - fabs(accel_ema[1] + accel_len) < accel_err_thr_raw && - fabs(accel_ema[2]) < accel_err_thr_raw ) + if ( fabs(accel_ema[0]) < accel_err_thr && + fabs(accel_ema[1] + accel_len) < accel_err_thr && + fabs(accel_ema[2]) < accel_err_thr ) return 3; // [ 0, -g, 0 ] - if ( fabs(accel_ema[0]) < accel_err_thr_raw && - fabs(accel_ema[1]) < accel_err_thr_raw && - fabs(accel_ema[2] - accel_len) < accel_err_thr_raw ) + if ( fabs(accel_ema[0]) < accel_err_thr && + fabs(accel_ema[1]) < accel_err_thr && + fabs(accel_ema[2] - accel_len) < accel_err_thr ) return 4; // [ 0, 0, g ] - if ( fabs(accel_ema[0]) < accel_err_thr_raw && - fabs(accel_ema[1]) < accel_err_thr_raw && - fabs(accel_ema[2] + accel_len) < accel_err_thr_raw ) + if ( fabs(accel_ema[0]) < accel_err_thr && + fabs(accel_ema[1]) < accel_err_thr && + fabs(accel_ema[2] + accel_len) < accel_err_thr ) return 5; // [ 0, 0, -g ] mavlink_log_info(mavlink_fd, "ERROR: invalid orientation"); From 27a25b5e172c972e4f9f31c2a30114498346bb08 Mon Sep 17 00:00:00 2001 From: Lorenz Meier Date: Sun, 5 May 2013 18:50:23 +0200 Subject: [PATCH 51/84] Improved update rate for velocity estimate, not yet where we want it to be --- apps/drivers/gps/gps_helper.cpp | 4 ++-- apps/drivers/gps/ubx.cpp | 10 +++++----- apps/drivers/gps/ubx.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/drivers/gps/gps_helper.cpp b/apps/drivers/gps/gps_helper.cpp index b03cccb453..54ac90dabd 100644 --- a/apps/drivers/gps/gps_helper.cpp +++ b/apps/drivers/gps/gps_helper.cpp @@ -46,13 +46,13 @@ float GPS_Helper::get_position_update_rate() { - _rate_count_lat_lon / (((float)(hrt_absolute_time() - _interval_rate_start)) / 1000000.0f); + return _rate_count_lat_lon / (((float)(hrt_absolute_time() - _interval_rate_start)) / 1000000.0f); } float GPS_Helper::get_velocity_update_rate() { - _rate_count_vel / (((float)(hrt_absolute_time() - _interval_rate_start)) / 1000000.0f); + return _rate_count_vel / (((float)(hrt_absolute_time() - _interval_rate_start)) / 1000000.0f); } float diff --git a/apps/drivers/gps/ubx.cpp b/apps/drivers/gps/ubx.cpp index e887e8f7c1..b3093b0f6f 100644 --- a/apps/drivers/gps/ubx.cpp +++ b/apps/drivers/gps/ubx.cpp @@ -140,7 +140,7 @@ UBX::configure(unsigned &baudrate) cfg_rate_packet.clsID = UBX_CLASS_CFG; cfg_rate_packet.msgID = UBX_MESSAGE_CFG_RATE; cfg_rate_packet.length = UBX_CFG_RATE_LENGTH; - cfg_rate_packet.measRate = UBX_CFG_RATE_PAYLOAD_MEASRATE; + cfg_rate_packet.measRate = UBX_CFG_RATE_PAYLOAD_MEASINTERVAL; cfg_rate_packet.navRate = UBX_CFG_RATE_PAYLOAD_NAVRATE; cfg_rate_packet.timeRef = UBX_CFG_RATE_PAYLOAD_TIMEREF; @@ -176,17 +176,17 @@ UBX::configure(unsigned &baudrate) // if (wait_for_ack(UBX_CONFIG_TIMEOUT) < 0) // continue; configure_message_rate(UBX_CLASS_NAV, UBX_MESSAGE_NAV_TIMEUTC, - UBX_CFG_MSG_PAYLOAD_RATE1_05HZ); + 1); // /* insist of receiving the ACK for this packet */ // if (wait_for_ack(UBX_CONFIG_TIMEOUT) < 0) // continue; configure_message_rate(UBX_CLASS_NAV, UBX_MESSAGE_NAV_SOL, - UBX_CFG_MSG_PAYLOAD_RATE1_05HZ); + 1); // /* insist of receiving the ACK for this packet */ // if (wait_for_ack(UBX_CONFIG_TIMEOUT) < 0) // continue; configure_message_rate(UBX_CLASS_NAV, UBX_MESSAGE_NAV_VELNED, - UBX_CFG_MSG_PAYLOAD_RATE1_5HZ); + 1); // /* insist of receiving the ACK for this packet */ // if (wait_for_ack(UBX_CONFIG_TIMEOUT) < 0) // continue; @@ -739,7 +739,7 @@ UBX::configure_message_rate(uint8_t msg_class, uint8_t msg_id, uint8_t rate) msg.msg_class = msg_class; msg.msg_id = msg_id; msg.rate = rate; - send_message(CFG, UBX_CONFIG_STATE_RATE, &msg, sizeof(msg)); + send_message(CFG, UBX_MESSAGE_CFG_MSG, &msg, sizeof(msg)); } void diff --git a/apps/drivers/gps/ubx.h b/apps/drivers/gps/ubx.h index a6cd0685de..5a433642ce 100644 --- a/apps/drivers/gps/ubx.h +++ b/apps/drivers/gps/ubx.h @@ -72,7 +72,7 @@ #define UBX_CFG_PRT_PAYLOAD_OUTPROTOMASK 0x01 /**< UBX out */ #define UBX_CFG_RATE_LENGTH 6 -#define UBX_CFG_RATE_PAYLOAD_MEASRATE 200 /**< 200ms for 5Hz */ +#define UBX_CFG_RATE_PAYLOAD_MEASINTERVAL 200 /**< 200ms for 5Hz */ #define UBX_CFG_RATE_PAYLOAD_NAVRATE 1 /**< cannot be changed */ #define UBX_CFG_RATE_PAYLOAD_TIMEREF 0 /**< 0: UTC, 1: GPS time */ From 3bf26ac51f76389217cf2f604ca2420bcc050acf Mon Sep 17 00:00:00 2001 From: px4dev Date: Sun, 5 May 2013 16:48:05 -0700 Subject: [PATCH 52/84] Obsolete bogus EXTRAFLAGS, add language-specific flags overrides. --- makefiles/toolchain_gnu-arm-eabi.mk | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/makefiles/toolchain_gnu-arm-eabi.mk b/makefiles/toolchain_gnu-arm-eabi.mk index 32a2773732..efb6b432a0 100644 --- a/makefiles/toolchain_gnu-arm-eabi.mk +++ b/makefiles/toolchain_gnu-arm-eabi.mk @@ -98,6 +98,14 @@ INSTRUMENTATIONDEFINES = -finstrument-functions \ ARCHCFLAGS = -std=gnu99 ARCHCXXFLAGS = -fno-exceptions -fno-rtti -std=gnu++0x +# Compatibility +# XXX remove this once downstream users are fixed +# +ifneq ($(EXTRAFLAGS),) +$(warning EXTRAFLAGS is deprecated, use EXTRADEFINES for common pre-processor definitions. See also EXTRACFLAGS, EXTRACXXFLAGS and EXTRALDFLAGS.) +EXTRADEFINES += $(EXTRAFLAGS) +endif + # Generic warnings # ARCHWARNINGS = -Wall \ @@ -144,6 +152,7 @@ CFLAGS = $(ARCHCFLAGS) \ $(INSTRUMENTATIONDEFINES) \ $(ARCHDEFINES) \ $(EXTRADEFINES) \ + $(EXTRACFLAGS) \ -fno-common \ $(addprefix -I,$(INCLUDE_DIRS)) @@ -156,18 +165,22 @@ CXXFLAGS = $(ARCHCXXFLAGS) \ $(ARCHXXINCLUDES) \ $(INSTRUMENTATIONDEFINES) \ $(ARCHDEFINES) \ - $(EXTRADEFINES) \ -DCONFIG_WCHAR_BUILTIN \ + $(EXTRADEFINES) \ + $(EXTRACXXFLAGS) \ $(addprefix -I,$(INCLUDE_DIRS)) # Flags we pass to the assembler # -AFLAGS = $(CFLAGS) -D__ASSEMBLY__ +AFLAGS = $(CFLAGS) -D__ASSEMBLY__ \ + $(EXTRADEFINES) \ + $(EXTRAAFLAGS) # Flags we pass to the linker # LDFLAGS += --warn-common \ --gc-sections \ + $(EXTRALDFLAGS) \ $(addprefix -T,$(LDSCRIPT)) \ $(addprefix -L,$(LIB_DIRS)) @@ -189,7 +202,7 @@ DEP_INCLUDES = $(subst .o,.d,$(OBJS)) define COMPILE @$(ECHO) "CC: $1" @$(MKDIR) -p $(dir $2) - $(Q) $(CC) -MD -c $(CFLAGS) $(EXTRAFLAGS) $(abspath $1) -o $2 + $(Q) $(CC) -MD -c $(CFLAGS) $(abspath $1) -o $2 endef # Compile C++ source $1 to $2 @@ -198,7 +211,7 @@ endef define COMPILEXX @$(ECHO) "CXX: $1" @$(MKDIR) -p $(dir $2) - $(Q) $(CXX) -MD -c $(CXXFLAGS) $(EXTRAFLAGS) $(abspath $1) -o $2 + $(Q) $(CXX) -MD -c $(CXXFLAGS) $(abspath $1) -o $2 endef # Assemble $1 into $2 @@ -206,7 +219,7 @@ endef define ASSEMBLE @$(ECHO) "AS: $1" @$(MKDIR) -p $(dir $2) - $(Q) $(CC) -c $(AFLAGS) $(EXTRAFLAGS) $(abspath $1) -o $2 + $(Q) $(CC) -c $(AFLAGS) $(abspath $1) -o $2 endef # Produce partially-linked $1 from files in $2 From 1ca535b94145c94db04d0655c2f4fb25c76a717a Mon Sep 17 00:00:00 2001 From: px4dev Date: Sun, 5 May 2013 16:52:26 -0700 Subject: [PATCH 53/84] Fix whitespace damage, update help text to indicate the -m option is for debug use only. --- src/systemcmds/pwm/pwm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/systemcmds/pwm/pwm.c b/src/systemcmds/pwm/pwm.c index 08e6c88dfa..ff733df52f 100644 --- a/src/systemcmds/pwm/pwm.c +++ b/src/systemcmds/pwm/pwm.c @@ -78,7 +78,7 @@ usage(const char *reason) " Channel group that should update at the alternate rate (may be specified more than once)\n" " arm | disarm Arm or disarm the ouptut\n" " ... PWM output values in microseconds to assign to the PWM outputs\n" - " Directly supply alt rate channel mask\n" + " Directly supply alt rate channel mask (debug use only)\n" "\n" "When -c is specified, any channel groups not listed with -c will update at the default rate.\n" ); From 3b65281f00150eaa29cfec1d4a4cb86fc83c326d Mon Sep 17 00:00:00 2001 From: px4dev Date: Sun, 5 May 2013 17:19:23 -0700 Subject: [PATCH 54/84] Remove EXTRAFLAGS compatibility hack. --- makefiles/toolchain_gnu-arm-eabi.mk | 8 -------- 1 file changed, 8 deletions(-) diff --git a/makefiles/toolchain_gnu-arm-eabi.mk b/makefiles/toolchain_gnu-arm-eabi.mk index efb6b432a0..0e651e53c8 100644 --- a/makefiles/toolchain_gnu-arm-eabi.mk +++ b/makefiles/toolchain_gnu-arm-eabi.mk @@ -98,14 +98,6 @@ INSTRUMENTATIONDEFINES = -finstrument-functions \ ARCHCFLAGS = -std=gnu99 ARCHCXXFLAGS = -fno-exceptions -fno-rtti -std=gnu++0x -# Compatibility -# XXX remove this once downstream users are fixed -# -ifneq ($(EXTRAFLAGS),) -$(warning EXTRAFLAGS is deprecated, use EXTRADEFINES for common pre-processor definitions. See also EXTRACFLAGS, EXTRACXXFLAGS and EXTRALDFLAGS.) -EXTRADEFINES += $(EXTRAFLAGS) -endif - # Generic warnings # ARCHWARNINGS = -Wall \ From 41ec41cf8cc16309cf6f7e949d3ddad78e5f44a2 Mon Sep 17 00:00:00 2001 From: Anton Babushkin Date: Mon, 6 May 2013 18:21:56 +0400 Subject: [PATCH 55/84] Accelerometer calibration bugfix --- apps/commander/accelerometer_calibration.c | 14 ++++++-------- apps/commander/accelerometer_calibration.h | 4 ++-- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/apps/commander/accelerometer_calibration.c b/apps/commander/accelerometer_calibration.c index 991145d73c..d79dd93dd0 100644 --- a/apps/commander/accelerometer_calibration.c +++ b/apps/commander/accelerometer_calibration.c @@ -232,7 +232,6 @@ int detect_orientation(int mavlink_fd, int sub_sensor_combined) { float accel_ema[3] = { 0.0f, 0.0f, 0.0f }; /* max-hold dispersion of accel */ float accel_disp[3] = { 0.0f, 0.0f, 0.0f }; - float accel_len2 = 0.0f; /* EMA time constant in seconds*/ float ema_len = 0.2f; /* set "still" threshold to 0.1 m/s^2 */ @@ -304,30 +303,29 @@ int detect_orientation(int mavlink_fd, int sub_sensor_combined) { } } - float accel_len = sqrt(accel_len2); - if ( fabs(accel_ema[0] - accel_len) < accel_err_thr && + if ( fabs(accel_ema[0] - CONSTANTS_ONE_G) < accel_err_thr && fabs(accel_ema[1]) < accel_err_thr && fabs(accel_ema[2]) < accel_err_thr ) return 0; // [ g, 0, 0 ] - if ( fabs(accel_ema[0] + accel_len) < accel_err_thr && + if ( fabs(accel_ema[0] + CONSTANTS_ONE_G) < accel_err_thr && fabs(accel_ema[1]) < accel_err_thr && fabs(accel_ema[2]) < accel_err_thr ) return 1; // [ -g, 0, 0 ] if ( fabs(accel_ema[0]) < accel_err_thr && - fabs(accel_ema[1] - accel_len) < accel_err_thr && + fabs(accel_ema[1] - CONSTANTS_ONE_G) < accel_err_thr && fabs(accel_ema[2]) < accel_err_thr ) return 2; // [ 0, g, 0 ] if ( fabs(accel_ema[0]) < accel_err_thr && - fabs(accel_ema[1] + accel_len) < accel_err_thr && + fabs(accel_ema[1] + CONSTANTS_ONE_G) < accel_err_thr && fabs(accel_ema[2]) < accel_err_thr ) return 3; // [ 0, -g, 0 ] if ( fabs(accel_ema[0]) < accel_err_thr && fabs(accel_ema[1]) < accel_err_thr && - fabs(accel_ema[2] - accel_len) < accel_err_thr ) + fabs(accel_ema[2] - CONSTANTS_ONE_G) < accel_err_thr ) return 4; // [ 0, 0, g ] if ( fabs(accel_ema[0]) < accel_err_thr && fabs(accel_ema[1]) < accel_err_thr && - fabs(accel_ema[2] + accel_len) < accel_err_thr ) + fabs(accel_ema[2] + CONSTANTS_ONE_G) < accel_err_thr ) return 5; // [ 0, 0, -g ] mavlink_log_info(mavlink_fd, "ERROR: invalid orientation"); diff --git a/apps/commander/accelerometer_calibration.h b/apps/commander/accelerometer_calibration.h index c0169c2a13..a11cf93d3c 100644 --- a/apps/commander/accelerometer_calibration.h +++ b/apps/commander/accelerometer_calibration.h @@ -1,8 +1,8 @@ /* * accelerometer_calibration.h * - * Created on: 25.04.2013 - * Author: ton + * Copyright (C) 2013 Anton Babushkin. All rights reserved. + * Author: Anton Babushkin */ #ifndef ACCELEROMETER_CALIBRATION_H_ From f3e6e4bb50d9d5e63ee423a25713d9033adcebf4 Mon Sep 17 00:00:00 2001 From: Anton Babushkin Date: Mon, 6 May 2013 22:59:45 +0400 Subject: [PATCH 56/84] Update servo arm only on real change. --- apps/drivers/px4fmu/fmu.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/drivers/px4fmu/fmu.cpp b/apps/drivers/px4fmu/fmu.cpp index e547245367..761a23c426 100644 --- a/apps/drivers/px4fmu/fmu.cpp +++ b/apps/drivers/px4fmu/fmu.cpp @@ -505,7 +505,11 @@ PX4FMU::task_main() orb_copy(ORB_ID(actuator_armed), _t_armed, &aa); /* update PWM servo armed status if armed and not locked down */ - up_pwm_servo_arm(aa.armed && !aa.lockdown); + bool set_armed = aa.armed && !aa.lockdown; + if (set_armed != _armed) { + _armed = set_armed; + up_pwm_servo_arm(set_armed); + } } // see if we have new PPM input data From eac9e10a83ab2f897e4d0c2c6c8cd9f9f55b29cb Mon Sep 17 00:00:00 2001 From: Lorenz Meier Date: Mon, 6 May 2013 23:50:14 +0200 Subject: [PATCH 57/84] Moved calibration --- .../modules}/commander/accelerometer_calibration.c | 0 .../modules}/commander/accelerometer_calibration.h | 0 src/modules/commander/module.mk | 10 ++++++---- 3 files changed, 6 insertions(+), 4 deletions(-) rename {apps => src/modules}/commander/accelerometer_calibration.c (100%) rename {apps => src/modules}/commander/accelerometer_calibration.h (100%) diff --git a/apps/commander/accelerometer_calibration.c b/src/modules/commander/accelerometer_calibration.c similarity index 100% rename from apps/commander/accelerometer_calibration.c rename to src/modules/commander/accelerometer_calibration.c diff --git a/apps/commander/accelerometer_calibration.h b/src/modules/commander/accelerometer_calibration.h similarity index 100% rename from apps/commander/accelerometer_calibration.h rename to src/modules/commander/accelerometer_calibration.h diff --git a/src/modules/commander/module.mk b/src/modules/commander/module.mk index 556d5c2df6..fe44e955ad 100644 --- a/src/modules/commander/module.mk +++ b/src/modules/commander/module.mk @@ -35,7 +35,9 @@ # Main system state machine # -MODULE_COMMAND = commander -SRCS = commander.c \ - state_machine_helper.c \ - calibration_routines.c +MODULE_COMMAND = commander +SRCS = commander.c \ + state_machine_helper.c \ + calibration_routines.c \ + accelerometer_calibration.c + From 100bcefc17cb77eff7085ef8c6c3055492c2ae32 Mon Sep 17 00:00:00 2001 From: James Goppert Date: Tue, 16 Apr 2013 14:11:56 -0400 Subject: [PATCH 58/84] Added velocity adjustment to stabilization. --- apps/controllib/fixedwing.cpp | 54 +++++++++++++++++++---------- apps/controllib/fixedwing.hpp | 6 ++-- apps/examples/control_demo/params.c | 3 +- 3 files changed, 42 insertions(+), 21 deletions(-) diff --git a/apps/controllib/fixedwing.cpp b/apps/controllib/fixedwing.cpp index 1cc28b9dd9..6309a12255 100644 --- a/apps/controllib/fixedwing.cpp +++ b/apps/controllib/fixedwing.cpp @@ -56,9 +56,9 @@ BlockYawDamper::BlockYawDamper(SuperBlock *parent, const char *name) : BlockYawDamper::~BlockYawDamper() {}; -void BlockYawDamper::update(float rCmd, float r) +void BlockYawDamper::update(float rCmd, float r, float outputScale) { - _rudder = _r2Rdr.update(rCmd - + _rudder = outputScale*_r2Rdr.update(rCmd - _rWashout.update(_rLowPass.update(r))); } @@ -77,13 +77,13 @@ BlockStabilization::BlockStabilization(SuperBlock *parent, const char *name) : BlockStabilization::~BlockStabilization() {}; void BlockStabilization::update(float pCmd, float qCmd, float rCmd, - float p, float q, float r) + float p, float q, float r, float outputScale) { - _aileron = _p2Ail.update( + _aileron = outputScale*_p2Ail.update( pCmd - _pLowPass.update(p)); - _elevator = _q2Elv.update( + _elevator = outputScale*_q2Elv.update( qCmd - _qLowPass.update(q)); - _yawDamper.update(rCmd, r); + _yawDamper.update(rCmd, r, outputScale); } BlockWaypointGuidance::BlockWaypointGuidance(SuperBlock *parent, const char *name) : @@ -163,11 +163,11 @@ BlockMultiModeBacksideAutopilot::BlockMultiModeBacksideAutopilot(SuperBlock *par // guidance block _guide(this, ""), - // block params - _trimAil(this, "TRIM_ROLL", false), /* general roll trim (full name: TRIM_ROLL) */ - _trimElv(this, "TRIM_PITCH", false), /* general pitch trim */ - _trimRdr(this, "TRIM_YAW", false), /* general yaw trim */ - _trimThr(this, "TRIM_THR", true), /* FWB_ specific throttle trim (full name: FWB_TRIM_THR) */ + _trimAil(this, "TRIM_ROLL", false), /* general roll trim (full name: TRIM_ROLL) */ + _trimElv(this, "TRIM_PITCH", false), /* general pitch trim */ + _trimRdr(this, "TRIM_YAW", false), /* general yaw trim */ + _trimThr(this, "TRIM_THR"), /* FWB_ specific throttle trim (full name: FWB_TRIM_THR) */ + _trimV(this, "TRIM_V"), /* FWB_ specific trim velocity (full name : FWB_TRIM_V) */ _vCmd(this, "V_CMD"), _rocMax(this, "ROC_MAX"), @@ -228,7 +228,15 @@ void BlockMultiModeBacksideAutopilot::update() _guide.update(_pos, _att, _posCmd, _lastPosCmd); // calculate velocity, XXX should be airspeed, but using ground speed for now - float v = sqrtf(_pos.vx * _pos.vx + _pos.vy * _pos.vy + _pos.vz * _pos.vz); + // for the purpose of control we will limit the velocity feedback between + // the min/max velocity + float v = _vLimit.update(sqrtf( + _pos.vx * _pos.vx + + _pos.vy * _pos.vy + + _pos.vz * _pos.vz)); + + // limit velocity command between min/max velocity + float vCmd = _vLimit.update(_vCmd.get()); // altitude hold float dThrottle = _h2Thr.update(_posCmd.altitude - _pos.alt); @@ -240,16 +248,19 @@ void BlockMultiModeBacksideAutopilot::update() // velocity hold // negative sign because nose over to increase speed - float thetaCmd = _theLimit.update(-_v2Theta.update( - _vLimit.update(_vCmd.get()) - v)); + float thetaCmd = _theLimit.update(-_v2Theta.update(vCmd - v)); float qCmd = _theta2Q.update(thetaCmd - _att.pitch); // yaw rate cmd float rCmd = 0; // stabilization + float velocityRatio = _trimV.get()/v; + float outputScale = velocityRatio*velocityRatio; + // this term scales the output based on the dynamic pressure change from trim _stabilization.update(pCmd, qCmd, rCmd, - _att.rollspeed, _att.pitchspeed, _att.yawspeed); + _att.rollspeed, _att.pitchspeed, _att.yawspeed, + outputScale); // output _actuators.control[CH_AIL] = _stabilization.getAileron() + _trimAil.get(); @@ -280,7 +291,12 @@ void BlockMultiModeBacksideAutopilot::update() } else if (_status.manual_control_mode == VEHICLE_MANUAL_CONTROL_MODE_SAS) { // calculate velocity, XXX should be airspeed, but using ground speed for now - float v = sqrtf(_pos.vx * _pos.vx + _pos.vy * _pos.vy + _pos.vz * _pos.vz); + // for the purpose of control we will limit the velocity feedback between + // the min/max velocity + float v = _vLimit.update(sqrtf( + _pos.vx * _pos.vx + + _pos.vy * _pos.vy + + _pos.vz * _pos.vz)); // pitch channel -> rate of climb // TODO, might want to put a gain on this, otherwise commanding @@ -294,8 +310,10 @@ void BlockMultiModeBacksideAutopilot::update() // throttle channel -> velocity // negative sign because nose over to increase speed - float vCmd = _manual.throttle * (_vLimit.getMax() - _vLimit.getMin()) + _vLimit.getMin(); - float thetaCmd = _theLimit.update(-_v2Theta.update(_vLimit.update(vCmd) - v)); + float vCmd = _vLimit.update(_manual.throttle * + (_vLimit.getMax() - _vLimit.getMin()) + + _vLimit.getMin()); + float thetaCmd = _theLimit.update(-_v2Theta.update(vCmd - v)); float qCmd = _theta2Q.update(thetaCmd - _att.pitch); // yaw rate cmd diff --git a/apps/controllib/fixedwing.hpp b/apps/controllib/fixedwing.hpp index 281cbb4cb6..c908ea2371 100644 --- a/apps/controllib/fixedwing.hpp +++ b/apps/controllib/fixedwing.hpp @@ -193,7 +193,7 @@ public: * good idea to declare a member to store the temporary * variable. */ - void update(float rCmd, float r); + void update(float rCmd, float r, float outputScale = 1.0); /** * Rudder output value accessor @@ -226,7 +226,8 @@ public: BlockStabilization(SuperBlock *parent, const char *name); virtual ~BlockStabilization(); void update(float pCmd, float qCmd, float rCmd, - float p, float q, float r); + float p, float q, float r, + float outputScale = 1.0); float getAileron() { return _aileron; } float getElevator() { return _elevator; } float getRudder() { return _yawDamper.getRudder(); } @@ -322,6 +323,7 @@ private: BlockParam _trimElv; BlockParam _trimRdr; BlockParam _trimThr; + BlockParam _trimV; BlockParam _vCmd; BlockParam _rocMax; diff --git a/apps/examples/control_demo/params.c b/apps/examples/control_demo/params.c index 428b779b17..cce38c3ec3 100644 --- a/apps/examples/control_demo/params.c +++ b/apps/examples/control_demo/params.c @@ -68,4 +68,5 @@ PARAM_DEFINE_FLOAT(FWB_ROC2THR_D, 0.0f); PARAM_DEFINE_FLOAT(FWB_ROC2THR_D_LP, 0.0f); PARAM_DEFINE_FLOAT(FWB_ROC2THR_I_MAX, 0.0f); -PARAM_DEFINE_FLOAT(FWB_TRIM_THR, 0.8f); // trim throttle (0,1) +PARAM_DEFINE_FLOAT(FWB_TRIM_THR, 0.8f); // trim throttle (0,1) +PARAM_DEFINE_FLOAT(FWB_TRIM_V, 12.0f); // trim velocity, m/s From 3ed93430060228b64893119a439187725d35d7ec Mon Sep 17 00:00:00 2001 From: James Goppert Date: Sun, 14 Apr 2013 20:09:38 -0400 Subject: [PATCH 59/84] HIL pressure fix. --- apps/controllib/fixedwing.cpp | 10 +-- apps/controllib/fixedwing.hpp | 6 +- apps/examples/control_demo/params.c | 14 ++-- apps/mavlink/mavlink_receiver.c | 122 +--------------------------- 4 files changed, 17 insertions(+), 135 deletions(-) diff --git a/apps/controllib/fixedwing.cpp b/apps/controllib/fixedwing.cpp index 1cc28b9dd9..3836a1a0fc 100644 --- a/apps/controllib/fixedwing.cpp +++ b/apps/controllib/fixedwing.cpp @@ -156,9 +156,9 @@ BlockMultiModeBacksideAutopilot::BlockMultiModeBacksideAutopilot(SuperBlock *par _theLimit(this, "THE"), _vLimit(this, "V"), - // altitude/roc hold + // altitude/climb rate hold _h2Thr(this, "H2THR"), - _roc2Thr(this, "ROC2THR"), + _cr2Thr(this, "CR2THR"), // guidance block _guide(this, ""), @@ -170,7 +170,7 @@ BlockMultiModeBacksideAutopilot::BlockMultiModeBacksideAutopilot(SuperBlock *par _trimThr(this, "TRIM_THR", true), /* FWB_ specific throttle trim (full name: FWB_TRIM_THR) */ _vCmd(this, "V_CMD"), - _rocMax(this, "ROC_MAX"), + _crMax(this, "CR_MAX"), _attPoll(), _lastPosCmd(), _timeStamp(0) @@ -285,8 +285,8 @@ void BlockMultiModeBacksideAutopilot::update() // pitch channel -> rate of climb // TODO, might want to put a gain on this, otherwise commanding // from +1 -> -1 m/s for rate of climb - //float dThrottle = _roc2Thr.update( - //_rocMax.get()*_manual.pitch - _pos.vz); + //float dThrottle = _cr2Thr.update( + //_crMax.get()*_manual.pitch - _pos.vz); // roll channel -> bank angle float phiCmd = _phiLimit.update(_manual.roll * _phiLimit.getMax()); diff --git a/apps/controllib/fixedwing.hpp b/apps/controllib/fixedwing.hpp index 281cbb4cb6..4323beeb30 100644 --- a/apps/controllib/fixedwing.hpp +++ b/apps/controllib/fixedwing.hpp @@ -310,9 +310,9 @@ private: BlockLimit _theLimit; BlockLimit _vLimit; - // altitude/ roc hold + // altitude/ climb rate hold BlockPID _h2Thr; - BlockPID _roc2Thr; + BlockPID _cr2Thr; // guidance BlockWaypointGuidance _guide; @@ -323,7 +323,7 @@ private: BlockParam _trimRdr; BlockParam _trimThr; BlockParam _vCmd; - BlockParam _rocMax; + BlockParam _crMax; struct pollfd _attPoll; vehicle_global_position_setpoint_s _lastPosCmd; diff --git a/apps/examples/control_demo/params.c b/apps/examples/control_demo/params.c index 428b779b17..71eacf25c8 100644 --- a/apps/examples/control_demo/params.c +++ b/apps/examples/control_demo/params.c @@ -59,13 +59,13 @@ PARAM_DEFINE_FLOAT(FWB_V_MAX, 16.0f); // maximum commanded velocity // rate of climb // this is what rate of climb is commanded (in m/s) // when the pitch stick is fully defelcted in simple mode -PARAM_DEFINE_FLOAT(FWB_ROC_MAX, 1.0f); +PARAM_DEFINE_FLOAT(FWB_CR_MAX, 1.0f); -// rate of climb -> thr -PARAM_DEFINE_FLOAT(FWB_ROC2THR_P, 0.01f); // rate of climb to throttle PID -PARAM_DEFINE_FLOAT(FWB_ROC2THR_I, 0.0f); -PARAM_DEFINE_FLOAT(FWB_ROC2THR_D, 0.0f); -PARAM_DEFINE_FLOAT(FWB_ROC2THR_D_LP, 0.0f); -PARAM_DEFINE_FLOAT(FWB_ROC2THR_I_MAX, 0.0f); +// climb rate -> thr +PARAM_DEFINE_FLOAT(FWB_CR2THR_P, 0.01f); // rate of climb to throttle PID +PARAM_DEFINE_FLOAT(FWB_CR2THR_I, 0.0f); +PARAM_DEFINE_FLOAT(FWB_CR2THR_D, 0.0f); +PARAM_DEFINE_FLOAT(FWB_CR2THR_D_LP, 0.0f); +PARAM_DEFINE_FLOAT(FWB_CR2THR_I_MAX, 0.0f); PARAM_DEFINE_FLOAT(FWB_TRIM_THR, 0.8f); // trim throttle (0,1) diff --git a/apps/mavlink/mavlink_receiver.c b/apps/mavlink/mavlink_receiver.c index 22c2fcdade..2ebfc5a10d 100644 --- a/apps/mavlink/mavlink_receiver.c +++ b/apps/mavlink/mavlink_receiver.c @@ -308,82 +308,6 @@ handle_message(mavlink_message_t *msg) uint64_t timestamp = hrt_absolute_time(); - /* TODO, set ground_press/ temp during calib */ - static const float ground_press = 1013.25f; // mbar - static const float ground_tempC = 21.0f; - static const float ground_alt = 0.0f; - static const float T0 = 273.15; - static const float R = 287.05f; - static const float g = 9.806f; - - if (msg->msgid == MAVLINK_MSG_ID_RAW_IMU) { - - mavlink_raw_imu_t imu; - mavlink_msg_raw_imu_decode(msg, &imu); - - /* packet counter */ - static uint16_t hil_counter = 0; - static uint16_t hil_frames = 0; - static uint64_t old_timestamp = 0; - - /* sensors general */ - hil_sensors.timestamp = imu.time_usec; - - /* hil gyro */ - static const float mrad2rad = 1.0e-3f; - hil_sensors.gyro_counter = hil_counter; - hil_sensors.gyro_raw[0] = imu.xgyro; - hil_sensors.gyro_raw[1] = imu.ygyro; - hil_sensors.gyro_raw[2] = imu.zgyro; - hil_sensors.gyro_rad_s[0] = imu.xgyro * mrad2rad; - hil_sensors.gyro_rad_s[1] = imu.ygyro * mrad2rad; - hil_sensors.gyro_rad_s[2] = imu.zgyro * mrad2rad; - - /* accelerometer */ - hil_sensors.accelerometer_counter = hil_counter; - static const float mg2ms2 = 9.8f / 1000.0f; - hil_sensors.accelerometer_raw[0] = imu.xacc; - hil_sensors.accelerometer_raw[1] = imu.yacc; - hil_sensors.accelerometer_raw[2] = imu.zacc; - hil_sensors.accelerometer_m_s2[0] = mg2ms2 * imu.xacc; - hil_sensors.accelerometer_m_s2[1] = mg2ms2 * imu.yacc; - hil_sensors.accelerometer_m_s2[2] = mg2ms2 * imu.zacc; - hil_sensors.accelerometer_mode = 0; // TODO what is this? - hil_sensors.accelerometer_range_m_s2 = 32.7f; // int16 - - /* adc */ - hil_sensors.adc_voltage_v[0] = 0; - hil_sensors.adc_voltage_v[1] = 0; - hil_sensors.adc_voltage_v[2] = 0; - - /* magnetometer */ - float mga2ga = 1.0e-3f; - hil_sensors.magnetometer_counter = hil_counter; - hil_sensors.magnetometer_raw[0] = imu.xmag; - hil_sensors.magnetometer_raw[1] = imu.ymag; - hil_sensors.magnetometer_raw[2] = imu.zmag; - hil_sensors.magnetometer_ga[0] = imu.xmag * mga2ga; - hil_sensors.magnetometer_ga[1] = imu.ymag * mga2ga; - hil_sensors.magnetometer_ga[2] = imu.zmag * mga2ga; - hil_sensors.magnetometer_range_ga = 32.7f; // int16 - hil_sensors.magnetometer_mode = 0; // TODO what is this - hil_sensors.magnetometer_cuttoff_freq_hz = 50.0f; - - /* publish */ - orb_publish(ORB_ID(sensor_combined), pub_hil_sensors, &hil_sensors); - - // increment counters - hil_counter += 1 ; - hil_frames += 1 ; - - // output - if ((timestamp - old_timestamp) > 10000000) { - printf("receiving hil imu at %d hz\n", hil_frames/10); - old_timestamp = timestamp; - hil_frames = 0; - } - } - if (msg->msgid == MAVLINK_MSG_ID_HIGHRES_IMU) { mavlink_highres_imu_t imu; @@ -437,13 +361,9 @@ handle_message(mavlink_message_t *msg) hil_sensors.magnetometer_mode = 0; // TODO what is this hil_sensors.magnetometer_cuttoff_freq_hz = 50.0f; + /* baro */ hil_sensors.baro_pres_mbar = imu.abs_pressure; - - float tempC = imu.temperature; - float tempAvgK = T0 + (tempC + ground_tempC) / 2.0f; - float h = ground_alt + (R / g) * tempAvgK * logf(ground_press / imu.abs_pressure); - - hil_sensors.baro_alt_meter = h; + hil_sensors.baro_alt_meter = imu.pressure_alt; hil_sensors.baro_temp_celcius = imu.temperature; hil_sensors.gyro_counter = hil_counter; @@ -516,44 +436,6 @@ handle_message(mavlink_message_t *msg) } } - if (msg->msgid == MAVLINK_MSG_ID_RAW_PRESSURE) { - - mavlink_raw_pressure_t press; - mavlink_msg_raw_pressure_decode(msg, &press); - - /* packet counter */ - static uint16_t hil_counter = 0; - static uint16_t hil_frames = 0; - static uint64_t old_timestamp = 0; - - /* sensors general */ - hil_sensors.timestamp = press.time_usec; - - /* baro */ - - float tempC = press.temperature / 100.0f; - float tempAvgK = T0 + (tempC + ground_tempC) / 2.0f; - float h = ground_alt + (R / g) * tempAvgK * logf(ground_press / press.press_abs); - hil_sensors.baro_counter = hil_counter; - hil_sensors.baro_pres_mbar = press.press_abs; - hil_sensors.baro_alt_meter = h; - hil_sensors.baro_temp_celcius = tempC; - - /* publish */ - orb_publish(ORB_ID(sensor_combined), pub_hil_sensors, &hil_sensors); - - // increment counters - hil_counter += 1 ; - hil_frames += 1 ; - - // output - if ((timestamp - old_timestamp) > 10000000) { - printf("receiving hil pressure at %d hz\n", hil_frames/10); - old_timestamp = timestamp; - hil_frames = 0; - } - } - if (msg->msgid == MAVLINK_MSG_ID_HIL_STATE) { mavlink_hil_state_t hil_state; From 06e390b5e98b5e83646a8cd5f75b6b546000fc85 Mon Sep 17 00:00:00 2001 From: James Goppert Date: Tue, 30 Apr 2013 16:55:12 -0400 Subject: [PATCH 60/84] Added MD25 I2C motor controller driver. --- apps/drivers/device/i2c.h | 9 + apps/drivers/md25/MD25.cpp | 553 +++++++++++++++++++++++++++++ apps/drivers/md25/MD25.hpp | 293 +++++++++++++++ apps/drivers/md25/Makefile | 43 +++ apps/drivers/md25/md25_main.cpp | 264 ++++++++++++++ nuttx/configs/px4fmu/nsh/appconfig | 1 + nuttx/configs/px4fmu/nsh/defconfig | 4 + 7 files changed, 1167 insertions(+) create mode 100644 apps/drivers/md25/MD25.cpp create mode 100644 apps/drivers/md25/MD25.hpp create mode 100644 apps/drivers/md25/Makefile create mode 100644 apps/drivers/md25/md25_main.cpp diff --git a/apps/drivers/device/i2c.h b/apps/drivers/device/i2c.h index 66c34dd7c4..cc1f4e4d91 100644 --- a/apps/drivers/device/i2c.h +++ b/apps/drivers/device/i2c.h @@ -53,6 +53,15 @@ namespace device __EXPORT class __EXPORT I2C : public CDev { +public: + + /** + * Get the address + */ + uint16_t get_address() { + return _address; + } + protected: /** * The number of times a read or write operation will be retried on diff --git a/apps/drivers/md25/MD25.cpp b/apps/drivers/md25/MD25.cpp new file mode 100644 index 0000000000..92778b109d --- /dev/null +++ b/apps/drivers/md25/MD25.cpp @@ -0,0 +1,553 @@ +/**************************************************************************** + * + * Copyright (C) 2013 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/** + * @file md25.cpp + * + * Driver for MD25 I2C Motor Driver + * + * references: + * http://www.robot-electronics.co.uk/htm/md25tech.htm + * http://www.robot-electronics.co.uk/files/rpi_md25.c + * + */ + +#include "MD25.hpp" +#include +#include + +#include +#include + +// registers +enum { + // RW: read/write + // R: read + REG_SPEED1_RW = 0, + REG_SPEED2_RW, + REG_ENC1A_R, + REG_ENC1B_R, + REG_ENC1C_R, + REG_ENC1D_R, + REG_ENC2A_R, + REG_ENC2B_R, + REG_ENC2C_R, + REG_ENC2D_R, + REG_BATTERY_VOLTS_R, + REG_MOTOR1_CURRENT_R, + REG_MOTOR2_CURRENT_R, + REG_SW_VERSION_R, + REG_ACCEL_RATE_RW, + REG_MODE_RW, + REG_COMMAND_RW, +}; + +MD25::MD25(const char *deviceName, int bus, + uint16_t address, uint32_t speed) : + I2C("MD25", deviceName, bus, address, speed), + _controlPoll(), + _actuators(NULL, ORB_ID(actuator_controls_0), 20), + _version(0), + _motor1Speed(0), + _motor2Speed(0), + _revolutions1(0), + _revolutions2(0), + _batteryVoltage(0), + _motor1Current(0), + _motor2Current(0), + _motorAccel(0), + _mode(MODE_UNSIGNED_SPEED), + _command(CMD_RESET_ENCODERS) +{ + // setup control polling + _controlPoll.fd = _actuators.getHandle(); + _controlPoll.events = POLLIN; + + // if initialization fails raise an error, unless + // probing + int ret = I2C::init(); + + if (ret != OK) { + warnc(ret, "I2C::init failed for bus: %d address: %d\n", bus, address); + } + + // setup default settings, reset encoders + setMotor1Speed(0); + setMotor2Speed(0); + resetEncoders(); + _setMode(MD25::MODE_UNSIGNED_SPEED); + setSpeedRegulation(true); + setTimeout(true); +} + +MD25::~MD25() +{ +} + +int MD25::readData() +{ + uint8_t sendBuf[1]; + sendBuf[0] = REG_SPEED1_RW; + uint8_t recvBuf[17]; + int ret = transfer(sendBuf, sizeof(sendBuf), + recvBuf, sizeof(recvBuf)); + + if (ret == OK) { + _version = recvBuf[REG_SW_VERSION_R]; + _motor1Speed = _uint8ToNorm(recvBuf[REG_SPEED1_RW]); + _motor2Speed = _uint8ToNorm(recvBuf[REG_SPEED2_RW]); + _revolutions1 = -int32_t((recvBuf[REG_ENC1A_R] << 24) + + (recvBuf[REG_ENC1B_R] << 16) + + (recvBuf[REG_ENC1C_R] << 8) + + recvBuf[REG_ENC1D_R]) / 360.0; + _revolutions2 = -int32_t((recvBuf[REG_ENC2A_R] << 24) + + (recvBuf[REG_ENC2B_R] << 16) + + (recvBuf[REG_ENC2C_R] << 8) + + recvBuf[REG_ENC2D_R]) / 360.0; + _batteryVoltage = recvBuf[REG_BATTERY_VOLTS_R] / 10.0; + _motor1Current = recvBuf[REG_MOTOR1_CURRENT_R] / 10.0; + _motor2Current = recvBuf[REG_MOTOR2_CURRENT_R] / 10.0; + _motorAccel = recvBuf[REG_ACCEL_RATE_RW]; + _mode = e_mode(recvBuf[REG_MODE_RW]); + _command = e_cmd(recvBuf[REG_COMMAND_RW]); + } + + return ret; +} + +void MD25::status(char *string, size_t n) +{ + snprintf(string, n, + "version:\t%10d\n" \ + "motor 1 speed:\t%10.2f\n" \ + "motor 2 speed:\t%10.2f\n" \ + "revolutions 1:\t%10.2f\n" \ + "revolutions 2:\t%10.2f\n" \ + "battery volts :\t%10.2f\n" \ + "motor 1 current :\t%10.2f\n" \ + "motor 2 current :\t%10.2f\n" \ + "motor accel :\t%10d\n" \ + "mode :\t%10d\n" \ + "command :\t%10d\n", + getVersion(), + double(getMotor1Speed()), + double(getMotor2Speed()), + double(getRevolutions1()), + double(getRevolutions2()), + double(getBatteryVolts()), + double(getMotor1Current()), + double(getMotor2Current()), + getMotorAccel(), + getMode(), + getCommand()); +} + +uint8_t MD25::getVersion() +{ + return _version; +} + +float MD25::getMotor1Speed() +{ + return _motor1Speed; +} + +float MD25::getMotor2Speed() +{ + return _motor2Speed; +} + +float MD25::getRevolutions1() +{ + return _revolutions1; +} + +float MD25::getRevolutions2() +{ + return _revolutions2; +} + +float MD25::getBatteryVolts() +{ + return _batteryVoltage; +} + +float MD25::getMotor1Current() +{ + return _motor1Current; +} +float MD25::getMotor2Current() +{ + return _motor2Current; +} + +uint8_t MD25::getMotorAccel() +{ + return _motorAccel; +} + +MD25::e_mode MD25::getMode() +{ + return _mode; +} + +MD25::e_cmd MD25::getCommand() +{ + return _command; +} + +int MD25::resetEncoders() +{ + return _writeUint8(REG_COMMAND_RW, + CMD_RESET_ENCODERS); +} + +int MD25::_setMode(e_mode mode) +{ + return _writeUint8(REG_MODE_RW, + mode); +} + +int MD25::setSpeedRegulation(bool enable) +{ + if (enable) { + return _writeUint8(REG_COMMAND_RW, + CMD_ENABLE_SPEED_REGULATION); + + } else { + return _writeUint8(REG_COMMAND_RW, + CMD_DISABLE_SPEED_REGULATION); + } +} + +int MD25::setTimeout(bool enable) +{ + if (enable) { + return _writeUint8(REG_COMMAND_RW, + CMD_ENABLE_TIMEOUT); + + } else { + return _writeUint8(REG_COMMAND_RW, + CMD_DISABLE_TIMEOUT); + } +} + +int MD25::setDeviceAddress(uint8_t address) +{ + uint8_t sendBuf[1]; + sendBuf[0] = CMD_CHANGE_I2C_SEQ_0; + int ret = OK; + ret = transfer(sendBuf, sizeof(sendBuf), + nullptr, 0); + + if (ret != OK) { + warnc(ret, "MD25::setDeviceAddress"); + return ret; + } + + usleep(5000); + sendBuf[0] = CMD_CHANGE_I2C_SEQ_1; + ret = transfer(sendBuf, sizeof(sendBuf), + nullptr, 0); + + if (ret != OK) { + warnc(ret, "MD25::setDeviceAddress"); + return ret; + } + + usleep(5000); + sendBuf[0] = CMD_CHANGE_I2C_SEQ_2; + ret = transfer(sendBuf, sizeof(sendBuf), + nullptr, 0); + + if (ret != OK) { + warnc(ret, "MD25::setDeviceAddress"); + return ret; + } + + return OK; +} + +int MD25::setMotor1Speed(float value) +{ + return _writeUint8(REG_SPEED1_RW, + _normToUint8(value)); +} + +int MD25::setMotor2Speed(float value) +{ + return _writeUint8(REG_SPEED2_RW, + _normToUint8(value)); +} + +void MD25::update() +{ + // wait for an actuator publication, + // check for exit condition every second + // note "::poll" is required to distinguish global + // poll from member function for driver + if (::poll(&_controlPoll, 1, 1000) < 0) return; // poll error + + // if new data, send to motors + if (_actuators.updated()) { + _actuators.update(); + setMotor1Speed(_actuators.control[CH_SPEED_LEFT]); + setMotor2Speed(_actuators.control[CH_SPEED_RIGHT]); + } +} + +int MD25::probe() +{ + uint8_t goodAddress = 0; + bool found = false; + int ret = OK; + + // try initial address first, if good, then done + if (readData() == OK) return ret; + + // try all other addresses + uint8_t testAddress = 0; + + //printf("searching for MD25 address\n"); + while (true) { + set_address(testAddress); + ret = readData(); + + if (ret == OK && !found) { + //printf("device found at address: 0x%X\n", testAddress); + if (!found) { + found = true; + goodAddress = testAddress; + } + } + + if (testAddress > 254) { + break; + } + + testAddress++; + } + + if (found) { + set_address(goodAddress); + return OK; + + } else { + set_address(0); + return ret; + } +} + +int MD25::search() +{ + uint8_t goodAddress = 0; + bool found = false; + int ret = OK; + // try all other addresses + uint8_t testAddress = 0; + + //printf("searching for MD25 address\n"); + while (true) { + set_address(testAddress); + ret = readData(); + + if (ret == OK && !found) { + printf("device found at address: 0x%X\n", testAddress); + + if (!found) { + found = true; + goodAddress = testAddress; + } + } + + if (testAddress > 254) { + break; + } + + testAddress++; + } + + if (found) { + set_address(goodAddress); + return OK; + + } else { + set_address(0); + return ret; + } +} + +int MD25::_writeUint8(uint8_t reg, uint8_t value) +{ + uint8_t sendBuf[2]; + sendBuf[0] = reg; + sendBuf[1] = value; + return transfer(sendBuf, sizeof(sendBuf), + nullptr, 0); +} + +int MD25::_writeInt8(uint8_t reg, int8_t value) +{ + uint8_t sendBuf[2]; + sendBuf[0] = reg; + sendBuf[1] = value; + return transfer(sendBuf, sizeof(sendBuf), + nullptr, 0); +} + +float MD25::_uint8ToNorm(uint8_t value) +{ + // TODO, should go from 0 to 255 + // possibly should handle this differently + return (value - 128) / 127.0; +} + +uint8_t MD25::_normToUint8(float value) +{ + if (value > 1) value = 1; + + if (value < -1) value = -1; + + // TODO, should go from 0 to 255 + // possibly should handle this differently + return 127 * value + 128; +} + +int md25Test(const char *deviceName, uint8_t bus, uint8_t address) +{ + printf("md25 test: starting\n"); + + // setup + MD25 md25("/dev/md25", bus, address); + + // print status + char buf[200]; + md25.status(buf, sizeof(buf)); + printf("%s\n", buf); + + // setup for test + md25.setSpeedRegulation(true); + md25.setTimeout(true); + float dt = 0.1; + float speed = 0.2; + float t = 0; + + // motor 1 test + printf("md25 test: spinning motor 1 forward for 1 rev at 0.1 speed\n"); + t = 0; + + while (true) { + t += dt; + md25.setMotor1Speed(speed); + md25.readData(); + usleep(1000000 * dt); + + if (md25.getRevolutions1() > 1) { + printf("finished 1 revolution fwd\n"); + break; + } + + if (t > 2.0f) break; + } + + md25.setMotor1Speed(0); + printf("revolution of wheel 1: %8.4f\n", double(md25.getRevolutions1())); + md25.resetEncoders(); + + t = 0; + + while (true) { + t += dt; + md25.setMotor1Speed(-speed); + md25.readData(); + usleep(1000000 * dt); + + if (md25.getRevolutions1() < -1) { + printf("finished 1 revolution rev\n"); + break; + } + + if (t > 2.0f) break; + } + + md25.setMotor1Speed(0); + printf("revolution of wheel 1: %8.4f\n", double(md25.getRevolutions1())); + md25.resetEncoders(); + + // motor 2 test + printf("md25 test: spinning motor 2 forward for 1 rev at 0.1 speed\n"); + t = 0; + + while (true) { + t += dt; + md25.setMotor2Speed(speed); + md25.readData(); + usleep(1000000 * dt); + + if (md25.getRevolutions2() > 1) { + printf("finished 1 revolution fwd\n"); + break; + } + + if (t > 2.0f) break; + } + + md25.setMotor2Speed(0); + printf("revolution of wheel 2: %8.4f\n", double(md25.getRevolutions2())); + md25.resetEncoders(); + + t = 0; + + while (true) { + t += dt; + md25.setMotor2Speed(-speed); + md25.readData(); + usleep(1000000 * dt); + + if (md25.getRevolutions2() < -1) { + printf("finished 1 revolution rev\n"); + break; + } + + if (t > 2.0f) break; + } + + md25.setMotor2Speed(0); + printf("revolution of wheel 2: %8.4f\n", double(md25.getRevolutions2())); + md25.resetEncoders(); + + printf("Test complete\n"); + return 0; +} + +// vi:noet:smarttab:autoindent:ts=4:sw=4:tw=78 diff --git a/apps/drivers/md25/MD25.hpp b/apps/drivers/md25/MD25.hpp new file mode 100644 index 0000000000..e77511b163 --- /dev/null +++ b/apps/drivers/md25/MD25.hpp @@ -0,0 +1,293 @@ +/**************************************************************************** + * + * Copyright (C) 2013 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/** + * @file md25.cpp + * + * Driver for MD25 I2C Motor Driver + * + * references: + * http://www.robot-electronics.co.uk/htm/md25tech.htm + * http://www.robot-electronics.co.uk/files/rpi_md25.c + * + */ + +#pragma once + +#include +#include +#include +#include +#include + +/** + * This is a driver for the MD25 motor controller utilizing the I2C interface. + */ +class MD25 : public device::I2C +{ +public: + + /** + * modes + * + * NOTE: this driver assumes we are always + * in mode 0! + * + * seprate speed mode: + * motor speed1 = speed1 + * motor speed2 = speed2 + * turn speed mode: + * motor speed1 = speed1 + speed2 + * motor speed2 = speed2 - speed2 + * unsigned: + * full rev (0), stop(128), full fwd (255) + * signed: + * full rev (-127), stop(0), full fwd (128) + * + * modes numbers: + * 0 : unsigned separate (default) + * 1 : signed separate + * 2 : unsigned turn + * 3 : signed turn + */ + enum e_mode { + MODE_UNSIGNED_SPEED = 0, + MODE_SIGNED_SPEED, + MODE_UNSIGNED_SPEED_TURN, + MODE_SIGNED_SPEED_TURN, + }; + + /** commands */ + enum e_cmd { + CMD_RESET_ENCODERS = 32, + CMD_DISABLE_SPEED_REGULATION = 48, + CMD_ENABLE_SPEED_REGULATION = 49, + CMD_DISABLE_TIMEOUT = 50, + CMD_ENABLE_TIMEOUT = 51, + CMD_CHANGE_I2C_SEQ_0 = 160, + CMD_CHANGE_I2C_SEQ_1 = 170, + CMD_CHANGE_I2C_SEQ_2 = 165, + }; + + /** control channels */ + enum e_channels { + CH_SPEED_LEFT = 0, + CH_SPEED_RIGHT + }; + + /** + * constructor + * @param deviceName the name of the device e.g. "/dev/md25" + * @param bus the I2C bus + * @param address the adddress on the I2C bus + * @param speed the speed of the I2C communication + */ + MD25(const char *deviceName, + int bus, + uint16_t address, + uint32_t speed = 100000); + + /** + * deconstructor + */ + virtual ~MD25(); + + /** + * @return software version + */ + uint8_t getVersion(); + + /** + * @return speed of motor, normalized (-1, 1) + */ + float getMotor1Speed(); + + /** + * @return speed of motor 2, normalized (-1, 1) + */ + float getMotor2Speed(); + + /** + * @return number of rotations since reset + */ + float getRevolutions1(); + + /** + * @return number of rotations since reset + */ + float getRevolutions2(); + + /** + * @return battery voltage, volts + */ + float getBatteryVolts(); + + /** + * @return motor 1 current, amps + */ + float getMotor1Current(); + + /** + * @return motor 2 current, amps + */ + float getMotor2Current(); + + /** + * @return the motor acceleration + * controls motor speed change (1-10) + * accel rate | time for full fwd. to full rev. + * 1 | 6.375 s + * 2 | 1.6 s + * 3 | 0.675 s + * 5(default) | 1.275 s + * 10 | 0.65 s + */ + uint8_t getMotorAccel(); + + /** + * @return motor output mode + * */ + e_mode getMode(); + + /** + * @return current command register value + */ + e_cmd getCommand(); + + /** + * resets the encoders + * @return non-zero -> error + * */ + int resetEncoders(); + + /** + * enable/disable speed regulation + * @return non-zero -> error + */ + int setSpeedRegulation(bool enable); + + /** + * set the timeout for the motors + * enable/disable timeout (motor stop) + * after 2 sec of no i2c messages + * @return non-zero -> error + */ + int setTimeout(bool enable); + + /** + * sets the device address + * can only be done with one MD25 + * on the bus + * @return non-zero -> error + */ + int setDeviceAddress(uint8_t address); + + /** + * set motor 1 speed + * @param normSpeed normalize speed between -1 and 1 + * @return non-zero -> error + */ + int setMotor1Speed(float normSpeed); + + /** + * set motor 2 speed + * @param normSpeed normalize speed between -1 and 1 + * @return non-zero -> error + */ + int setMotor2Speed(float normSpeed); + + /** + * main update loop that updates MD25 motor + * speeds based on actuator publication + */ + void update(); + + /** + * probe for device + */ + virtual int probe(); + + /** + * search for device + */ + int search(); + + /** + * read data from i2c + */ + int readData(); + + /** + * print status + */ + void status(char *string, size_t n); + +private: + /** poll structure for control packets */ + struct pollfd _controlPoll; + + /** actuator controls subscription */ + control::UOrbSubscription _actuators; + + // local copy of data from i2c device + uint8_t _version; + float _motor1Speed; + float _motor2Speed; + float _revolutions1; + float _revolutions2; + float _batteryVoltage; + float _motor1Current; + float _motor2Current; + uint8_t _motorAccel; + e_mode _mode; + e_cmd _command; + + // private methods + int _writeUint8(uint8_t reg, uint8_t value); + int _writeInt8(uint8_t reg, int8_t value); + float _uint8ToNorm(uint8_t value); + uint8_t _normToUint8(float value); + + /** + * set motor control mode, + * this driver assumed we are always in mode 0 + * so we don't let the user change the mode + * @return non-zero -> error + */ + int _setMode(e_mode); +}; + +// unit testing +int md25Test(const char *deviceName, uint8_t bus, uint8_t address); + +// vi:noet:smarttab:autoindent:ts=4:sw=4:tw=78 diff --git a/apps/drivers/md25/Makefile b/apps/drivers/md25/Makefile new file mode 100644 index 0000000000..cce2fd0953 --- /dev/null +++ b/apps/drivers/md25/Makefile @@ -0,0 +1,43 @@ +############################################################################ +# +# Copyright (C) 2013 PX4 Development Team. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name PX4 nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +# +# MD25 I2C Based Motor Controller +# http://www.robot-electronics.co.uk/htm/md25tech.htm +# + +APPNAME = md25 +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 2048 + +include $(APPDIR)/mk/app.mk diff --git a/apps/drivers/md25/md25_main.cpp b/apps/drivers/md25/md25_main.cpp new file mode 100644 index 0000000000..85aaab7f6d --- /dev/null +++ b/apps/drivers/md25/md25_main.cpp @@ -0,0 +1,264 @@ +/**************************************************************************** + * + * Copyright (C) 2013 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + + + +/** + * @ file md25.cpp + * + * Driver for MD25 I2C Motor Driver + * + * references: + * http://www.robot-electronics.co.uk/htm/md25tech.htm + * http://www.robot-electronics.co.uk/files/rpi_md25.c + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include "MD25.hpp" + +static bool thread_should_exit = false; /**< Deamon exit flag */ +static bool thread_running = false; /**< Deamon status flag */ +static int deamon_task; /**< Handle of deamon task / thread */ + +/** + * Deamon management function. + */ +extern "C" __EXPORT int md25_main(int argc, char *argv[]); + +/** + * Mainloop of deamon. + */ +int md25_thread_main(int argc, char *argv[]); + +/** + * Print the correct usage. + */ +static void usage(const char *reason); + +static void +usage(const char *reason) +{ + if (reason) + fprintf(stderr, "%s\n", reason); + + fprintf(stderr, "usage: md25 {start|stop|status|search|test|change_address}\n\n"); + exit(1); +} + +/** + * The deamon app only briefly exists to start + * the background job. The stack size assigned in the + * Makefile does only apply to this management task. + * + * The actual stack size should be set in the call + * to task_create(). + */ +int md25_main(int argc, char *argv[]) +{ + + if (argc < 1) + usage("missing command"); + + if (!strcmp(argv[1], "start")) { + + if (thread_running) { + printf("md25 already running\n"); + /* this is not an error */ + exit(0); + } + + thread_should_exit = false; + deamon_task = task_spawn("md25", + SCHED_DEFAULT, + SCHED_PRIORITY_MAX - 10, + 2048, + md25_thread_main, + (const char **)argv); + exit(0); + } + + if (!strcmp(argv[1], "test")) { + + if (argc < 4) { + printf("usage: md25 test bus address\n"); + exit(0); + } + + const char *deviceName = "/dev/md25"; + + uint8_t bus = strtoul(argv[2], nullptr, 0); + + uint8_t address = strtoul(argv[3], nullptr, 0); + + md25Test(deviceName, bus, address); + + exit(0); + } + + if (!strcmp(argv[1], "probe")) { + if (argc < 4) { + printf("usage: md25 probe bus address\n"); + exit(0); + } + + const char *deviceName = "/dev/md25"; + + uint8_t bus = strtoul(argv[2], nullptr, 0); + + uint8_t address = strtoul(argv[3], nullptr, 0); + + MD25 md25(deviceName, bus, address); + + int ret = md25.probe(); + + if (ret == OK) { + printf("MD25 found on bus %d at address 0x%X\n", bus, md25.get_address()); + + } else { + printf("MD25 not found on bus %d\n", bus); + } + + exit(0); + } + + if (!strcmp(argv[1], "search")) { + if (argc < 3) { + printf("usage: md25 search bus\n"); + exit(0); + } + + const char *deviceName = "/dev/md25"; + + uint8_t bus = strtoul(argv[2], nullptr, 0); + + uint8_t address = strtoul(argv[3], nullptr, 0); + + MD25 md25(deviceName, bus, address); + + md25.search(); + + exit(0); + } + + if (!strcmp(argv[1], "change_address")) { + if (argc < 5) { + printf("usage: md25 change_address bus old_address new_address\n"); + exit(0); + } + + const char *deviceName = "/dev/md25"; + + uint8_t bus = strtoul(argv[2], nullptr, 0); + + uint8_t old_address = strtoul(argv[3], nullptr, 0); + + uint8_t new_address = strtoul(argv[4], nullptr, 0); + + MD25 md25(deviceName, bus, old_address); + + int ret = md25.setDeviceAddress(new_address); + + if (ret == OK) { + printf("MD25 new address set to 0x%X\n", new_address); + + } else { + printf("MD25 failed to set address to 0x%X\n", new_address); + } + + exit(0); + } + + if (!strcmp(argv[1], "stop")) { + thread_should_exit = true; + exit(0); + } + + if (!strcmp(argv[1], "status")) { + if (thread_running) { + printf("\tmd25 app is running\n"); + + } else { + printf("\tmd25 app not started\n"); + } + + exit(0); + } + + usage("unrecognized command"); + exit(1); +} + +int md25_thread_main(int argc, char *argv[]) +{ + printf("[MD25] starting\n"); + + if (argc < 5) { + // extra md25 in arg list since this is a thread + printf("usage: md25 start bus address\n"); + exit(0); + } + + const char *deviceName = "/dev/md25"; + + uint8_t bus = strtoul(argv[3], nullptr, 0); + + uint8_t address = strtoul(argv[4], nullptr, 0); + + // start + MD25 md25("/dev/md25", bus, address); + + thread_running = true; + + // loop + while (!thread_should_exit) { + md25.update(); + } + + // exit + printf("[MD25] exiting.\n"); + thread_running = false; + return 0; +} + +// vi:noet:smarttab:autoindent:ts=4:sw=4:tw=78 diff --git a/nuttx/configs/px4fmu/nsh/appconfig b/nuttx/configs/px4fmu/nsh/appconfig index 82ab94be78..300ed3f31a 100644 --- a/nuttx/configs/px4fmu/nsh/appconfig +++ b/nuttx/configs/px4fmu/nsh/appconfig @@ -128,6 +128,7 @@ CONFIGURED_APPS += drivers/mkblctrl CONFIGURED_APPS += drivers/hil CONFIGURED_APPS += drivers/gps CONFIGURED_APPS += drivers/mb12xx +CONFIGURED_APPS += drivers/md25 # Testing stuff CONFIGURED_APPS += px4/sensors_bringup diff --git a/nuttx/configs/px4fmu/nsh/defconfig b/nuttx/configs/px4fmu/nsh/defconfig index 130886aac2..b89a08708d 100755 --- a/nuttx/configs/px4fmu/nsh/defconfig +++ b/nuttx/configs/px4fmu/nsh/defconfig @@ -647,10 +647,14 @@ CONFIG_DISABLE_POLL=n # CONFIG_LIBC_FIXEDPRECISION - Sets 7 digits after dot for printing: # 5.1234567 # CONFIG_HAVE_LONG_LONG - Enabled printf("%llu) +# CONFIG_LIBC_STRERR - allow printing of error text +# CONFIG_LIBC_STRERR_SHORT - allow printing of short error text # CONFIG_NOPRINTF_FIELDWIDTH=n CONFIG_LIBC_FLOATINGPOINT=y CONFIG_HAVE_LONG_LONG=y +CONFIG_LIBC_STRERROR=n +CONFIG_LIBC_STRERROR_SHORT=n # # Allow for architecture optimized implementations From 1caffca3584fe323c83206379cc337e19768d854 Mon Sep 17 00:00:00 2001 From: px4dev Date: Wed, 8 May 2013 22:50:18 -0700 Subject: [PATCH 61/84] whitespace --- makefiles/firmware.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefiles/firmware.mk b/makefiles/firmware.mk index fff0e1c65c..b63aa28d73 100644 --- a/makefiles/firmware.mk +++ b/makefiles/firmware.mk @@ -193,7 +193,7 @@ EXTRA_CLEANS = # for GMSL). # where to look for modules -MODULE_SEARCH_DIRS += $(WORK_DIR) $(MODULE_SRC) $(PX4_MODULE_SRC) +MODULE_SEARCH_DIRS += $(WORK_DIR) $(MODULE_SRC) $(PX4_MODULE_SRC) # sort and unique the modules list MODULES := $(sort $(MODULES)) From 296a19072d26dfb814f7ca164e508b9203d51ac1 Mon Sep 17 00:00:00 2001 From: Lorenz Meier Date: Thu, 9 May 2013 15:39:54 +0200 Subject: [PATCH 62/84] Enabled leds on FMU again --- makefiles/config_px4fmu_default.mk | 1 + src/drivers/boards/px4fmu/module.mk | 3 ++- src/drivers/boards/px4fmu/px4fmu_init.c | 27 +++++++++++++++++------- src/drivers/boards/px4fmu/px4fmu_led.c | 28 ++++++++++++++++--------- src/drivers/led/led.cpp | 21 ++++++++++++------- 5 files changed, 54 insertions(+), 26 deletions(-) diff --git a/makefiles/config_px4fmu_default.mk b/makefiles/config_px4fmu_default.mk index 07f9bdbc32..7f12ca7315 100644 --- a/makefiles/config_px4fmu_default.mk +++ b/makefiles/config_px4fmu_default.mk @@ -14,6 +14,7 @@ MODULES += drivers/device MODULES += drivers/stm32 MODULES += drivers/stm32/adc MODULES += drivers/stm32/tone_alarm +MODULES += drivers/led MODULES += drivers/px4io MODULES += drivers/px4fmu MODULES += drivers/boards/px4fmu diff --git a/src/drivers/boards/px4fmu/module.mk b/src/drivers/boards/px4fmu/module.mk index 2cb261d305..66b7769173 100644 --- a/src/drivers/boards/px4fmu/module.mk +++ b/src/drivers/boards/px4fmu/module.mk @@ -6,4 +6,5 @@ SRCS = px4fmu_can.c \ px4fmu_init.c \ px4fmu_pwm_servo.c \ px4fmu_spi.c \ - px4fmu_usb.c + px4fmu_usb.c \ + px4fmu_led.c diff --git a/src/drivers/boards/px4fmu/px4fmu_init.c b/src/drivers/boards/px4fmu/px4fmu_init.c index 5dd70c3f95..69edc23ab2 100644 --- a/src/drivers/boards/px4fmu/px4fmu_init.c +++ b/src/drivers/boards/px4fmu/px4fmu_init.c @@ -1,6 +1,6 @@ /**************************************************************************** * - * Copyright (C) 2012 PX4 Development Team. All rights reserved. + * Copyright (c) 2012, 2013 PX4 Development Team. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -91,6 +91,19 @@ # endif #endif +/* + * Ideally we'd be able to get these from up_internal.h, + * but since we want to be able to disable the NuttX use + * of leds for system indication at will and there is no + * separate switch, we need to build independent of the + * CONFIG_ARCH_LEDS configuration switch. + */ +__BEGIN_DECLS +extern void led_init(); +extern void led_on(int led); +extern void led_off(int led); +__END_DECLS + /**************************************************************************** * Protected Functions ****************************************************************************/ @@ -114,7 +127,7 @@ __EXPORT void stm32_boardinitialize(void) /* configure SPI interfaces */ stm32_spiinitialize(); - /* configure LEDs */ + /* configure LEDs (empty call to NuttX' ledinit) */ up_ledinit(); } @@ -178,11 +191,11 @@ __EXPORT int nsh_archinitialize(void) (hrt_callout)stm32_serial_dma_poll, NULL); - // initial LED state -// drv_led_start(); - up_ledoff(LED_BLUE); - up_ledoff(LED_AMBER); - up_ledon(LED_BLUE); + /* initial LED state */ + drv_led_start(); + led_off(LED_AMBER); + led_on(LED_BLUE); + /* Configure SPI-based devices */ diff --git a/src/drivers/boards/px4fmu/px4fmu_led.c b/src/drivers/boards/px4fmu/px4fmu_led.c index fd1e159aa7..34fd194c33 100644 --- a/src/drivers/boards/px4fmu/px4fmu_led.c +++ b/src/drivers/boards/px4fmu/px4fmu_led.c @@ -39,19 +39,27 @@ #include -#include #include -#include -#include - -#include "chip.h" -#include "up_arch.h" -#include "up_internal.h" #include "stm32_internal.h" #include "px4fmu_internal.h" -__EXPORT void up_ledinit() +#include + +/* + * Ideally we'd be able to get these from up_internal.h, + * but since we want to be able to disable the NuttX use + * of leds for system indication at will and there is no + * separate switch, we need to build independent of the + * CONFIG_ARCH_LEDS configuration switch. + */ +__BEGIN_DECLS +extern void led_init(); +extern void led_on(int led); +extern void led_off(int led); +__END_DECLS + +__EXPORT void led_init() { /* Configure LED1-2 GPIOs for output */ @@ -59,7 +67,7 @@ __EXPORT void up_ledinit() stm32_configgpio(GPIO_LED2); } -__EXPORT void up_ledon(int led) +__EXPORT void led_on(int led) { if (led == 0) { @@ -73,7 +81,7 @@ __EXPORT void up_ledon(int led) } } -__EXPORT void up_ledoff(int led) +__EXPORT void led_off(int led) { if (led == 0) { diff --git a/src/drivers/led/led.cpp b/src/drivers/led/led.cpp index c7c45525e1..04b565358c 100644 --- a/src/drivers/led/led.cpp +++ b/src/drivers/led/led.cpp @@ -41,12 +41,17 @@ #include #include -/* Ideally we'd be able to get these from up_internal.h */ -//#include +/* + * Ideally we'd be able to get these from up_internal.h, + * but since we want to be able to disable the NuttX use + * of leds for system indication at will and there is no + * separate switch, we need to build independent of the + * CONFIG_ARCH_LEDS configuration switch. + */ __BEGIN_DECLS -extern void up_ledinit(); -extern void up_ledon(int led); -extern void up_ledoff(int led); +extern void led_init(); +extern void led_on(int led); +extern void led_off(int led); __END_DECLS class LED : device::CDev @@ -74,7 +79,7 @@ int LED::init() { CDev::init(); - up_ledinit(); + led_init(); return 0; } @@ -86,11 +91,11 @@ LED::ioctl(struct file *filp, int cmd, unsigned long arg) switch (cmd) { case LED_ON: - up_ledon(arg); + led_on(arg); break; case LED_OFF: - up_ledoff(arg); + led_off(arg); break; default: From 3ec536a876a66f4e56549957e81ed4547c92a0c3 Mon Sep 17 00:00:00 2001 From: Lorenz Meier Date: Thu, 9 May 2013 17:13:38 +0200 Subject: [PATCH 63/84] Improved GPS update rate calculation --- src/drivers/gps/gps.cpp | 4 ++-- src/drivers/gps/gps_helper.cpp | 11 +++++++++-- src/drivers/gps/gps_helper.h | 4 ++++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/drivers/gps/gps.cpp b/src/drivers/gps/gps.cpp index 7db2578160..38835418b0 100644 --- a/src/drivers/gps/gps.cpp +++ b/src/drivers/gps/gps.cpp @@ -288,7 +288,6 @@ GPS::task_main() // GPS is obviously detected successfully, reset statistics _Helper->reset_update_rates(); - warnx("module configuration successful"); while (_Helper->receive(TIMEOUT_5HZ) > 0 && !_task_should_exit) { // lock(); @@ -306,6 +305,8 @@ GPS::task_main() _rate = last_rate_count / ((float)((hrt_absolute_time() - last_rate_measurement)) / 1000000.0f); last_rate_measurement = hrt_absolute_time(); last_rate_count = 0; + _Helper->store_update_rates(); + _Helper->reset_update_rates(); } if (!_healthy) { @@ -381,7 +382,6 @@ GPS::print_info() warnx("rate velocity: \t%6.2f Hz", (double)_Helper->get_velocity_update_rate()); warnx("rate publication:\t%6.2f Hz", (double)_rate); - _Helper->reset_update_rates(); } usleep(100000); diff --git a/src/drivers/gps/gps_helper.cpp b/src/drivers/gps/gps_helper.cpp index 54ac90dabd..ba86d370a8 100644 --- a/src/drivers/gps/gps_helper.cpp +++ b/src/drivers/gps/gps_helper.cpp @@ -46,13 +46,13 @@ float GPS_Helper::get_position_update_rate() { - return _rate_count_lat_lon / (((float)(hrt_absolute_time() - _interval_rate_start)) / 1000000.0f); + return _rate_lat_lon; } float GPS_Helper::get_velocity_update_rate() { - return _rate_count_vel / (((float)(hrt_absolute_time() - _interval_rate_start)) / 1000000.0f); + return _rate_vel; } float @@ -63,6 +63,13 @@ GPS_Helper::reset_update_rates() _interval_rate_start = hrt_absolute_time(); } +float +GPS_Helper::store_update_rates() +{ + _rate_vel = _rate_count_vel / (((float)(hrt_absolute_time() - _interval_rate_start)) / 1000000.0f); + _rate_lat_lon = _rate_count_lat_lon / (((float)(hrt_absolute_time() - _interval_rate_start)) / 1000000.0f); +} + int GPS_Helper::set_baudrate(const int &fd, unsigned baud) { diff --git a/src/drivers/gps/gps_helper.h b/src/drivers/gps/gps_helper.h index 7e456a6aae..defc1a074a 100644 --- a/src/drivers/gps/gps_helper.h +++ b/src/drivers/gps/gps_helper.h @@ -52,11 +52,15 @@ public: float get_position_update_rate(); float get_velocity_update_rate(); float reset_update_rates(); + float store_update_rates(); protected: uint8_t _rate_count_lat_lon; uint8_t _rate_count_vel; + float _rate_lat_lon; + float _rate_vel; + uint64_t _interval_rate_start; }; From fa1b7388f3485d8c7af42607b154f529d43153ea Mon Sep 17 00:00:00 2001 From: Lorenz Meier Date: Thu, 9 May 2013 17:34:00 +0200 Subject: [PATCH 64/84] Implemented new led status proposal --- src/modules/commander/commander.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/modules/commander/commander.c b/src/modules/commander/commander.c index 01ab9e3d9c..cd2ef8137e 100644 --- a/src/modules/commander/commander.c +++ b/src/modules/commander/commander.c @@ -1503,22 +1503,40 @@ int commander_thread_main(int argc, char *argv[]) if ((current_status.state_machine == SYSTEM_STATE_GROUND_READY || current_status.state_machine == SYSTEM_STATE_AUTO || current_status.state_machine == SYSTEM_STATE_MANUAL)) { - /* armed */ - led_toggle(LED_BLUE); + /* armed, solid */ + led_on(LED_AMBER); } else if (counter % (1000000 / COMMANDER_MONITORING_INTERVAL) == 0) { /* not armed */ - led_toggle(LED_BLUE); + led_toggle(LED_AMBER); } - /* toggle error led at 5 Hz in HIL mode */ + if (hrt_absolute_time() - gps_position.timestamp_position < 2000000) { + + /* toggle GPS (blue) led at 1 Hz if GPS present but no lock, make is solid once locked */ + if ((hrt_absolute_time() - gps_position.timestamp_position < 2000000) + && (gps_position.fix_type == GPS_FIX_TYPE_3D)) { + /* GPS lock */ + led_on(LED_BLUE); + + } else if (counter % (1000000 / COMMANDER_MONITORING_INTERVAL) == 0) { + /* no GPS lock, but GPS module is aquiring lock */ + led_toggle(LED_BLUE); + } + + } else { + /* no GPS info, don't light the blue led */ + led_off(LED_BLUE); + } + + /* toggle GPS led at 5 Hz in HIL mode */ if (current_status.flag_hil_enabled) { /* hil enabled */ - led_toggle(LED_AMBER); + led_toggle(LED_BLUE); } else if (bat_remain < 0.3f && (low_voltage_counter > LOW_VOLTAGE_BATTERY_COUNTER_LIMIT)) { /* toggle error (red) at 5 Hz on low battery or error */ - led_toggle(LED_AMBER); + led_toggle(LED_BLUE); } else { // /* Constant error indication in standby mode without GPS */ From 26efba2ff365b1463ca9f6aaaf936557a92c4eb1 Mon Sep 17 00:00:00 2001 From: Lorenz Meier Date: Thu, 9 May 2013 17:38:12 +0200 Subject: [PATCH 65/84] New blink patterns for safety switch, removed GPS lock indicator --- src/drivers/px4io/px4io.cpp | 11 ++--------- src/modules/px4iofirmware/protocol.h | 1 - src/modules/px4iofirmware/safety.c | 9 +++------ 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/src/drivers/px4io/px4io.cpp b/src/drivers/px4io/px4io.cpp index b4703839bf..e69fbebf74 100644 --- a/src/drivers/px4io/px4io.cpp +++ b/src/drivers/px4io/px4io.cpp @@ -502,8 +502,7 @@ PX4IO::init() io_reg_modify(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_ARMING, PX4IO_P_SETUP_ARMING_ARM_OK | PX4IO_P_SETUP_ARMING_INAIR_RESTART_OK | - PX4IO_P_SETUP_ARMING_MANUAL_OVERRIDE_OK | - PX4IO_P_SETUP_ARMING_VECTOR_FLIGHT_OK, 0); + PX4IO_P_SETUP_ARMING_MANUAL_OVERRIDE_OK, 0); /* publish RC config to IO */ ret = io_set_rc_config(); @@ -707,11 +706,6 @@ PX4IO::io_set_arming_state() } else { clear |= PX4IO_P_SETUP_ARMING_ARM_OK; } - if (vstatus.flag_vector_flight_mode_ok) { - set |= PX4IO_P_SETUP_ARMING_VECTOR_FLIGHT_OK; - } else { - clear |= PX4IO_P_SETUP_ARMING_VECTOR_FLIGHT_OK; - } if (vstatus.flag_external_manual_override_ok) { set |= PX4IO_P_SETUP_ARMING_MANUAL_OVERRIDE_OK; } else { @@ -1309,11 +1303,10 @@ PX4IO::print_status() /* setup and state */ printf("features 0x%04x\n", io_reg_get(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_FEATURES)); uint16_t arming = io_reg_get(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_ARMING); - printf("arming 0x%04x%s%s%s%s\n", + printf("arming 0x%04x%s%s%s\n", arming, ((arming & PX4IO_P_SETUP_ARMING_ARM_OK) ? " ARM_OK" : ""), ((arming & PX4IO_P_SETUP_ARMING_MANUAL_OVERRIDE_OK) ? " MANUAL_OVERRIDE_OK" : ""), - ((arming & PX4IO_P_SETUP_ARMING_VECTOR_FLIGHT_OK) ? " VECTOR_FLIGHT_OK" : ""), ((arming & PX4IO_P_SETUP_ARMING_INAIR_RESTART_OK) ? " INAIR_RESTART_OK" : "")); printf("rates 0x%04x default %u alt %u relays 0x%04x\n", io_reg_get(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_PWM_RATES), diff --git a/src/modules/px4iofirmware/protocol.h b/src/modules/px4iofirmware/protocol.h index b80551a077..d015fb629a 100644 --- a/src/modules/px4iofirmware/protocol.h +++ b/src/modules/px4iofirmware/protocol.h @@ -147,7 +147,6 @@ #define PX4IO_P_SETUP_ARMING 1 /* arming controls */ #define PX4IO_P_SETUP_ARMING_ARM_OK (1 << 0) /* OK to arm */ #define PX4IO_P_SETUP_ARMING_MANUAL_OVERRIDE_OK (1 << 2) /* OK to switch to manual override via override RC channel */ -#define PX4IO_P_SETUP_ARMING_VECTOR_FLIGHT_OK (1 << 3) /* OK to perform position / vector control (= position lock) */ #define PX4IO_P_SETUP_ARMING_INAIR_RESTART_OK (1 << 4) /* OK to try in-air restart */ #define PX4IO_P_SETUP_PWM_RATES 2 /* bitmask, 0 = low rate, 1 = high rate */ diff --git a/src/modules/px4iofirmware/safety.c b/src/modules/px4iofirmware/safety.c index 5495d5ae12..a2880d2efb 100644 --- a/src/modules/px4iofirmware/safety.c +++ b/src/modules/px4iofirmware/safety.c @@ -56,11 +56,10 @@ static unsigned counter = 0; /* * Define the various LED flash sequences for each system state. */ -#define LED_PATTERN_SAFE 0xffff /**< always on */ -#define LED_PATTERN_VECTOR_FLIGHT_MODE_OK 0xFFFE /**< always on with short break */ -#define LED_PATTERN_FMU_ARMED 0x4444 /**< slow blinking */ +#define LED_PATTERN_SAFE 0x000f /**< always on */ +#define LED_PATTERN_FMU_ARMED 0x5555 /**< slow blinking */ #define LED_PATTERN_IO_ARMED 0x5555 /**< fast blinking */ -#define LED_PATTERN_IO_FMU_ARMED 0x5050 /**< long off then double blink */ +#define LED_PATTERN_IO_FMU_ARMED 0xffff /**< long off then double blink */ static unsigned blink_counter = 0; @@ -151,8 +150,6 @@ safety_check_button(void *arg) } else if (r_setup_arming & PX4IO_P_SETUP_ARMING_ARM_OK) { pattern = LED_PATTERN_FMU_ARMED; - } else if (r_setup_arming & PX4IO_P_SETUP_ARMING_VECTOR_FLIGHT_OK) { - pattern = LED_PATTERN_VECTOR_FLIGHT_MODE_OK; } /* Turn the LED on if we have a 1 at the current bit position */ From d6cb588c3c078d3858d8c7bcb78ca72373aa73d8 Mon Sep 17 00:00:00 2001 From: px4dev Date: Thu, 9 May 2013 10:02:56 -0700 Subject: [PATCH 66/84] fix capitalisation of include file name Marko Pagott --- src/drivers/md25/md25_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/drivers/md25/md25_main.cpp b/src/drivers/md25/md25_main.cpp index 85aaab7f6d..740dd0b287 100644 --- a/src/drivers/md25/md25_main.cpp +++ b/src/drivers/md25/md25_main.cpp @@ -55,7 +55,7 @@ #include #include -#include "MD25.hpp" +#include "md25.hpp" static bool thread_should_exit = false; /**< Deamon exit flag */ static bool thread_running = false; /**< Deamon status flag */ From b7a9e0778359b9da7eb27e1292557e7a0f9a7278 Mon Sep 17 00:00:00 2001 From: Lorenz Meier Date: Thu, 9 May 2013 19:03:24 +0200 Subject: [PATCH 67/84] Hotfix: Wrong capitalization on header file name --- src/drivers/md25/md25_main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/drivers/md25/md25_main.cpp b/src/drivers/md25/md25_main.cpp index 85aaab7f6d..80850e7088 100644 --- a/src/drivers/md25/md25_main.cpp +++ b/src/drivers/md25/md25_main.cpp @@ -1,6 +1,6 @@ /**************************************************************************** * - * Copyright (C) 2013 PX4 Development Team. All rights reserved. + * Copyright (c) 2013 PX4 Development Team. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -55,7 +55,7 @@ #include #include -#include "MD25.hpp" +#include "md25.hpp" static bool thread_should_exit = false; /**< Deamon exit flag */ static bool thread_running = false; /**< Deamon status flag */ From 304ce63f00e72cf8a8162abad295a52a5773265d Mon Sep 17 00:00:00 2001 From: Lorenz Meier Date: Thu, 9 May 2013 19:03:24 +0200 Subject: [PATCH 68/84] Hotfix: Wrong capitalization on header file name --- src/drivers/md25/md25_main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/drivers/md25/md25_main.cpp b/src/drivers/md25/md25_main.cpp index 85aaab7f6d..80850e7088 100644 --- a/src/drivers/md25/md25_main.cpp +++ b/src/drivers/md25/md25_main.cpp @@ -1,6 +1,6 @@ /**************************************************************************** * - * Copyright (C) 2013 PX4 Development Team. All rights reserved. + * Copyright (c) 2013 PX4 Development Team. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -55,7 +55,7 @@ #include #include -#include "MD25.hpp" +#include "md25.hpp" static bool thread_should_exit = false; /**< Deamon exit flag */ static bool thread_running = false; /**< Deamon status flag */ From 196ee8b16fcd42fca04d1fb7e11ec46dd45c8421 Mon Sep 17 00:00:00 2001 From: px4dev Date: Sat, 11 May 2013 11:32:05 -0700 Subject: [PATCH 69/84] Change the way modules are built so that object paths are relative and use vpath for locating sources (so source paths are also shorter). Add some basic documentation for the build system files while we're at it. --- makefiles/README.txt | 71 +++++++++++++++++++++++++++++ makefiles/firmware.mk | 7 ++- makefiles/module.mk | 51 +++++++++++++-------- src/modules/mathlib/CMSIS/module.mk | 5 +- 4 files changed, 110 insertions(+), 24 deletions(-) create mode 100644 makefiles/README.txt diff --git a/makefiles/README.txt b/makefiles/README.txt new file mode 100644 index 0000000000..8b84e4c40d --- /dev/null +++ b/makefiles/README.txt @@ -0,0 +1,71 @@ +PX4 Build System +================ + +The files in this directory implement the PX4 runtime firmware build system +and configuration for the standard PX4 boards and software, in conjunction +with Makefile in the parent directory. + +../Makefile + + Top-level makefile for the PX4 build system. This makefile supports + building NuttX archives, as well as supervising the building of all + of the defined PX4 firmware configurations. + + Try 'make help' in the parent directory for documentation. + +firmware.mk + + Manages the build for one specific firmware configuration. + See the comments at the top of this file for detailed documentation. + + Builds modules, builtin command lists and the ROMFS (if configured). + + This is the makefile directly used by external build systems; it can + be configured to compile modules both inside and outside the PX4 + source tree. When used in this mode, at least BOARD, MODULES and + CONFIG_FILE must be set. + +module.mk + + Called by firmware.mk to build individual modules. + See the comments at the top of this file for detailed documentation. + + Not normally used other than by firmware.mk. + +nuttx.mk + + Called by ../Makefile to build or download the NuttX archives. + +upload.mk + + Called by ../Makefile to upload files to a target board. Can be used + by external build systems as well. + +setup.mk + + Provides common path and tool definitions. Implements host system-specific + compatibility hacks. + +board_.mk + + Board-specific configuration for . Typically sets CONFIG_ARCH + and then includes the toolchain definition for the board. + +config__.mk + + Parameters for a specific configuration on a specific board. + The board name is derived from the filename. Sets MODULES to select + source modules to be included in the configuration, may also set + ROMFS_ROOT to build a ROMFS and BUILTIN_COMMANDS to include non-module + commands (e.g. from NuttX) + +toolchain_.mk + + Provides macros used to compile and link source files. + Accepts EXTRADEFINES to add additional pre-processor symbol definitions, + EXTRACFLAGS, EXTRACXXFLAGS, EXTRAAFLAGS and EXTRALDFLAGS to pass + additional flags to the C compiler, C++ compiler, assembler and linker + respectively. + + Defines the COMPILE, COMPILEXX, ASSEMBLE, PRELINK, ARCHIVE and LINK + macros that are used elsewhere in the build system. diff --git a/makefiles/firmware.mk b/makefiles/firmware.mk index b63aa28d73..e6a45a4e8a 100644 --- a/makefiles/firmware.mk +++ b/makefiles/firmware.mk @@ -223,12 +223,15 @@ MODULE_OBJS := $(foreach path,$(dir $(MODULE_MKFILES)),$(WORK_DIR)$(path)module .PHONY: $(MODULE_OBJS) $(MODULE_OBJS): relpath = $(patsubst $(WORK_DIR)%,%,$@) $(MODULE_OBJS): mkfile = $(patsubst %module.pre.o,%module.mk,$(relpath)) +$(MODULE_OBJS): workdir = $(@D) $(MODULE_OBJS): $(GLOBAL_DEPS) $(NUTTX_CONFIG_HEADER) + $(Q) $(MKDIR) -p $(workdir) $(Q) $(MAKE) -r -f $(PX4_MK_DIR)module.mk \ - MODULE_WORK_DIR=$(dir $@) \ + -C $(workdir) \ + MODULE_WORK_DIR=$(workdir) \ MODULE_OBJ=$@ \ MODULE_MK=$(mkfile) \ - MODULE_NAME=$(lastword $(subst /, ,$(@D))) \ + MODULE_NAME=$(lastword $(subst /, ,$(workdir))) \ module # make a list of phony clean targets for modules diff --git a/makefiles/module.mk b/makefiles/module.mk index 0fe6f0ffec..db6f4e15ec 100644 --- a/makefiles/module.mk +++ b/makefiles/module.mk @@ -39,6 +39,10 @@ # symbols, as the global namespace is shared between all modules. Normally an # module will just export one or more _main functions. # +# IMPORTANT NOTE: +# +# This makefile assumes it is being invoked in the module's output directory. +# # # Variables that can be set by the module's module.mk: @@ -179,26 +183,30 @@ CXXFLAGS += -fvisibility=$(DEFAULT_VISIBILITY) -include $(PX4_INCLUDE_DIR)visibi # module: $(MODULE_OBJ) $(MODULE_COMMAND_FILES) +## +## Locate sources (allows relative source paths in module.mk) +## +#define SRC_SEARCH +# $(abspath $(firstword $(wildcard $1) $(wildcard $(MODULE_SRC)/$1) MISSING_$1)) +#endef # -# Locate sources (allows relative source paths in module.mk) +#ABS_SRCS ?= $(foreach src,$(SRCS),$(call SRC_SEARCH,$(src))) +#MISSING_SRCS := $(subst MISSING_,,$(filter MISSING_%,$(ABS_SRCS))) +#ifneq ($(MISSING_SRCS),) +#$(error $(MODULE_MK): missing in SRCS: $(MISSING_SRCS)) +#endif +#ifeq ($(ABS_SRCS),) +#$(error $(MODULE_MK): nothing to compile in SRCS) +#endif # -define SRC_SEARCH - $(abspath $(firstword $(wildcard $1) $(wildcard $(MODULE_SRC)/$1) MISSING_$1)) -endef +## +## Object files we will generate from sources +## +#OBJS := $(foreach src,$(ABS_SRCS),$(MODULE_WORK_DIR)$(src).o) -ABS_SRCS ?= $(foreach src,$(SRCS),$(call SRC_SEARCH,$(src))) -MISSING_SRCS := $(subst MISSING_,,$(filter MISSING_%,$(ABS_SRCS))) -ifneq ($(MISSING_SRCS),) -$(error $(MODULE_MK): missing in SRCS: $(MISSING_SRCS)) -endif -ifeq ($(ABS_SRCS),) -$(error $(MODULE_MK): nothing to compile in SRCS) -endif - -# -# Object files we will generate from sources -# -OBJS := $(foreach src,$(ABS_SRCS),$(MODULE_WORK_DIR)$(src).o) +OBJS = $(addsuffix .o,$(SRCS)) +$(info SRCS $(SRCS)) +$(info OBJS $(OBJS)) # # SRCS -> OBJS rules @@ -206,13 +214,16 @@ OBJS := $(foreach src,$(ABS_SRCS),$(MODULE_WORK_DIR)$(src).o) $(OBJS): $(GLOBAL_DEPS) -$(filter %.c.o,$(OBJS)): $(MODULE_WORK_DIR)%.c.o: %.c $(GLOBAL_DEPS) +vpath %.c $(MODULE_SRC) +$(filter %.c.o,$(OBJS)): %.c.o: %.c $(GLOBAL_DEPS) $(call COMPILE,$<,$@) -$(filter %.cpp.o,$(OBJS)): $(MODULE_WORK_DIR)%.cpp.o: %.cpp $(GLOBAL_DEPS) +vpath %.cpp $(MODULE_SRC) +$(filter %.cpp.o,$(OBJS)): %.cpp.o: %.cpp $(GLOBAL_DEPS) $(call COMPILEXX,$<,$@) -$(filter %.S.o,$(OBJS)): $(MODULE_WORK_DIR)%.S.o: %.S $(GLOBAL_DEPS) +vpath %.S $(MODULE_SRC) +$(filter %.S.o,$(OBJS)): %.S.o: %.S $(GLOBAL_DEPS) $(call ASSEMBLE,$<,$@) # diff --git a/src/modules/mathlib/CMSIS/module.mk b/src/modules/mathlib/CMSIS/module.mk index c676f32618..ba45b159ea 100644 --- a/src/modules/mathlib/CMSIS/module.mk +++ b/src/modules/mathlib/CMSIS/module.mk @@ -38,8 +38,9 @@ # # Find sources # -DSPLIB_SRCDIR := $(PX4_MODULE_SRC)/modules/mathlib/CMSIS -ABS_SRCS := $(wildcard $(DSPLIB_SRCDIR)/DSP_Lib/Source/*/*.c) +DSPLIB_SRCDIR := $(dir $(lastword $(MAKEFILE_LIST))) +SRCLIST := $(wildcard $(DSPLIB_SRCDIR)DSP_Lib/Source/*/*.c) +SRCS := $(patsubst $(DSPLIB_SRCDIR)%,%,$(SRCLIST)) zork.c INCLUDE_DIRS += $(DSPLIB_SRCDIR)/Include \ $(DSPLIB_SRCDIR)/Device/ARM/ARMCM4/Include \ From 555d42e0cd2724225391bede58629d3bcea175db Mon Sep 17 00:00:00 2001 From: px4dev Date: Sat, 11 May 2013 16:46:52 -0700 Subject: [PATCH 70/84] Oops, left in some test code. --- src/modules/mathlib/CMSIS/module.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/mathlib/CMSIS/module.mk b/src/modules/mathlib/CMSIS/module.mk index ba45b159ea..5e1abe642f 100644 --- a/src/modules/mathlib/CMSIS/module.mk +++ b/src/modules/mathlib/CMSIS/module.mk @@ -40,7 +40,7 @@ # DSPLIB_SRCDIR := $(dir $(lastword $(MAKEFILE_LIST))) SRCLIST := $(wildcard $(DSPLIB_SRCDIR)DSP_Lib/Source/*/*.c) -SRCS := $(patsubst $(DSPLIB_SRCDIR)%,%,$(SRCLIST)) zork.c +SRCS := $(patsubst $(DSPLIB_SRCDIR)%,%,$(SRCLIST)) INCLUDE_DIRS += $(DSPLIB_SRCDIR)/Include \ $(DSPLIB_SRCDIR)/Device/ARM/ARMCM4/Include \ From 0c43da3b6424dbc877c464b6898f18fe650c703f Mon Sep 17 00:00:00 2001 From: Lorenz Meier Date: Sun, 12 May 2013 13:11:12 +0200 Subject: [PATCH 71/84] Tested with PX4FMU and PX4IO with GPS and arming --- src/modules/commander/commander.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/commander/commander.c b/src/modules/commander/commander.c index cd2ef8137e..aab8f3e04d 100644 --- a/src/modules/commander/commander.c +++ b/src/modules/commander/commander.c @@ -1519,7 +1519,7 @@ int commander_thread_main(int argc, char *argv[]) /* GPS lock */ led_on(LED_BLUE); - } else if (counter % (1000000 / COMMANDER_MONITORING_INTERVAL) == 0) { + } else if ((counter + 4) % (1000000 / COMMANDER_MONITORING_INTERVAL) == 0) { /* no GPS lock, but GPS module is aquiring lock */ led_toggle(LED_BLUE); } @@ -1535,8 +1535,8 @@ int commander_thread_main(int argc, char *argv[]) led_toggle(LED_BLUE); } else if (bat_remain < 0.3f && (low_voltage_counter > LOW_VOLTAGE_BATTERY_COUNTER_LIMIT)) { - /* toggle error (red) at 5 Hz on low battery or error */ - led_toggle(LED_BLUE); + /* toggle arming (red) at 5 Hz on low battery or error */ + led_toggle(LED_AMBER); } else { // /* Constant error indication in standby mode without GPS */ From 0ee738e9c91c49739798ac5ff8dd4a12c06bb82f Mon Sep 17 00:00:00 2001 From: px4dev Date: Sun, 12 May 2013 10:51:25 -0700 Subject: [PATCH 72/84] Fix ROMFS dependency scan, add a warning if ROMFS_ROOT appears to be empty. --- makefiles/firmware.mk | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/makefiles/firmware.mk b/makefiles/firmware.mk index e6a45a4e8a..6fa0ae3eb0 100644 --- a/makefiles/firmware.mk +++ b/makefiles/firmware.mk @@ -269,13 +269,17 @@ endif # # Add dependencies on anything in the ROMFS root -ROMFS_DEPS += $(wildcard \ - (ROMFS_ROOT)/* \ - (ROMFS_ROOT)/*/* \ - (ROMFS_ROOT)/*/*/* \ - (ROMFS_ROOT)/*/*/*/* \ - (ROMFS_ROOT)/*/*/*/*/* \ - (ROMFS_ROOT)/*/*/*/*/*/*) +ROMFS_FILES += $(wildcard \ + $(ROMFS_ROOT)/* \ + $(ROMFS_ROOT)/*/* \ + $(ROMFS_ROOT)/*/*/* \ + $(ROMFS_ROOT)/*/*/*/* \ + $(ROMFS_ROOT)/*/*/*/*/* \ + $(ROMFS_ROOT)/*/*/*/*/*/*) +ifeq ($(ROMFS_FILES),) +$(error ROMFS_ROOT $(ROMFS_ROOT) specifies a directory containing no files) +endif +ROMFS_DEPS += $(ROMFS_FILES) ROMFS_IMG = $(WORK_DIR)romfs.img ROMFS_CSRC = $(ROMFS_IMG:.img=.c) ROMFS_OBJ = $(ROMFS_CSRC:.c=.o) From 79f9b61aff0570d1ab98dc5a4c7e6a71eec5009b Mon Sep 17 00:00:00 2001 From: Lorenz Meier Date: Sun, 12 May 2013 20:05:20 +0200 Subject: [PATCH 73/84] Fixed led patterns to be up to the latest specs --- src/drivers/px4io/px4io.cpp | 32 ++++++++++++-------- src/modules/commander/state_machine_helper.c | 5 +++ src/modules/px4iofirmware/protocol.h | 3 +- src/modules/px4iofirmware/safety.c | 26 ++++++++-------- src/modules/uORB/topics/actuator_controls.h | 1 + 5 files changed, 41 insertions(+), 26 deletions(-) diff --git a/src/drivers/px4io/px4io.cpp b/src/drivers/px4io/px4io.cpp index e69fbebf74..3006cf885b 100644 --- a/src/drivers/px4io/px4io.cpp +++ b/src/drivers/px4io/px4io.cpp @@ -416,7 +416,7 @@ PX4IO::init() * already armed, and has been configured for in-air restart */ if ((reg & PX4IO_P_SETUP_ARMING_INAIR_RESTART_OK) && - (reg & PX4IO_P_SETUP_ARMING_ARM_OK)) { + (reg & PX4IO_P_SETUP_ARMING_FMU_ARMED)) { mavlink_log_emergency(_mavlink_fd, "[IO] RECOVERING FROM FMU IN-AIR RESTART"); @@ -500,7 +500,7 @@ PX4IO::init() /* dis-arm IO before touching anything */ io_reg_modify(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_ARMING, - PX4IO_P_SETUP_ARMING_ARM_OK | + PX4IO_P_SETUP_ARMING_FMU_ARMED | PX4IO_P_SETUP_ARMING_INAIR_RESTART_OK | PX4IO_P_SETUP_ARMING_MANUAL_OVERRIDE_OK, 0); @@ -701,11 +701,18 @@ PX4IO::io_set_arming_state() uint16_t set = 0; uint16_t clear = 0; - if (armed.armed) { - set |= PX4IO_P_SETUP_ARMING_ARM_OK; + if (armed.armed && !armed.lockdown) { + set |= PX4IO_P_SETUP_ARMING_FMU_ARMED; } else { - clear |= PX4IO_P_SETUP_ARMING_ARM_OK; + clear |= PX4IO_P_SETUP_ARMING_FMU_ARMED; } + + if (armed.ready_to_arm) { + set |= PX4IO_P_SETUP_ARMING_IO_ARM_OK; + } else { + clear |= PX4IO_P_SETUP_ARMING_IO_ARM_OK; + } + if (vstatus.flag_external_manual_override_ok) { set |= PX4IO_P_SETUP_ARMING_MANUAL_OVERRIDE_OK; } else { @@ -1271,9 +1278,9 @@ PX4IO::print_status() io_reg_get(PX4IO_PAGE_STATUS, PX4IO_P_STATUS_IBATT), io_reg_get(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_VBATT_SCALE)); printf("amp_per_volt %.3f amp_offset %.3f mAhDischarged %.3f\n", - _battery_amp_per_volt, - _battery_amp_bias, - _battery_mamphour_total); + (double)_battery_amp_per_volt, + (double)_battery_amp_bias, + (double)_battery_mamphour_total); printf("actuators"); for (unsigned i = 0; i < _max_actuators; i++) printf(" %u", io_reg_get(PX4IO_PAGE_ACTUATORS, i)); @@ -1303,9 +1310,10 @@ PX4IO::print_status() /* setup and state */ printf("features 0x%04x\n", io_reg_get(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_FEATURES)); uint16_t arming = io_reg_get(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_ARMING); - printf("arming 0x%04x%s%s%s\n", + printf("arming 0x%04x%s%s%s%s\n", arming, - ((arming & PX4IO_P_SETUP_ARMING_ARM_OK) ? " ARM_OK" : ""), + ((arming & PX4IO_P_SETUP_ARMING_FMU_ARMED) ? " FMU_ARMED" : ""), + ((arming & PX4IO_P_SETUP_ARMING_IO_ARM_OK) ? " IO_ARM_OK" : ""), ((arming & PX4IO_P_SETUP_ARMING_MANUAL_OVERRIDE_OK) ? " MANUAL_OVERRIDE_OK" : ""), ((arming & PX4IO_P_SETUP_ARMING_INAIR_RESTART_OK) ? " INAIR_RESTART_OK" : "")); printf("rates 0x%04x default %u alt %u relays 0x%04x\n", @@ -1347,12 +1355,12 @@ PX4IO::ioctl(file *filep, int cmd, unsigned long arg) switch (cmd) { case PWM_SERVO_ARM: /* set the 'armed' bit */ - ret = io_reg_modify(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_ARMING, 0, PX4IO_P_SETUP_ARMING_ARM_OK); + ret = io_reg_modify(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_ARMING, 0, PX4IO_P_SETUP_ARMING_FMU_ARMED); break; case PWM_SERVO_DISARM: /* clear the 'armed' bit */ - ret = io_reg_modify(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_ARMING, PX4IO_P_SETUP_ARMING_ARM_OK, 0); + ret = io_reg_modify(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_ARMING, PX4IO_P_SETUP_ARMING_FMU_ARMED, 0); break; case PWM_SERVO_SET_UPDATE_RATE: diff --git a/src/modules/commander/state_machine_helper.c b/src/modules/commander/state_machine_helper.c index bea388a101..ab728c7bbb 100644 --- a/src/modules/commander/state_machine_helper.c +++ b/src/modules/commander/state_machine_helper.c @@ -249,6 +249,11 @@ void publish_armed_status(const struct vehicle_status_s *current_status) { struct actuator_armed_s armed; armed.armed = current_status->flag_system_armed; + + /* XXX allow arming by external components on multicopters only if not yet armed by RC */ + /* XXX allow arming only if core sensors are ok */ + armed.ready_to_arm = true; + /* lock down actuators if required, only in HIL */ armed.lockdown = (current_status->flag_hil_enabled) ? true : false; orb_advert_t armed_pub = orb_advertise(ORB_ID(actuator_armed), &armed); diff --git a/src/modules/px4iofirmware/protocol.h b/src/modules/px4iofirmware/protocol.h index d015fb629a..e575bd8412 100644 --- a/src/modules/px4iofirmware/protocol.h +++ b/src/modules/px4iofirmware/protocol.h @@ -145,7 +145,8 @@ #define PX4IO_P_SETUP_FEATURES 0 #define PX4IO_P_SETUP_ARMING 1 /* arming controls */ -#define PX4IO_P_SETUP_ARMING_ARM_OK (1 << 0) /* OK to arm */ +#define PX4IO_P_SETUP_ARMING_IO_ARM_OK (1 << 0) /* OK to arm the IO side */ +#define PX4IO_P_SETUP_ARMING_FMU_ARMED (1 << 1) /* FMU is already armed */ #define PX4IO_P_SETUP_ARMING_MANUAL_OVERRIDE_OK (1 << 2) /* OK to switch to manual override via override RC channel */ #define PX4IO_P_SETUP_ARMING_INAIR_RESTART_OK (1 << 4) /* OK to try in-air restart */ diff --git a/src/modules/px4iofirmware/safety.c b/src/modules/px4iofirmware/safety.c index a2880d2efb..f6cd5fb450 100644 --- a/src/modules/px4iofirmware/safety.c +++ b/src/modules/px4iofirmware/safety.c @@ -1,6 +1,6 @@ /**************************************************************************** * - * Copyright (C) 2012 PX4 Development Team. All rights reserved. + * Copyright (c) 2012, 2013 PX4 Development Team. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,7 +32,8 @@ ****************************************************************************/ /** - * @file Safety button logic. + * @file safety.c + * Safety button logic. */ #include @@ -56,10 +57,10 @@ static unsigned counter = 0; /* * Define the various LED flash sequences for each system state. */ -#define LED_PATTERN_SAFE 0x000f /**< always on */ -#define LED_PATTERN_FMU_ARMED 0x5555 /**< slow blinking */ -#define LED_PATTERN_IO_ARMED 0x5555 /**< fast blinking */ -#define LED_PATTERN_IO_FMU_ARMED 0xffff /**< long off then double blink */ +#define LED_PATTERN_FMU_OK_TO_ARM 0x0003 /**< slow blinking */ +#define LED_PATTERN_FMU_REFUSE_TO_ARM 0x5555 /**< fast blinking */ +#define LED_PATTERN_IO_ARMED 0x5050 /**< long off, then double blink */ +#define LED_PATTERN_IO_FMU_ARMED 0xffff /**< constantly on */ static unsigned blink_counter = 0; @@ -108,7 +109,8 @@ safety_check_button(void *arg) * state machine, keep ARM_COUNTER_THRESHOLD the same * length in all cases of the if/else struct below. */ - if (safety_button_pressed && !(r_status_flags & PX4IO_P_STATUS_FLAGS_ARMED)) { + if (safety_button_pressed && !(r_status_flags & PX4IO_P_STATUS_FLAGS_ARMED) && + (r_setup_arming & PX4IO_P_SETUP_ARMING_IO_ARM_OK)) { if (counter < ARM_COUNTER_THRESHOLD) { counter++; @@ -119,8 +121,6 @@ safety_check_button(void *arg) counter++; } - /* Disarm quickly */ - } else if (safety_button_pressed && (r_status_flags & PX4IO_P_STATUS_FLAGS_ARMED)) { if (counter < ARM_COUNTER_THRESHOLD) { @@ -137,18 +137,18 @@ safety_check_button(void *arg) } /* Select the appropriate LED flash pattern depending on the current IO/FMU arm state */ - uint16_t pattern = LED_PATTERN_SAFE; + uint16_t pattern = LED_PATTERN_FMU_REFUSE_TO_ARM; if (r_status_flags & PX4IO_P_STATUS_FLAGS_ARMED) { - if (r_setup_arming & PX4IO_P_SETUP_ARMING_ARM_OK) { + if (r_setup_arming & PX4IO_P_SETUP_ARMING_FMU_ARMED) { pattern = LED_PATTERN_IO_FMU_ARMED; } else { pattern = LED_PATTERN_IO_ARMED; } - } else if (r_setup_arming & PX4IO_P_SETUP_ARMING_ARM_OK) { - pattern = LED_PATTERN_FMU_ARMED; + } else if (r_setup_arming & PX4IO_P_SETUP_ARMING_IO_ARM_OK) { + pattern = LED_PATTERN_FMU_OK_TO_ARM; } diff --git a/src/modules/uORB/topics/actuator_controls.h b/src/modules/uORB/topics/actuator_controls.h index 0b50a29ac8..b7c4196c0a 100644 --- a/src/modules/uORB/topics/actuator_controls.h +++ b/src/modules/uORB/topics/actuator_controls.h @@ -69,6 +69,7 @@ ORB_DECLARE(actuator_controls_3); /** global 'actuator output is live' control. */ struct actuator_armed_s { bool armed; /**< Set to true if system is armed */ + bool ready_to_arm; /**< Set to true if system is ready to be armed */ bool lockdown; /**< Set to true if actuators are forced to being disabled (due to emergency or HIL) */ }; From 6ea204c8136a3e4c81e2e542e56a865c57f381e7 Mon Sep 17 00:00:00 2001 From: Lorenz Meier Date: Sun, 12 May 2013 20:08:09 +0200 Subject: [PATCH 74/84] Added fixed wing controller example --- makefiles/config_px4fmu_default.mk | 4 + src/examples/fixedwing_control/main.c | 474 +++++++++++++++++++++++ src/examples/fixedwing_control/module.mk | 41 ++ src/examples/fixedwing_control/params.c | 77 ++++ src/examples/fixedwing_control/params.h | 65 ++++ 5 files changed, 661 insertions(+) create mode 100644 src/examples/fixedwing_control/main.c create mode 100644 src/examples/fixedwing_control/module.mk create mode 100644 src/examples/fixedwing_control/params.c create mode 100644 src/examples/fixedwing_control/params.h diff --git a/makefiles/config_px4fmu_default.mk b/makefiles/config_px4fmu_default.mk index 00d402c4a9..27bf0f973b 100644 --- a/makefiles/config_px4fmu_default.mk +++ b/makefiles/config_px4fmu_default.mk @@ -105,6 +105,10 @@ MODULES += modules/uORB # https://pixhawk.ethz.ch/px4/dev/debug_values #MODULES += examples/px4_mavlink_debug +# Tutorial code from +# https://pixhawk.ethz.ch/px4/dev/example_fixedwing_control +MODULES += examples/fixedwing_control + # # Transitional support - add commands from the NuttX export archive. # diff --git a/src/examples/fixedwing_control/main.c b/src/examples/fixedwing_control/main.c new file mode 100644 index 0000000000..1753070e2f --- /dev/null +++ b/src/examples/fixedwing_control/main.c @@ -0,0 +1,474 @@ +/**************************************************************************** + * + * Copyright (c) 2013 PX4 Development Team. All rights reserved. + * Author: Lorenz Meier + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ +/** + * @file main.c + * Implementation of a fixed wing attitude controller. This file is a complete + * fixed wing controller flying manual attitude control or auto waypoint control. + * There is no need to touch any other system components to extend / modify the + * complete control architecture. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* process-specific header files */ +#include "params.h" + +/* Prototypes */ +/** + * Daemon management function. + */ +__EXPORT int ex_fixedwing_control_main(int argc, char *argv[]); + +/** + * Mainloop of daemon. + */ +int fixedwing_control_thread_main(int argc, char *argv[]); + +/** + * Print the correct usage. + */ +static void usage(const char *reason); + +void control_attitude(const struct vehicle_attitude_setpoint_s *att_sp, const struct vehicle_attitude_s *att, + float speed_body[], float gyro[], struct vehicle_rates_setpoint_s *rates_sp, + struct actuator_controls_s *actuators); + +void control_heading(const struct vehicle_global_position_s *pos, const struct vehicle_global_position_setpoint_s *sp, + const struct vehicle_attitude_s *att, struct vehicle_attitude_setpoint_s *att_sp); + +/* Variables */ +static bool thread_should_exit = false; /**< Daemon exit flag */ +static bool thread_running = false; /**< Daemon status flag */ +static int deamon_task; /**< Handle of deamon task / thread */ +static struct params p; +static struct param_handles ph; + +void control_attitude(const struct vehicle_attitude_setpoint_s *att_sp, const struct vehicle_attitude_s *att, + float speed_body[], float gyro[], struct vehicle_rates_setpoint_s *rates_sp, + struct actuator_controls_s *actuators) +{ + + /* + * The PX4 architecture provides a mixer outside of the controller. + * The mixer is fed with a default vector of actuator controls, representing + * moments applied to the vehicle frame. This vector + * is structured as: + * + * Control Group 0 (attitude): + * + * 0 - roll (-1..+1) + * 1 - pitch (-1..+1) + * 2 - yaw (-1..+1) + * 3 - thrust ( 0..+1) + * 4 - flaps (-1..+1) + * ... + * + * Control Group 1 (payloads / special): + * + * ... + */ + + /* + * Calculate roll error and apply P gain + */ + float roll_err = att->roll - att_sp->roll_body; + actuators->control[0] = roll_err * p.roll_p; + + /* + * Calculate pitch error and apply P gain + */ + float pitch_err = att->pitch - att_sp->pitch_body; + actuators->control[1] = pitch_err * p.pitch_p; +} + +void control_heading(const struct vehicle_global_position_s *pos, const struct vehicle_global_position_setpoint_s *sp, + const struct vehicle_attitude_s *att, struct vehicle_attitude_setpoint_s *att_sp) +{ + + /* + * Calculate heading error of current position to desired position + */ + + /* PX4 uses 1e7 scaled integers to represent global coordinates for max resolution */ + float bearing = get_bearing_to_next_waypoint(pos->lat/1e7d, pos->lon/1e7d, sp->lat/1e7d, sp->lon/1e7d); + + /* calculate heading error */ + float yaw_err = att->yaw - bearing; + /* apply control gain */ + att_sp->roll_body = yaw_err * p.hdng_p; +} + +/* Main Thread */ +int fixedwing_control_thread_main(int argc, char *argv[]) +{ + /* read arguments */ + bool verbose = false; + + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0) { + verbose = true; + } + } + + /* welcome user (warnx prints a line, including an appended\n, with variable arguments */ + warnx("[example fixedwing control] started"); + + /* initialize parameters, first the handles, then the values */ + parameters_init(&ph); + parameters_update(&ph, &p); + + /* declare and safely initialize all structs to zero */ + struct vehicle_attitude_s att; + memset(&att, 0, sizeof(att)); + struct vehicle_attitude_setpoint_s att_sp; + memset(&att_sp, 0, sizeof(att_sp)); + struct vehicle_rates_setpoint_s rates_sp; + memset(&rates_sp, 0, sizeof(rates_sp)); + struct vehicle_global_position_s global_pos; + memset(&global_pos, 0, sizeof(global_pos)); + struct manual_control_setpoint_s manual_sp; + memset(&manual_sp, 0, sizeof(manual_sp)); + struct vehicle_status_s vstatus; + memset(&vstatus, 0, sizeof(vstatus)); + struct vehicle_global_position_setpoint_s global_sp; + memset(&global_sp, 0, sizeof(global_sp)); + + /* output structs */ + struct actuator_controls_s actuators; + memset(&actuators, 0, sizeof(actuators)); + + + /* publish actuator controls */ + for (unsigned i = 0; i < NUM_ACTUATOR_CONTROLS; i++) { + actuators.control[i] = 0.0f; + } + + orb_advert_t actuator_pub = orb_advertise(ORB_ID_VEHICLE_ATTITUDE_CONTROLS, &actuators); + orb_advert_t rates_pub = orb_advertise(ORB_ID(vehicle_rates_setpoint), &rates_sp); + + /* subscribe */ + int att_sub = orb_subscribe(ORB_ID(vehicle_attitude)); + int att_sp_sub = orb_subscribe(ORB_ID(vehicle_attitude_setpoint)); + int global_pos_sub = orb_subscribe(ORB_ID(vehicle_global_position)); + int manual_sp_sub = orb_subscribe(ORB_ID(manual_control_setpoint)); + int vstatus_sub = orb_subscribe(ORB_ID(vehicle_status)); + int global_sp_sub = orb_subscribe(ORB_ID(vehicle_global_position_setpoint)); + int param_sub = orb_subscribe(ORB_ID(parameter_update)); + + /* Setup of loop */ + float gyro[3] = {0.0f, 0.0f, 0.0f}; + float speed_body[3] = {0.0f, 0.0f, 0.0f}; + struct pollfd fds[2] = {{ .fd = param_sub, .events = POLLIN }, + { .fd = att_sub, .events = POLLIN }}; + + while (!thread_should_exit) { + + /* + * Wait for a sensor or param update, check for exit condition every 500 ms. + * This means that the execution will block here without consuming any resources, + * but will continue to execute the very moment a new attitude measurement or + * a param update is published. So no latency in contrast to the polling + * design pattern (do not confuse the poll() system call with polling). + * + * This design pattern makes the controller also agnostic of the attitude + * update speed - it runs as fast as the attitude updates with minimal latency. + */ + int ret = poll(fds, 2, 500); + + if (ret < 0) { + /* poll error, this will not really happen in practice */ + warnx("poll error"); + + } else if (ret == 0) { + /* no return value = nothing changed for 500 ms, ignore */ + } else { + + /* only update parameters if they changed */ + if (fds[0].revents & POLLIN) { + /* read from param to clear updated flag (uORB API requirement) */ + struct parameter_update_s update; + orb_copy(ORB_ID(parameter_update), param_sub, &update); + + /* if a param update occured, re-read our parameters */ + parameters_update(&ph, &p); + } + + /* only run controller if attitude changed */ + if (fds[1].revents & POLLIN) { + + + /* Check if there is a new position measurement or position setpoint */ + bool pos_updated; + orb_check(global_pos_sub, &pos_updated); + bool global_sp_updated; + orb_check(global_sp_sub, &global_sp_updated); + + /* get a local copy of attitude */ + orb_copy(ORB_ID(vehicle_attitude), att_sub, &att); + + if (global_sp_updated) + orb_copy(ORB_ID(vehicle_global_position_setpoint), global_sp_sub, &global_sp); + + if (pos_updated) { + orb_copy(ORB_ID(vehicle_global_position), global_pos_sub, &global_pos); + + if (att.R_valid) { + speed_body[0] = att.R[0][0] * global_pos.vx + att.R[0][1] * global_pos.vy + att.R[0][2] * global_pos.vz; + speed_body[1] = att.R[1][0] * global_pos.vx + att.R[1][1] * global_pos.vy + att.R[1][2] * global_pos.vz; + speed_body[2] = att.R[2][0] * global_pos.vx + att.R[2][1] * global_pos.vy + att.R[2][2] * global_pos.vz; + + } else { + speed_body[0] = 0; + speed_body[1] = 0; + speed_body[2] = 0; + + warnx("Did not get a valid R\n"); + } + } + + orb_copy(ORB_ID(manual_control_setpoint), manual_sp_sub, &manual_sp); + orb_copy(ORB_ID(vehicle_status), vstatus_sub, &vstatus); + + gyro[0] = att.rollspeed; + gyro[1] = att.pitchspeed; + gyro[2] = att.yawspeed; + + /* control */ + + if (vstatus.state_machine == SYSTEM_STATE_AUTO || + vstatus.state_machine == SYSTEM_STATE_STABILIZED) { + + /* simple heading control */ + control_heading(&global_pos, &global_sp, &att, &att_sp); + + /* nail pitch and yaw (rudder) to zero. This example only controls roll (index 0) */ + actuators.control[1] = 0.0f; + actuators.control[2] = 0.0f; + + /* simple attitude control */ + control_attitude(&att_sp, &att, speed_body, gyro, &rates_sp, &actuators); + + /* pass through throttle */ + actuators.control[3] = att_sp.thrust; + + /* set flaps to zero */ + actuators.control[4] = 0.0f; + + } else if (vstatus.state_machine == SYSTEM_STATE_MANUAL) { + if (vstatus.manual_control_mode == VEHICLE_MANUAL_CONTROL_MODE_SAS) { + + /* if the RC signal is lost, try to stay level and go slowly back down to ground */ + if (vstatus.rc_signal_lost) { + + /* put plane into loiter */ + att_sp.roll_body = 0.3f; + att_sp.pitch_body = 0.0f; + + /* limit throttle to 60 % of last value if sane */ + if (isfinite(manual_sp.throttle) && + (manual_sp.throttle >= 0.0f) && + (manual_sp.throttle <= 1.0f)) { + att_sp.thrust = 0.6f * manual_sp.throttle; + + } else { + att_sp.thrust = 0.0f; + } + + att_sp.yaw_body = 0; + + // XXX disable yaw control, loiter + + } else { + + att_sp.roll_body = manual_sp.roll; + att_sp.pitch_body = manual_sp.pitch; + att_sp.yaw_body = 0; + att_sp.thrust = manual_sp.throttle; + } + + att_sp.timestamp = hrt_absolute_time(); + + /* attitude control */ + control_attitude(&att_sp, &att, speed_body, gyro, &rates_sp, &actuators); + + /* pass through throttle */ + actuators.control[3] = att_sp.thrust; + + /* pass through flaps */ + if (isfinite(manual_sp.flaps)) { + actuators.control[4] = manual_sp.flaps; + + } else { + actuators.control[4] = 0.0f; + } + + } else if (vstatus.manual_control_mode == VEHICLE_MANUAL_CONTROL_MODE_DIRECT) { + /* directly pass through values */ + actuators.control[0] = manual_sp.roll; + /* positive pitch means negative actuator -> pull up */ + actuators.control[1] = manual_sp.pitch; + actuators.control[2] = manual_sp.yaw; + actuators.control[3] = manual_sp.throttle; + + if (isfinite(manual_sp.flaps)) { + actuators.control[4] = manual_sp.flaps; + + } else { + actuators.control[4] = 0.0f; + } + } + } + + /* publish rates */ + orb_publish(ORB_ID(vehicle_rates_setpoint), rates_pub, &rates_sp); + + /* sanity check and publish actuator outputs */ + if (isfinite(actuators.control[0]) && + isfinite(actuators.control[1]) && + isfinite(actuators.control[2]) && + isfinite(actuators.control[3])) { + orb_publish(ORB_ID_VEHICLE_ATTITUDE_CONTROLS, actuator_pub, &actuators); + } + } + } + } + + printf("[ex_fixedwing_control] exiting, stopping all motors.\n"); + thread_running = false; + + /* kill all outputs */ + for (unsigned i = 0; i < NUM_ACTUATOR_CONTROLS; i++) + actuators.control[i] = 0.0f; + + orb_publish(ORB_ID_VEHICLE_ATTITUDE_CONTROLS, actuator_pub, &actuators); + + fflush(stdout); + + return 0; +} + +/* Startup Functions */ + +static void +usage(const char *reason) +{ + if (reason) + fprintf(stderr, "%s\n", reason); + + fprintf(stderr, "usage: ex_fixedwing_control {start|stop|status}\n\n"); + exit(1); +} + +/** + * The daemon app only briefly exists to start + * the background job. The stack size assigned in the + * Makefile does only apply to this management task. + * + * The actual stack size should be set in the call + * to task_create(). + */ +int ex_fixedwing_control_main(int argc, char *argv[]) +{ + if (argc < 1) + usage("missing command"); + + if (!strcmp(argv[1], "start")) { + + if (thread_running) { + printf("ex_fixedwing_control already running\n"); + /* this is not an error */ + exit(0); + } + + thread_should_exit = false; + deamon_task = task_spawn("ex_fixedwing_control", + SCHED_DEFAULT, + SCHED_PRIORITY_MAX - 20, + 2048, + fixedwing_control_thread_main, + (argv) ? (const char **)&argv[2] : (const char **)NULL); + thread_running = true; + exit(0); + } + + if (!strcmp(argv[1], "stop")) { + thread_should_exit = true; + exit(0); + } + + if (!strcmp(argv[1], "status")) { + if (thread_running) { + printf("\tex_fixedwing_control is running\n"); + + } else { + printf("\tex_fixedwing_control not started\n"); + } + + exit(0); + } + + usage("unrecognized command"); + exit(1); +} + + + diff --git a/src/examples/fixedwing_control/module.mk b/src/examples/fixedwing_control/module.mk new file mode 100644 index 0000000000..d2c48934fc --- /dev/null +++ b/src/examples/fixedwing_control/module.mk @@ -0,0 +1,41 @@ +############################################################################ +# +# Copyright (c) 2012, 2013 PX4 Development Team. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name PX4 nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +# +# Fixedwing Attitude Control Demo / Example Application +# + +MODULE_COMMAND = ex_fixedwing_control + +SRCS = main.c \ + params.c diff --git a/src/examples/fixedwing_control/params.c b/src/examples/fixedwing_control/params.c new file mode 100644 index 0000000000..8042c74f5e --- /dev/null +++ b/src/examples/fixedwing_control/params.c @@ -0,0 +1,77 @@ +/**************************************************************************** + * + * Copyright (c) 2013 PX4 Development Team. All rights reserved. + * Author: Lorenz Meier + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/* + * @file params.c + * + * Parameters for fixedwing demo + */ + +#include "params.h" + +/* controller parameters, use max. 15 characters for param name! */ + +/** + * + */ +PARAM_DEFINE_FLOAT(EXFW_HDNG_P, 0.2f); + +/** + * + */ +PARAM_DEFINE_FLOAT(EXFW_ROLL_P, 0.2f); + +/** + * + */ +PARAM_DEFINE_FLOAT(EXFW_PITCH_P, 0.2f); + +int parameters_init(struct param_handles *h) +{ + /* PID parameters */ + h->hdng_p = param_find("EXFW_HDNG_P"); + h->roll_p = param_find("EXFW_ROLL_P"); + h->pitch_p = param_find("EXFW_PITCH_P"); + + return OK; +} + +int parameters_update(const struct param_handles *h, struct params *p) +{ + param_get(h->hdng_p, &(p->hdng_p)); + param_get(h->roll_p, &(p->roll_p)); + param_get(h->pitch_p, &(p->pitch_p)); + + return OK; +} diff --git a/src/examples/fixedwing_control/params.h b/src/examples/fixedwing_control/params.h new file mode 100644 index 0000000000..4ae8e90ec4 --- /dev/null +++ b/src/examples/fixedwing_control/params.h @@ -0,0 +1,65 @@ +/**************************************************************************** + * + * Copyright (c) 2013 PX4 Development Team. All rights reserved. + * Author: Lorenz Meier + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/* + * @file params.h + * + * Definition of parameters for fixedwing example + */ + +#include + +struct params { + float hdng_p; + float roll_p; + float pitch_p; +}; + +struct param_handles { + param_t hdng_p; + param_t roll_p; + param_t pitch_p; +}; + +/** + * Initialize all parameter handles and values + * + */ +int parameters_init(struct param_handles *h); + +/** + * Update all parameters + * + */ +int parameters_update(const struct param_handles *h, struct params *p); From edb0e01dfd9c38b826ec038ff7b8387e8ce0bd21 Mon Sep 17 00:00:00 2001 From: px4dev Date: Sun, 12 May 2013 14:04:57 -0700 Subject: [PATCH 75/84] HOTFIX: simplify symbol names going into the ROMFS object, hopefully this avoids inconsistent symbol naming on Windows. --- Makefile | 9 +++++++-- makefiles/firmware.mk | 2 +- makefiles/toolchain_gnu-arm-eabi.mk | 15 +++++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 224910e0fc..1d1287b7f7 100644 --- a/Makefile +++ b/Makefile @@ -159,11 +159,11 @@ $(NUTTX_ARCHIVES): $(ARCHIVE_DIR)%.export: $(NUTTX_SRC) $(NUTTX_APPS) .PHONY: clean clean: $(Q) $(RMDIR) $(BUILD_DIR)*.build - $(Q) $(REMOVE) -f $(IMAGE_DIR)*.px4 + $(Q) $(REMOVE) $(IMAGE_DIR)*.px4 .PHONY: distclean distclean: clean - $(Q) $(REMOVE) -f $(ARCHIVE_DIR)*.export + $(Q) $(REMOVE) $(ARCHIVE_DIR)*.export $(Q) make -C $(NUTTX_SRC) -r $(MQUIET) distclean # @@ -196,6 +196,11 @@ help: @echo " distclean" @echo " Remove all compilation products, including NuttX RTOS archives." @echo "" + @echo " upload" + @echo " When exactly one config is being built, add this target to upload the" + @echo " firmware to the board when the build is complete. Not supported for" + @echo " all configurations." + @echo "" @echo " Common options:" @echo " ---------------" @echo "" diff --git a/makefiles/firmware.mk b/makefiles/firmware.mk index 6fa0ae3eb0..7afa3e787d 100644 --- a/makefiles/firmware.mk +++ b/makefiles/firmware.mk @@ -280,7 +280,7 @@ ifeq ($(ROMFS_FILES),) $(error ROMFS_ROOT $(ROMFS_ROOT) specifies a directory containing no files) endif ROMFS_DEPS += $(ROMFS_FILES) -ROMFS_IMG = $(WORK_DIR)romfs.img +ROMFS_IMG = romfs.img ROMFS_CSRC = $(ROMFS_IMG:.img=.c) ROMFS_OBJ = $(ROMFS_CSRC:.c=.o) LIBS += $(ROMFS_OBJ) diff --git a/makefiles/toolchain_gnu-arm-eabi.mk b/makefiles/toolchain_gnu-arm-eabi.mk index 0e651e53c8..874e7154c7 100644 --- a/makefiles/toolchain_gnu-arm-eabi.mk +++ b/makefiles/toolchain_gnu-arm-eabi.mk @@ -254,6 +254,20 @@ endef # - relink the object and insert the binary file # - edit symbol names to suit # +# NOTE: exercise caution using this with absolute pathnames; it looks +# like the MinGW tools insert an extra _ in the binary symbol name; e.g. +# the path: +# +# /d/px4/firmware/Build/px4fmu_default.build/romfs.img +# +# is assigned symbols like: +# +# _binary_d__px4_firmware_Build_px4fmu_default_build_romfs_img_size +# +# when we would expect +# +# _binary__d_px4_firmware_Build_px4fmu_default_build_romfs_img_size +# define BIN_SYM_PREFIX _binary_$(subst /,_,$(subst .,_,$1)) endef @@ -267,4 +281,5 @@ define BIN_TO_OBJ --redefine-sym $(call BIN_SYM_PREFIX,$1)_start=$3 \ --redefine-sym $(call BIN_SYM_PREFIX,$1)_size=$3_len \ --strip-symbol $(call BIN_SYM_PREFIX,$1)_end + $(Q) $(REMOVE) $2.c $2.c.o endef From 1ff6c80866775b48bf38de5cdf5dea5f99691fc0 Mon Sep 17 00:00:00 2001 From: Lorenz Meier Date: Mon, 13 May 2013 08:28:36 +0200 Subject: [PATCH 76/84] More example fixes --- makefiles/config_px4fmu_default.mk | 2 +- src/examples/px4_daemon_app/module.mk | 2 +- src/examples/px4_mavlink_debug/module.mk | 2 +- src/examples/px4_simple_app/module.mk | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/makefiles/config_px4fmu_default.mk b/makefiles/config_px4fmu_default.mk index 27bf0f973b..ae62b70347 100644 --- a/makefiles/config_px4fmu_default.mk +++ b/makefiles/config_px4fmu_default.mk @@ -107,7 +107,7 @@ MODULES += modules/uORB # Tutorial code from # https://pixhawk.ethz.ch/px4/dev/example_fixedwing_control -MODULES += examples/fixedwing_control +MODULES += examples/fixedwing_control # # Transitional support - add commands from the NuttX export archive. diff --git a/src/examples/px4_daemon_app/module.mk b/src/examples/px4_daemon_app/module.mk index d23c19b75d..5f8aa73d57 100644 --- a/src/examples/px4_daemon_app/module.mk +++ b/src/examples/px4_daemon_app/module.mk @@ -37,4 +37,4 @@ MODULE_COMMAND = px4_daemon_app -SRCS = px4_daemon_app.c +SRCS = px4_daemon_app.c diff --git a/src/examples/px4_mavlink_debug/module.mk b/src/examples/px4_mavlink_debug/module.mk index 3d400fdbfc..fefd614961 100644 --- a/src/examples/px4_mavlink_debug/module.mk +++ b/src/examples/px4_mavlink_debug/module.mk @@ -37,4 +37,4 @@ MODULE_COMMAND = px4_mavlink_debug -SRCS = px4_mavlink_debug.c \ No newline at end of file +SRCS = px4_mavlink_debug.c \ No newline at end of file diff --git a/src/examples/px4_simple_app/module.mk b/src/examples/px4_simple_app/module.mk index 2c102fa500..32b06c3a58 100644 --- a/src/examples/px4_simple_app/module.mk +++ b/src/examples/px4_simple_app/module.mk @@ -37,4 +37,4 @@ MODULE_COMMAND = px4_simple_app -SRCS = px4_simple_app.c +SRCS = px4_simple_app.c From ff518e72d4f8628a44ff5d4106cf56ace6ec97f7 Mon Sep 17 00:00:00 2001 From: Lorenz Meier Date: Mon, 13 May 2013 08:34:48 +0200 Subject: [PATCH 77/84] Make it harder to run into a non-existent uORB error --- ROMFS/px4fmu_common/init.d/rc.sensors | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ROMFS/px4fmu_common/init.d/rc.sensors b/ROMFS/px4fmu_common/init.d/rc.sensors index 42c2f52e94..62c7184b85 100644 --- a/ROMFS/px4fmu_common/init.d/rc.sensors +++ b/ROMFS/px4fmu_common/init.d/rc.sensors @@ -7,6 +7,14 @@ # Start sensor drivers here. # +# +# Check for UORB +# +if uorb start +then + echo "uORB started" +fi + ms5611 start adc start From 69571c48c4fa742cfbfe9ce2333fc3d9c1f06034 Mon Sep 17 00:00:00 2001 From: Lorenz Meier Date: Mon, 13 May 2013 10:02:15 +0200 Subject: [PATCH 78/84] Fixed compile and logic errors, behaving now --- src/modules/px4iofirmware/mixer.cpp | 4 ++-- src/modules/px4iofirmware/registers.c | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/modules/px4iofirmware/mixer.cpp b/src/modules/px4iofirmware/mixer.cpp index f38593d2aa..5ada1b220e 100644 --- a/src/modules/px4iofirmware/mixer.cpp +++ b/src/modules/px4iofirmware/mixer.cpp @@ -174,7 +174,7 @@ mixer_tick(void) * here. */ bool should_arm = ( - /* FMU is armed */ (r_setup_arming & PX4IO_P_SETUP_ARMING_ARM_OK) && + /* FMU is armed */ (r_setup_arming & PX4IO_P_SETUP_ARMING_FMU_ARMED) && /* IO is armed */ (r_status_flags & PX4IO_P_STATUS_FLAGS_ARMED) && /* there is valid input */ (r_status_flags & (PX4IO_P_STATUS_FLAGS_RAW_PWM | PX4IO_P_STATUS_FLAGS_MIXER_OK)) && /* IO initialised without error */ (r_status_flags & PX4IO_P_STATUS_FLAGS_INIT_OK) && @@ -246,7 +246,7 @@ void mixer_handle_text(const void *buffer, size_t length) { /* do not allow a mixer change while fully armed */ - if (/* FMU is armed */ (r_setup_arming & PX4IO_P_SETUP_ARMING_ARM_OK) && + if (/* FMU is armed */ (r_setup_arming & PX4IO_P_SETUP_ARMING_FMU_ARMED) && /* IO is armed */ (r_status_flags & PX4IO_P_STATUS_FLAGS_ARMED)) { return; } diff --git a/src/modules/px4iofirmware/registers.c b/src/modules/px4iofirmware/registers.c index 4f3addfea8..61049c8b6a 100644 --- a/src/modules/px4iofirmware/registers.c +++ b/src/modules/px4iofirmware/registers.c @@ -142,9 +142,10 @@ volatile uint16_t r_page_setup[] = }; #define PX4IO_P_SETUP_FEATURES_VALID (0) -#define PX4IO_P_SETUP_ARMING_VALID (PX4IO_P_SETUP_ARMING_ARM_OK | \ +#define PX4IO_P_SETUP_ARMING_VALID (PX4IO_P_SETUP_ARMING_FMU_ARMED | \ PX4IO_P_SETUP_ARMING_MANUAL_OVERRIDE_OK | \ - PX4IO_P_SETUP_ARMING_INAIR_RESTART_OK) + PX4IO_P_SETUP_ARMING_INAIR_RESTART_OK | \ + PX4IO_P_SETUP_ARMING_IO_ARM_OK) #define PX4IO_P_SETUP_RATES_VALID ((1 << IO_SERVO_COUNT) - 1) #define PX4IO_P_SETUP_RELAYS_VALID ((1 << PX4IO_RELAY_CHANNELS) - 1) @@ -311,7 +312,7 @@ registers_set_one(uint8_t page, uint8_t offset, uint16_t value) * so that an in-air reset of FMU can not lead to a * lockup of the IO arming state. */ - if ((r_setup_arming & PX4IO_P_SETUP_ARMING_ARM_OK) && !(value & PX4IO_P_SETUP_ARMING_ARM_OK)) { + if ((r_setup_arming & PX4IO_P_SETUP_ARMING_FMU_ARMED) && !(value & PX4IO_P_SETUP_ARMING_FMU_ARMED)) { r_status_flags &= ~PX4IO_P_STATUS_FLAGS_ARMED; } @@ -362,7 +363,7 @@ registers_set_one(uint8_t page, uint8_t offset, uint16_t value) case PX4IO_PAGE_RC_CONFIG: { /* do not allow a RC config change while fully armed */ - if (/* FMU is armed */ (r_setup_arming & PX4IO_P_SETUP_ARMING_ARM_OK) && + if (/* FMU is armed */ (r_setup_arming & PX4IO_P_SETUP_ARMING_FMU_ARMED) && /* IO is armed */ (r_status_flags & PX4IO_P_STATUS_FLAGS_ARMED)) { break; } From 3ac76c4476038b170c319cfccd4a934363e1aca4 Mon Sep 17 00:00:00 2001 From: Lorenz Meier Date: Mon, 13 May 2013 10:15:36 +0200 Subject: [PATCH 79/84] Blink pattern fixes --- src/modules/px4iofirmware/safety.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/modules/px4iofirmware/safety.c b/src/modules/px4iofirmware/safety.c index f6cd5fb450..4dbecc2744 100644 --- a/src/modules/px4iofirmware/safety.c +++ b/src/modules/px4iofirmware/safety.c @@ -60,6 +60,7 @@ static unsigned counter = 0; #define LED_PATTERN_FMU_OK_TO_ARM 0x0003 /**< slow blinking */ #define LED_PATTERN_FMU_REFUSE_TO_ARM 0x5555 /**< fast blinking */ #define LED_PATTERN_IO_ARMED 0x5050 /**< long off, then double blink */ +#define LED_PATTERN_FMU_ARMED 0x5500 /**< long off, then quad blink */ #define LED_PATTERN_IO_FMU_ARMED 0xffff /**< constantly on */ static unsigned blink_counter = 0; @@ -147,6 +148,8 @@ safety_check_button(void *arg) pattern = LED_PATTERN_IO_ARMED; } + } else if (r_setup_arming & PX4IO_P_SETUP_ARMING_FMU_ARMED) { + pattern = LED_PATTERN_FMU_ARMED; } else if (r_setup_arming & PX4IO_P_SETUP_ARMING_IO_ARM_OK) { pattern = LED_PATTERN_FMU_OK_TO_ARM; From 7ae053c16b6bfb8bcd01cfc5418771854363f659 Mon Sep 17 00:00:00 2001 From: Lorenz Meier Date: Mon, 13 May 2013 10:26:42 +0200 Subject: [PATCH 80/84] Hotfix: Make the param file name less then 8 characters --- ROMFS/px4fmu_common/init.d/rc.FMU_quad_x | 6 +++--- ROMFS/px4fmu_common/init.d/rc.IO_QUAD | 6 +++--- ROMFS/px4fmu_common/init.d/rc.PX4IO | 6 +++--- ROMFS/px4fmu_common/init.d/rc.PX4IOAR | 8 ++++---- ROMFS/px4fmu_common/init.d/rc.hil | 6 +++--- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/ROMFS/px4fmu_common/init.d/rc.FMU_quad_x b/ROMFS/px4fmu_common/init.d/rc.FMU_quad_x index 8787443ea2..980197d68e 100644 --- a/ROMFS/px4fmu_common/init.d/rc.FMU_quad_x +++ b/ROMFS/px4fmu_common/init.d/rc.FMU_quad_x @@ -20,10 +20,10 @@ uorb start # Load microSD params # echo "[init] loading microSD params" -param select /fs/microsd/parameters -if [ -f /fs/microsd/parameters ] +param select /fs/microsd/params +if [ -f /fs/microsd/params ] then - param load /fs/microsd/parameters + param load /fs/microsd/params fi # diff --git a/ROMFS/px4fmu_common/init.d/rc.IO_QUAD b/ROMFS/px4fmu_common/init.d/rc.IO_QUAD index 287cb0483b..5f2de0d7e0 100644 --- a/ROMFS/px4fmu_common/init.d/rc.IO_QUAD +++ b/ROMFS/px4fmu_common/init.d/rc.IO_QUAD @@ -13,10 +13,10 @@ uorb start # Load microSD params # echo "[init] loading microSD params" -param select /fs/microsd/parameters -if [ -f /fs/microsd/parameters ] +param select /fs/microsd/params +if [ -f /fs/microsd/params ] then - param load /fs/microsd/parameters + param load /fs/microsd/params fi # diff --git a/ROMFS/px4fmu_common/init.d/rc.PX4IO b/ROMFS/px4fmu_common/init.d/rc.PX4IO index 7ae4a55860..925a5703e7 100644 --- a/ROMFS/px4fmu_common/init.d/rc.PX4IO +++ b/ROMFS/px4fmu_common/init.d/rc.PX4IO @@ -13,10 +13,10 @@ uorb start # Load microSD params # echo "[init] loading microSD params" -param select /fs/microsd/parameters -if [ -f /fs/microsd/parameters ] +param select /fs/microsd/params +if [ -f /fs/microsd/params ] then - param load /fs/microsd/parameters + param load /fs/microsd/params fi # diff --git a/ROMFS/px4fmu_common/init.d/rc.PX4IOAR b/ROMFS/px4fmu_common/init.d/rc.PX4IOAR index ab29e21c7e..f55ac2ae34 100644 --- a/ROMFS/px4fmu_common/init.d/rc.PX4IOAR +++ b/ROMFS/px4fmu_common/init.d/rc.PX4IOAR @@ -17,13 +17,13 @@ echo "[init] doing PX4IOAR startup..." uorb start # -# Init the parameter storage +# Load microSD params # echo "[init] loading microSD params" -param select /fs/microsd/parameters -if [ -f /fs/microsd/parameters ] +param select /fs/microsd/params +if [ -f /fs/microsd/params ] then - param load /fs/microsd/parameters + param load /fs/microsd/params fi # diff --git a/ROMFS/px4fmu_common/init.d/rc.hil b/ROMFS/px4fmu_common/init.d/rc.hil index 980b78edda..7614ac0feb 100644 --- a/ROMFS/px4fmu_common/init.d/rc.hil +++ b/ROMFS/px4fmu_common/init.d/rc.hil @@ -17,10 +17,10 @@ hil mode_pwm # Load microSD params # echo "[init] loading microSD params" -param select /fs/microsd/parameters -if [ -f /fs/microsd/parameters ] +param select /fs/microsd/params +if [ -f /fs/microsd/params ] then - param load /fs/microsd/parameters + param load /fs/microsd/params fi # From 9a07788d58dd6f1ca6657e18048bf88eae5f6e10 Mon Sep 17 00:00:00 2001 From: Lorenz Meier Date: Mon, 13 May 2013 23:25:18 +0200 Subject: [PATCH 81/84] Hotfix: Off-by-one fix in overflow check --- src/drivers/ardrone_interface/ardrone_motor_control.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/drivers/ardrone_interface/ardrone_motor_control.c b/src/drivers/ardrone_interface/ardrone_motor_control.c index f15c74a22d..ecd31a073d 100644 --- a/src/drivers/ardrone_interface/ardrone_motor_control.c +++ b/src/drivers/ardrone_interface/ardrone_motor_control.c @@ -482,10 +482,10 @@ void ardrone_mixing_and_output(int ardrone_write, const struct actuator_controls motor_pwm[3] = (motor_pwm[3] > 0) ? motor_pwm[3] : 10; /* Failsafe logic - should never be necessary */ - motor_pwm[0] = (motor_pwm[0] <= 512) ? motor_pwm[0] : 512; - motor_pwm[1] = (motor_pwm[1] <= 512) ? motor_pwm[1] : 512; - motor_pwm[2] = (motor_pwm[2] <= 512) ? motor_pwm[2] : 512; - motor_pwm[3] = (motor_pwm[3] <= 512) ? motor_pwm[3] : 512; + motor_pwm[0] = (motor_pwm[0] <= 511) ? motor_pwm[0] : 511; + motor_pwm[1] = (motor_pwm[1] <= 511) ? motor_pwm[1] : 511; + motor_pwm[2] = (motor_pwm[2] <= 511) ? motor_pwm[2] : 511; + motor_pwm[3] = (motor_pwm[3] <= 511) ? motor_pwm[3] : 511; /* send motors via UART */ ardrone_write_motor_commands(ardrone_write, motor_pwm[0], motor_pwm[1], motor_pwm[2], motor_pwm[3]); From 0c43315c1ed8538daee9ad47c14731c295c2dda2 Mon Sep 17 00:00:00 2001 From: px4dev Date: Mon, 13 May 2013 22:20:08 -0700 Subject: [PATCH 82/84] Hotfix: better error messages for missing modules --- makefiles/firmware.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/makefiles/firmware.mk b/makefiles/firmware.mk index 7afa3e787d..497e792376 100644 --- a/makefiles/firmware.mk +++ b/makefiles/firmware.mk @@ -201,9 +201,9 @@ MODULES := $(sort $(MODULES)) # locate the first instance of a module by full path or by looking on the # module search path define MODULE_SEARCH - $(abspath $(firstword $(wildcard $(1)/module.mk) \ - $(foreach search_dir,$(MODULE_SEARCH_DIRS),$(wildcard $(search_dir)/$(1)/module.mk)) \ - MISSING_$1)) + $(firstword $(abspath $(wildcard $(1)/module.mk)) \ + $(abspath $(foreach search_dir,$(MODULE_SEARCH_DIRS),$(wildcard $(search_dir)/$(1)/module.mk))) \ + MISSING_$1) endef # make a list of module makefiles and check that we found them all From fa816d0fd65da461fd5bf8803cf00caebaf23c5c Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 16 May 2013 16:21:33 +1000 Subject: [PATCH 83/84] arming: added PWM_SERVO_SET_ARM_OK and PWM_SERVO_CLEAR_ARM_OK these new ioctls allow for the flight code to tell the IO board that arming can proceed --- src/drivers/drv_pwm_output.h | 6 ++++++ src/drivers/px4fmu/fmu.cpp | 5 +++++ src/drivers/px4io/px4io.cpp | 10 ++++++++++ 3 files changed, 21 insertions(+) diff --git a/src/drivers/drv_pwm_output.h b/src/drivers/drv_pwm_output.h index 07831f20cf..56af710592 100644 --- a/src/drivers/drv_pwm_output.h +++ b/src/drivers/drv_pwm_output.h @@ -109,6 +109,12 @@ ORB_DECLARE(output_pwm); /** selects servo update rates, one bit per servo. 0 = default (50Hz), 1 = alternate */ #define PWM_SERVO_SELECT_UPDATE_RATE _IOC(_PWM_SERVO_BASE, 4) +/** set the 'ARM ok' bit, which activates the safety switch */ +#define PWM_SERVO_SET_ARM_OK _IOC(_PWM_SERVO_BASE, 5) + +/** clear the 'ARM ok' bit, which deactivates the safety switch */ +#define PWM_SERVO_CLEAR_ARM_OK _IOC(_PWM_SERVO_BASE, 6) + /** set a single servo to a specific value */ #define PWM_SERVO_SET(_servo) _IOC(_PWM_SERVO_BASE, 0x20 + _servo) diff --git a/src/drivers/px4fmu/fmu.cpp b/src/drivers/px4fmu/fmu.cpp index 761a23c426..bf72892ebe 100644 --- a/src/drivers/px4fmu/fmu.cpp +++ b/src/drivers/px4fmu/fmu.cpp @@ -606,6 +606,11 @@ PX4FMU::pwm_ioctl(file *filp, int cmd, unsigned long arg) up_pwm_servo_arm(true); break; + case PWM_SERVO_SET_ARM_OK: + case PWM_SERVO_CLEAR_ARM_OK: + // these are no-ops, as no safety switch + break; + case PWM_SERVO_DISARM: up_pwm_servo_arm(false); break; diff --git a/src/drivers/px4io/px4io.cpp b/src/drivers/px4io/px4io.cpp index 3006cf885b..a40142792a 100644 --- a/src/drivers/px4io/px4io.cpp +++ b/src/drivers/px4io/px4io.cpp @@ -1358,6 +1358,16 @@ PX4IO::ioctl(file *filep, int cmd, unsigned long arg) ret = io_reg_modify(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_ARMING, 0, PX4IO_P_SETUP_ARMING_FMU_ARMED); break; + case PWM_SERVO_SET_ARM_OK: + /* set the 'OK to arm' bit */ + ret = io_reg_modify(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_ARMING, 0, PX4IO_P_SETUP_ARMING_IO_ARM_OK); + break; + + case PWM_SERVO_CLEAR_ARM_OK: + /* clear the 'OK to arm' bit */ + ret = io_reg_modify(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_ARMING, PX4IO_P_SETUP_ARMING_IO_ARM_OK, 0); + break; + case PWM_SERVO_DISARM: /* clear the 'armed' bit */ ret = io_reg_modify(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_ARMING, PX4IO_P_SETUP_ARMING_FMU_ARMED, 0); From 504b6d12561d68874ded4c1f747c21926a065045 Mon Sep 17 00:00:00 2001 From: px4dev Date: Fri, 17 May 2013 01:55:02 -0700 Subject: [PATCH 84/84] Hotfix: install the firmware .bin files as well as the .px4 bundles until we have a chance to fix the px4io uploader. --- Makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Makefile b/Makefile index 1d1287b7f7..dea3443901 100644 --- a/Makefile +++ b/Makefile @@ -95,9 +95,14 @@ all: $(STAGED_FIRMWARES) # # Copy FIRMWARES into the image directory. # +# XXX copying the .bin files is a hack to work around the PX4IO uploader +# not supporting .px4 files, and it should be deprecated onced that +# is taken care of. +# $(STAGED_FIRMWARES): $(IMAGE_DIR)%.px4: $(BUILD_DIR)%.build/firmware.px4 @echo %% Copying $@ $(Q) $(COPY) $< $@ + $(Q) $(COPY) $(patsubst %.px4,%.bin,$<) $(patsubst %.px4,%.bin,$@) # # Generate FIRMWARES.