diff --git a/Tools/Pozyx/IndoorLoiter/IndoorLoiter.ino b/Tools/Pozyx/IndoorLoiter/IndoorLoiter.ino index ec822deef2..0b004b99a3 100644 --- a/Tools/Pozyx/IndoorLoiter/IndoorLoiter.ino +++ b/Tools/Pozyx/IndoorLoiter/IndoorLoiter.ino @@ -1,120 +1,155 @@ -#include -#include - #include #include -/*//#include */ -#include "C:\Users\rmackay9\Documents\GitHub\ardupilot\Build.ArduCopter\libraries\GCS_MAVLink\include\mavlink\v2.0\common\mavlink.h" #include #include -/*#include // download from https://github.com/PaulStoffregen/Time */ -//#include "C:\Users\rmackay9\Documents\GitHub\Time\Time.h" ////////////////// Pozyx Prams ////////////////////////////// +#define CONFIG_TX_GAIN 33.5f #define NUM_ANCHORS 4 // the network id of the anchors: change these to the network ids of your anchors. -uint16_t anchors[4] = { 0x601C, // (0,0) - 0x6020, // x-axis - 0x6057, // y-axis - 0x605E}; +uint16_t anchor_id[4] = { 0x601C, // (0,0) + 0x6020, // x-axis + 0x6057, // y-axis + 0x605E}; // only required for manual anchor calibration. // Please change this to the coordinates measured for the anchors -int32_t anchors_x[NUM_ANCHORS] = {0, 18600, 0, 18600}; // anchor x-coorindates in mm (horizontal) -int32_t anchors_y[NUM_ANCHORS] = {0, 0, 10000, 10000}; // anchor y-coordinates in mm (vertical) -int32_t heights[NUM_ANCHORS] = {1420, 0, 0, 1450}; // anchor z-coordinates in mm - -////////////////// MAVLINK Prams ////////////////////////////// -#define LATITUDE_BASE (36.324187 * 1.0e7) -#define LONGITUDE_BASE (138.639212 * 1.0e7) -uint8_t buf[MAVLINK_MSG_ID_GPS_INPUT_LEN]; -int32_t latitude = 0; -int32_t longitude = 0; +int32_t anchors_x[NUM_ANCHORS] = {0, 10000, 0, 10000}; // anchor x-coorindates in mm (horizontal) +int32_t anchors_y[NUM_ANCHORS] = {0, 0, 10000, 10000}; // anchor y-coordinates in mm (vertical) +int32_t heights[NUM_ANCHORS] = {-1200, -1200, -1200, -1200}; // anchor z-coordinates in mm (1.2m above vehicle's starting altitude) // RX TX serial for flight controller ex) Pixhawk // https://github.com/PaulStoffregen/AltSoftSerial - SoftwareSerial fcboardSerial(10, 11); // rx, tx +#define MSG_HEADER 0x01 +#define MSGID_BEACON_CONFIG 0x02 +#define MSGID_BEACON_DIST 0x03 +#define MSGID_POSITION 0x04 + +// structure for messages uploaded to ardupilot +union beacon_config_msg { + struct { + uint8_t beacon_id; + uint8_t beacon_count; + int32_t x; + int32_t y; + int32_t z; + } info; + uint8_t buf[14]; +}; +union beacon_distance_msg { + struct { + uint8_t beacon_id; + uint32_t distance; + } info; + uint8_t buf[5]; +}; +union vehicle_position_msg { + struct { + int32_t x; + int32_t y; + int32_t z; + int16_t position_error; + } info; + uint8_t buf[14]; +}; //////////////////////////////////////////////// void setup() { - Serial.begin(115200); - fcboardSerial.begin(57600); - - if (Pozyx.begin() == POZYX_FAILURE) { - Serial.println(("ERR: shield")); - delay(100); - abort(); - } - - Serial.println(("V1.0")); + Serial.begin(115200); + fcboardSerial.begin(115200); - // clear all previous devices in the device list - Pozyx.clearDevices(); - - //int status = Pozyx.doAnchorCalibration(POZYX_2_5D, 10, num_anchors, anchors, heights); - /*int status = Pozyx.doAnchorCalibration(POZYX_2D, 10, num_anchors, anchors, heights); - if (status != POZYX_SUCCESS) { - Serial.println(status); - Serial.println(("ERROR: calibration")); - Serial.println(("Reset required")); - delay(100); - abort(); - }*/ - - // if the automatic anchor calibration is unsuccessful, try manually setting the anchor coordinates. - // fot this, you must update the arrays anchors_x, anchors_y and heights above - // comment out the doAnchorCalibration block and the if-statement above if you are using manual mode - SetAnchorsManual(); + if (Pozyx.begin() == POZYX_FAILURE) { + Serial.println(("ERR: shield")); + delay(100); + abort(); + } - printCalibrationResult(); - Serial.println(("Waiting..")); - delay(5000); + Serial.println(("V1.0")); - Serial.println(("Starting: ")); + // clear all previous devices in the device list + Pozyx.clearDevices(); + + // configure beacons + while (!configure_beacons()) { + delay(1000); + } + + // if the automatic anchor calibration is unsuccessful, try manually setting the anchor coordinates. + // fot this, you must update the arrays anchors_x, anchors_y and heights above + // comment out the doAnchorCalibration block and the if-statement above if you are using manual mode + SetAnchorsManual(); + + print_anchor_coordinates(); + + Serial.println(("Waiting..")); + delay(5000); + + Serial.println(("Starting: ")); } void loop() -{ - coordinates_t position; - - int status = Pozyx.doPositioning(&position, POZYX_2_5D, 1000); - //int status = Pozyx.doPositioning(&position); - - if (status == POZYX_SUCCESS) { - // print out the result - printCoordinates(position); +{ + static uint32_t loop_start = 0; + static uint8_t stage = 0; // 0 = initialisation, 1 = normal flight + static uint16_t beacon_sent_count = 0; + static uint32_t beacon_sent_time = 0; - // send GPS MAVLINK message - SendGPSMAVLinkMessage(position); - } else { - Serial.println("fail"); - } + // initialise start time + if (loop_start == 0) { + loop_start = millis(); + } + + // advance to normal flight stage after 1min + if (stage == 0) { + uint32_t time_diff = (millis() - loop_start); + if (time_diff > 60000) { + stage = 1; + Serial.println("Stage1"); + } + } + + // slow down counter + static uint8_t counter = 0; + counter++; + if (counter >= 20) { + counter = 0; + } + + // during stage 0 (init) send position and beacon config as quickly as possible + // during stage 1 send about every 2 seconds + if (stage == 0 || counter == 0) { + send_beacon_config(); + get_position(); + if (beacon_sent_count > 0 && beacon_sent_time != 0) { + uint32_t time_diff = millis() - beacon_sent_time; + float hz = (float)beacon_sent_count / (time_diff / 1000.0f); + Serial.print("Beacon hz:"); + Serial.println(hz); + } + beacon_sent_count = 0; + beacon_sent_time = millis(); + } + + // send beacon distances + get_ranges(); + beacon_sent_count++; } -// function to print the coordinates to the serial monitor -void printCoordinates(coordinates_t coor) -{ - Serial.print("x:"); - Serial.print(coor.x); - print_tab(); - Serial.print("y:"); - Serial.print(coor.y); - print_tab(); - Serial.print("z:"); - Serial.print(coor.z); - print_tab(); - Serial.print("lat:"); - Serial.print(latitude); - print_tab(); - Serial.print("lng:"); - Serial.print(longitude); - print_tab(); - Serial.println(); +uint32_t time_start_ms; +void timer_start() +{ + time_start_ms = millis(); +} +void timer_end() +{ + uint32_t time_diff = millis() - time_start_ms; + Serial.print("ms:"); + Serial.println(time_diff); } void print_comma() @@ -127,40 +162,169 @@ void print_tab() Serial.print("\t"); } -#define LOCATION_SCALING_FACTOR_INV_MM 0.08983204953368922f -#define DEG_TO_RAD (M_PI / 180.0f) - -float longitude_scale(uint32_t lat) +// set a tag or anchor's gain +// set tag_id to zero to set local device's gain +// returns true on success +bool set_device_gain(uint16_t dev_id, float gain) { - static int32_t last_lat = 0; - static float scale = 1.0; - if (labs(last_lat - lat) < 100000) { - // we are within 0.01 degrees (about 1km) of the - // previous latitude. We can avoid the cos() and return - // the same scale factor. - return scale; + float tx_power = -1; + + // get/set transmit power of tag + bool gain_ok = false; + uint8_t retry = 0; + while (!gain_ok && retry < 5) { + if (Pozyx.getTxPower(&tx_power, dev_id) == POZYX_SUCCESS) { + if (tx_power != gain) { + Pozyx.setTxPower(CONFIG_TX_GAIN, dev_id); + } else { + gain_ok = true; + } + } + retry++; } - scale = cosf(lat * 1.0e-7f * DEG_TO_RAD); - if (scale < 0.01f) { - scale = 0.01f; + + // display final gain + Serial.print("Dev "); + Serial.print(dev_id, HEX); + Serial.print(" gain "); + if (tx_power > 0) { + Serial.print(tx_power); + } else { + Serial.print("unknown"); } - if (scale > 1.0f) { - scale = 1.0f; - } - last_lat = lat; - return scale; + Serial.print(" (retry "); + Serial.print(retry); + Serial.print(")"); + Serial.println(); + + return gain_ok; } -void location_offset(int32_t &lat, int32_t &lng, int32_t offset_north_mm, int32_t offset_east_mm) +// performs repeated calls to get reliable distance between devices +bool get_remote_range(uint16_t dev1, uint16_t dev2, int32_t& range) { - int32_t dlat = offset_north_mm * LOCATION_SCALING_FACTOR_INV_MM; - int32_t dlng = (offset_east_mm * LOCATION_SCALING_FACTOR_INV_MM) / longitude_scale(lat); - lat += dlat; - lng += dlng; + // set distances between tags + uint32_t range_tot = 0; + uint16_t count = 0; + device_range_t dev_range; + for (uint8_t i=0; i <= 10; i++) { + // origin to 1st + if (Pozyx.doRemoteRanging(dev1, dev2, &dev_range) == POZYX_SUCCESS) { + range_tot += dev_range.distance; + count++; + } + if (Pozyx.doRemoteRanging(dev2, dev1, &dev_range) == POZYX_SUCCESS) { + range_tot += dev_range.distance; + count++; + } + } + // success if at least 5 successful ranges were retrieved + if (count > 5) { + range = range_tot / count; + return true; + } + return false; } -// print out the anchor coordinates (also required for the processing sketch) -void printCalibrationResult() +void print_failed_to_range(uint16_t dev1, uint16_t dev2) +{ + Serial.print("ranging fail "); + Serial.print(dev1,HEX); + Serial.print(" to "); + Serial.println(dev2,HEX); +} + +void set_beacon_position(uint8_t index, int32_t x_mm, int32_t y_mm, int32_t z_mm) +{ + anchors_x[index] = x_mm; + anchors_y[index] = y_mm; + heights[index] = z_mm; +} + +// configure beacons +bool configure_beacons() +{ + bool configured_ok = true; + + // get/set transmit power of tag + if (!set_device_gain(0, CONFIG_TX_GAIN)) { + configured_ok = false; + } + + // set transmit power of beacons + for (uint8_t i=0; i < NUM_ANCHORS; i++) { + if (!set_device_gain(anchor_id[i], CONFIG_TX_GAIN)) { + configured_ok = false; + } + } + + // set distances between tags + int32_t x_range = 0, y_range = 0; + // origin to x-axis (i.e. bottom right) + if (get_remote_range(anchor_id[0], anchor_id[1], x_range)) { + set_beacon_position(1, x_range, 0, heights[1]); + } else { + print_failed_to_range(anchor_id[0], anchor_id[1]); + configured_ok = false; + } + // origin to y-axis (i.e. top left) + if (get_remote_range(anchor_id[0], anchor_id[2], y_range)) { + set_beacon_position(2, 0, y_range, heights[2]); + } else { + print_failed_to_range(anchor_id[0], anchor_id[2]); + configured_ok = false; + } + // top right + if (x_range != 0 && y_range != 0) { + set_beacon_position(3, x_range, y_range, heights[3]); + } else { + Serial.println("beacons too close"); + configured_ok = false; + } + + if (configured_ok) { + Serial.println("Beacon Configuration complete"); + } else { + Serial.println("Beacon Configuration failed!"); + } + + return configured_ok; +} + +// function to manually set the anchor coordinates +void SetAnchorsManual() +{ + for (uint8_t i=0; i= rmon) { - rmon += 12; - year -= 1; + // get range for each anchor + device_range_t range; + bool success = false; + for (uint8_t i=0; i