123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 |
- /*
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /*
- Original C Code by Marvelmind (https://github.com/MarvelmindRobotics/marvelmind.c)
- Adapted into Ardupilot by Karthik Desai, Amilcar Lucas
- April 2017
- */
- #include <AP_HAL/AP_HAL.h>
- #include <AP_Math/crc.h>
- #include "AP_Beacon_Marvelmind.h"
- #define AP_BEACON_MARVELMIND_POSITION_DATAGRAM_ID 0x0001
- #define AP_BEACON_MARVELMIND_POSITIONS_DATAGRAM_ID 0x0002
- #define AP_BEACON_MARVELMIND_DISTANCES_DATAGRAM_ID 0x0004
- #define AP_BEACON_MARVELMIND_POSITION_DATAGRAM_HIGHRES_ID 0x0011
- #define AP_BEACON_MARVELMIND_POSITIONS_DATAGRAM_HIGHRES_ID 0x0012
- extern const AP_HAL::HAL& hal;
- #define MM_DEBUG_LEVEL 0
- #if MM_DEBUG_LEVEL
- #include <GCS_MAVLink/GCS.h>
- #define Debug(level, fmt, args ...) do { if (level <= MM_DEBUG_LEVEL) { gcs().send_text(MAV_SEVERITY_INFO, fmt, ## args); } } while (0)
- #else
- #define Debug(level, fmt, args ...)
- #endif
- AP_Beacon_Marvelmind::AP_Beacon_Marvelmind(AP_Beacon &frontend, AP_SerialManager &serial_manager) :
- AP_Beacon_Backend(frontend)
- {
- uart = serial_manager.find_serial(AP_SerialManager::SerialProtocol_Beacon, 0);
- if (uart != nullptr) {
- uart->begin(serial_manager.find_baudrate(AP_SerialManager::SerialProtocol_Beacon, 0));
- last_update_ms = 0;
- parse_state = RECV_HDR; // current state of receive data
- num_bytes_in_block_received = 0; // bytes received
- data_id = 0;
- hedge._have_new_values = false;
- hedge.positions_beacons.num_beacons = 0;
- hedge.positions_beacons.updated = false;
- }
- }
- void AP_Beacon_Marvelmind::process_position_datagram()
- {
- hedge.cur_position.address = input_buffer[16];
- hedge.cur_position.timestamp = input_buffer[5]
- | (((uint32_t) input_buffer[6]) << 8)
- | (((uint32_t) input_buffer[7]) << 16)
- | (((uint32_t) input_buffer[8]) << 24);
- const int16_t vx = input_buffer[9] | (((uint16_t) input_buffer[10]) << 8);
- hedge.cur_position.x__mm = vx * 10; // centimeters -> millimeters
- const int16_t vy = input_buffer[11] | (((uint16_t) input_buffer[12]) << 8);
- hedge.cur_position.y__mm = vy * 10; // centimeters -> millimeters
- const int16_t vz = input_buffer[13] | (((uint16_t) input_buffer[14]) << 8);
- hedge.cur_position.z__mm = vz * 10; // centimeters -> millimeters
- hedge.cur_position.high_resolution = false;
- hedge._have_new_values = true;
- }
- void AP_Beacon_Marvelmind::process_position_highres_datagram()
- {
- hedge.cur_position.address = input_buffer[22];
- hedge.cur_position.timestamp = input_buffer[5]
- | (((uint32_t) input_buffer[6]) << 8)
- | (((uint32_t) input_buffer[7]) << 16)
- | (((uint32_t) input_buffer[8]) << 24);
- hedge.cur_position.x__mm = input_buffer[9] | (((uint32_t) input_buffer[10]) << 8)
- | (((uint32_t) input_buffer[11]) << 16)
- | (((uint32_t) input_buffer[12]) << 24);
- hedge.cur_position.y__mm = input_buffer[13] | (((uint32_t) input_buffer[14]) << 8)
- | (((uint32_t) input_buffer[15]) << 16)
- | (((uint32_t) input_buffer[16]) << 24);
- hedge.cur_position.z__mm = input_buffer[17] | (((uint32_t) input_buffer[18]) << 8)
- | (((uint32_t) input_buffer[19]) << 16)
- | (((uint32_t) input_buffer[20]) << 24);
- hedge.cur_position.high_resolution = true;
- hedge._have_new_values = true;
- }
- AP_Beacon_Marvelmind::StationaryBeaconPosition* AP_Beacon_Marvelmind::get_or_alloc_beacon(uint8_t address)
- {
- const uint8_t n_used = hedge.positions_beacons.num_beacons;
- for (uint8_t i = 0; i < n_used; i++) {
- if (hedge.positions_beacons.beacons[i].address == address) {
- return &hedge.positions_beacons.beacons[i];
- }
- }
- if (n_used >= AP_BEACON_MAX_BEACONS) {
- return nullptr;
- }
- hedge.positions_beacons.num_beacons = (n_used + 1);
- return &hedge.positions_beacons.beacons[n_used];
- }
- void AP_Beacon_Marvelmind::process_beacons_positions_datagram()
- {
- const uint8_t n = input_buffer[5]; // number of beacons in packet
- StationaryBeaconPosition *stationary_beacon;
- if ((1 + n * 8) != input_buffer[4]) {
- Debug(1, "beacon pos lo pkt size %d != %d", input_buffer[4], (1 + n * 8));
- return; // incorrect size
- }
- for (uint8_t i = 0; i < n; i++) {
- const uint8_t ofs = 6 + i * 8;
- const uint8_t address = input_buffer[ofs];
- const int16_t x = input_buffer[ofs + 1]
- | (((uint16_t) input_buffer[ofs + 2]) << 8);
- const int16_t y = input_buffer[ofs + 3]
- | (((uint16_t) input_buffer[ofs + 4]) << 8);
- const int16_t z = input_buffer[ofs + 5]
- | (((uint16_t) input_buffer[ofs + 6]) << 8);
- stationary_beacon = get_or_alloc_beacon(address);
- if (stationary_beacon != nullptr) {
- stationary_beacon->address = address; //The instance and the address are the same
- stationary_beacon->x__mm = x * 10; // centimeters -> millimeters
- stationary_beacon->y__mm = y * 10; // centimeters -> millimeters
- stationary_beacon->z__mm = z * 10; // centimeters -> millimeters
- stationary_beacon->high_resolution = false;
- hedge.positions_beacons.updated = true;
- }
- }
- order_stationary_beacons();
- }
- void AP_Beacon_Marvelmind::process_beacons_positions_highres_datagram()
- {
- const uint8_t n = input_buffer[5]; // number of beacons in packet
- StationaryBeaconPosition *stationary_beacon;
- if ((1 + n * 14) != input_buffer[4]) {
- Debug(1, "beacon pos hi pkt size %d != %d", input_buffer[4], (1 + n * 14));
- return; // incorrect size
- }
- for (uint8_t i = 0; i < n; i++) {
- const uint8_t ofs = 6 + i * 14;
- const uint8_t address = input_buffer[ofs];
- const int32_t x = input_buffer[ofs + 1]
- | (((uint32_t) input_buffer[ofs + 2]) << 8)
- | (((uint32_t) input_buffer[ofs + 3]) << 16)
- | (((uint32_t) input_buffer[ofs + 4]) << 24);
- const int32_t y = input_buffer[ofs + 5]
- | (((uint32_t) input_buffer[ofs + 6]) << 8)
- | (((uint32_t) input_buffer[ofs + 7]) << 16)
- | (((uint32_t) input_buffer[ofs + 8]) << 24);
- const int32_t z = input_buffer[ofs + 9]
- | (((uint32_t) input_buffer[ofs + 10]) << 8)
- | (((uint32_t) input_buffer[ofs + 11]) << 16)
- | (((uint32_t) input_buffer[ofs + 12]) << 24);
- stationary_beacon = get_or_alloc_beacon(address);
- if (stationary_beacon != nullptr) {
- stationary_beacon->address = address; //The instance and the address are the same
- stationary_beacon->x__mm = x; // millimeters
- stationary_beacon->y__mm = y; // millimeters
- stationary_beacon->z__mm = z; // millimeters
- stationary_beacon->high_resolution = true;
- hedge.positions_beacons.updated = true;
- }
- }
- order_stationary_beacons();
- }
- void AP_Beacon_Marvelmind::process_beacons_distances_datagram()
- {
- if (32 != input_buffer[4]) {
- Debug(1, "beacon dist pkt size %d != 32", input_buffer[4]);
- return; // incorrect size
- }
- bool set = false;
- for (uint8_t i = 0; i < hedge.positions_beacons.num_beacons; i++) {
- const uint8_t ofs = 6 + i * 6;
- const uint8_t address = input_buffer[ofs];
- const int8_t instance = find_beacon_instance(address);
- if (instance != -1) {
- const uint32_t distance = input_buffer[ofs + 1]
- | (((uint32_t) input_buffer[ofs + 2]) << 8)
- | (((uint32_t) input_buffer[ofs + 3]) << 16)
- | (((uint32_t) input_buffer[ofs + 4]) << 24);
- hedge.positions_beacons.beacons[instance].distance__m = distance * 0.001f; // millimeters -> meters
- set_beacon_distance(instance, hedge.positions_beacons.beacons[instance].distance__m);
- set = true;
- Debug(2, "Beacon %d is %.2fm", instance, hedge.positions_beacons.beacons[instance].distance__m);
- }
- }
- if (set) {
- last_update_ms = AP_HAL::millis();
- }
- }
- int8_t AP_Beacon_Marvelmind::find_beacon_instance(uint8_t address) const
- {
- for (uint8_t i = 0; i < hedge.positions_beacons.num_beacons; i++) {
- if (hedge.positions_beacons.beacons[i].address == address) {
- return i;
- }
- }
- return -1;
- }
- void AP_Beacon_Marvelmind::update(void)
- {
- if (uart == nullptr) {
- return;
- }
- // read any available characters
- int32_t num_bytes_read = uart->available();
- uint8_t received_char = 0;
- if (num_bytes_read < 0) {
- return;
- }
- while (num_bytes_read-- > 0) {
- bool good_byte = false;
- received_char = uart->read();
- input_buffer[num_bytes_in_block_received] = received_char;
- switch (parse_state) {
- case RECV_HDR:
- switch (num_bytes_in_block_received) {
- case 0:
- good_byte = (received_char == 0xff);
- break;
- case 1:
- good_byte = (received_char == 0x47);
- break;
- case 2:
- good_byte = true;
- break;
- case 3:
- data_id = (((uint16_t)received_char) << 8) + input_buffer[2];
- good_byte = (data_id == AP_BEACON_MARVELMIND_POSITION_DATAGRAM_ID)
- || (data_id == AP_BEACON_MARVELMIND_POSITIONS_DATAGRAM_ID)
- || (data_id == AP_BEACON_MARVELMIND_DISTANCES_DATAGRAM_ID)
- || (data_id == AP_BEACON_MARVELMIND_POSITION_DATAGRAM_HIGHRES_ID)
- || (data_id == AP_BEACON_MARVELMIND_POSITIONS_DATAGRAM_HIGHRES_ID);
- break;
- case 4: {
- switch (data_id) {
- case AP_BEACON_MARVELMIND_POSITION_DATAGRAM_ID: {
- good_byte = (received_char == 0x10);
- break;
- }
- case AP_BEACON_MARVELMIND_DISTANCES_DATAGRAM_ID:
- case AP_BEACON_MARVELMIND_POSITIONS_DATAGRAM_ID:
- case AP_BEACON_MARVELMIND_POSITIONS_DATAGRAM_HIGHRES_ID:
- good_byte = true;
- break;
- case AP_BEACON_MARVELMIND_POSITION_DATAGRAM_HIGHRES_ID: {
- good_byte = (received_char == 0x16);
- break;
- }
- }
- if (good_byte) {
- parse_state = RECV_DGRAM;
- }
- break;
- }
- }
- if (good_byte) {
- // correct header byte
- num_bytes_in_block_received++;
- } else {
- // ...or incorrect
- parse_state = RECV_HDR;
- num_bytes_in_block_received = 0;
- }
- break;
- case RECV_DGRAM:
- num_bytes_in_block_received++;
- if (num_bytes_in_block_received >= 7 + input_buffer[4]) {
- // parse dgram
- uint16_t block_crc = calc_crc_modbus(input_buffer, num_bytes_in_block_received);
- if (block_crc == 0) {
- switch (data_id) {
- case AP_BEACON_MARVELMIND_POSITION_DATAGRAM_ID:
- {
- // add to position_buffer
- process_position_datagram();
- vehicle_position_initialized = true;
- set_stationary_beacons_positions();
- break;
- }
- case AP_BEACON_MARVELMIND_POSITIONS_DATAGRAM_ID:
- {
- process_beacons_positions_datagram();
- beacon_position_initialized = true;
- set_stationary_beacons_positions();
- break;
- }
- case AP_BEACON_MARVELMIND_DISTANCES_DATAGRAM_ID:
- {
- process_beacons_distances_datagram();
- break;
- }
- case AP_BEACON_MARVELMIND_POSITION_DATAGRAM_HIGHRES_ID:
- {
- process_position_highres_datagram();
- vehicle_position_initialized = true;
- set_stationary_beacons_positions();
- break;
- }
- case AP_BEACON_MARVELMIND_POSITIONS_DATAGRAM_HIGHRES_ID:
- {
- process_beacons_positions_highres_datagram();
- beacon_position_initialized = true;
- set_stationary_beacons_positions();
- break;
- }
- }
- }
- // and repeat
- parse_state = RECV_HDR;
- num_bytes_in_block_received = 0;
- }
- break;
- }
- }
- }
- bool AP_Beacon_Marvelmind::healthy()
- {
- // healthy if we have parsed a message within the past 300ms
- return ((AP_HAL::millis() - last_update_ms) < AP_BEACON_TIMEOUT_MS);
- }
- void AP_Beacon_Marvelmind::set_stationary_beacons_positions()
- {
- bool set = false;
- if (vehicle_position_initialized && beacon_position_initialized) {
- if (hedge._have_new_values) {
- vehicle_position_NED__m = Vector3f(hedge.cur_position.y__mm * 0.001f,
- hedge.cur_position.x__mm * 0.001f,
- -hedge.cur_position.z__mm * 0.001f); //Transform Marvelmind ENU to Ardupilot NED
- //TODO: Calculate Accuracy of the received signal. Marvelmind *advertises* +/- 2cms
- // But we are conservative here and use 20cm instead (until MM provides us with a proper accuracy value)
- set_vehicle_position(vehicle_position_NED__m, 0.2f);
- set = true;
- Debug(2,
- "Hedge is at N%.2f, E%.2f, D%.2f",
- vehicle_position_NED__m[0],
- vehicle_position_NED__m[1],
- vehicle_position_NED__m[2]);
- }
- hedge._have_new_values = false;
- for (uint8_t i = 0; i < hedge.positions_beacons.num_beacons; ++i) {
- if (hedge.positions_beacons.updated) {
- beacon_position_NED__m[i] = Vector3f(hedge.positions_beacons.beacons[i].y__mm * 0.001f,
- hedge.positions_beacons.beacons[i].x__mm * 0.001f,
- -hedge.positions_beacons.beacons[i].z__mm * 0.001f); //Transform Marvelmind ENU to Ardupilot NED
- set_beacon_position(i, beacon_position_NED__m[i]);
- set = true;
- Debug(2,
- "Beacon %d is at N%.2f, E%.2f, D%.2f",
- i,
- beacon_position_NED__m[i][0],
- beacon_position_NED__m[i][1],
- beacon_position_NED__m[i][2]);
- }
- }
- hedge.positions_beacons.updated = false;
- }
- if (set) {
- last_update_ms = AP_HAL::millis();
- }
- }
- void AP_Beacon_Marvelmind::order_stationary_beacons()
- {
- if (hedge.positions_beacons.updated) {
- bool swapped = false;
- uint8_t j = hedge.positions_beacons.num_beacons;
- do
- {
- swapped = false;
- StationaryBeaconPosition beacon_to_swap;
- for (uint8_t i = 1; i < j; i++) {
- if (hedge.positions_beacons.beacons[i-1].address > hedge.positions_beacons.beacons[i].address) {
- beacon_to_swap = hedge.positions_beacons.beacons[i];
- hedge.positions_beacons.beacons[i] = hedge.positions_beacons.beacons[i-1];
- hedge.positions_beacons.beacons[i-1] = beacon_to_swap;
- swapped = true;
- }
- }
- j--;
- } while(swapped);
- }
- }
|