123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632 |
- #include "AC_Fence.h"
- #include <AP_AHRS/AP_AHRS.h>
- #include <AP_HAL/AP_HAL.h>
- extern const AP_HAL::HAL& hal;
- #if APM_BUILD_TYPE(APM_BUILD_APMrover2)
- #define AC_FENCE_TYPE_DEFAULT AC_FENCE_TYPE_CIRCLE | AC_FENCE_TYPE_POLYGON
- #else
- #define AC_FENCE_TYPE_DEFAULT AC_FENCE_TYPE_ALT_MAX | AC_FENCE_TYPE_CIRCLE | AC_FENCE_TYPE_POLYGON
- #endif
- const AP_Param::GroupInfo AC_Fence::var_info[] = {
-
-
-
-
-
- AP_GROUPINFO("ENABLE", 0, AC_Fence, _enabled, 0),
-
-
-
-
-
-
- AP_GROUPINFO("TYPE", 1, AC_Fence, _enabled_fences, AC_FENCE_TYPE_DEFAULT),
-
-
-
-
-
-
- AP_GROUPINFO("ACTION", 2, AC_Fence, _action, AC_FENCE_ACTION_RTL_AND_LAND),
-
-
-
-
-
-
-
- AP_GROUPINFO_FRAME("ALT_MAX", 3, AC_Fence, _alt_max, AC_FENCE_ALT_MAX_DEFAULT, AP_PARAM_FRAME_COPTER | AP_PARAM_FRAME_SUB | AP_PARAM_FRAME_TRICOPTER | AP_PARAM_FRAME_HELI),
-
-
-
-
-
-
- AP_GROUPINFO("RADIUS", 4, AC_Fence, _circle_radius, AC_FENCE_CIRCLE_RADIUS_DEFAULT),
-
-
-
-
-
-
- AP_GROUPINFO("MARGIN", 5, AC_Fence, _margin, AC_FENCE_MARGIN_DEFAULT),
-
-
-
-
-
- AP_GROUPINFO("TOTAL", 6, AC_Fence, _total, 0),
-
-
-
-
-
-
-
- AP_GROUPINFO_FRAME("ALT_MIN", 7, AC_Fence, _alt_min, AC_FENCE_ALT_MIN_DEFAULT, AP_PARAM_FRAME_SUB),
- AP_GROUPEND
- };
- AC_Fence::AC_Fence()
- {
- #if CONFIG_HAL_BOARD == HAL_BOARD_SITL
- if (_singleton != nullptr) {
- AP_HAL::panic("Fence must be singleton");
- }
- #endif
- _singleton = this;
- AP_Param::setup_object_defaults(this, var_info);
- }
- void AC_Fence::enable(bool value)
- {
- _enabled = value;
- if (!value) {
- clear_breach(AC_FENCE_TYPE_ALT_MAX | AC_FENCE_TYPE_CIRCLE | AC_FENCE_TYPE_POLYGON);
- }
- }
- uint8_t AC_Fence::get_enabled_fences() const
- {
- if (!_enabled) {
- return 0;
- }
- return _enabled_fences;
- }
- bool AC_Fence::pre_arm_check_polygon(const char* &fail_msg) const
- {
- if (!(_enabled_fences & AC_FENCE_TYPE_POLYGON)) {
-
- return true;
- }
- if (!_boundary_valid) {
- fail_msg = "Polygon boundary invalid";
- return false;
- }
- return true;
- }
- bool AC_Fence::pre_arm_check_circle(const char* &fail_msg) const
- {
- if (_circle_radius < 0) {
- fail_msg = "Invalid FENCE_RADIUS value";
- return false;
- }
- return true;
- }
- bool AC_Fence::pre_arm_check_alt(const char* &fail_msg) const
- {
- if (_alt_max < 0.0f) {
- fail_msg = "Invalid FENCE_ALT_MAX value";
- return false;
- }
- return true;
- }
- bool AC_Fence::pre_arm_check(const char* &fail_msg) const
- {
- fail_msg = nullptr;
-
- if (!_enabled || !_enabled_fences) {
- return true;
- }
-
- if (_breached_fences) {
- fail_msg = "vehicle outside fence";
- return false;
- }
-
-
- if ((_enabled_fences & AC_FENCE_TYPE_CIRCLE) ||
- (_enabled_fences & AC_FENCE_TYPE_POLYGON)) {
- Vector2f position;
- if (!AP::ahrs().get_relative_position_NE_home(position)) {
- fail_msg = "fence requires position";
- return false;
- }
- }
- if (!pre_arm_check_polygon(fail_msg)) {
- return false;
- }
- if (!pre_arm_check_circle(fail_msg)) {
- return false;
- }
- if (!pre_arm_check_alt(fail_msg)) {
- return false;
- }
-
- return true;
- }
- bool AC_Fence::check_fence_alt_max()
- {
-
- if (!(_enabled_fences & AC_FENCE_TYPE_ALT_MAX)) {
-
- return false;
- }
- AP::ahrs().get_relative_position_D_home(_curr_alt);
- _curr_alt = -_curr_alt;
-
- if(_curr_alt >= _alt_max) {
-
- _alt_max_breach_distance = _curr_alt - _alt_max;
-
- if (!(_breached_fences & AC_FENCE_TYPE_ALT_MAX) ||
- (!is_zero(_alt_max_backup) && _curr_alt >= _alt_max_backup)) {
-
- record_breach(AC_FENCE_TYPE_ALT_MAX);
-
- _alt_max_backup = _curr_alt + AC_FENCE_ALT_MAX_BACKUP_DISTANCE;
-
- return true;
- }
-
- return false;
- }
-
-
- if ((_breached_fences & AC_FENCE_TYPE_ALT_MAX) != 0) {
- clear_breach(AC_FENCE_TYPE_ALT_MAX);
- _alt_max_backup = 0.0f;
- _alt_max_breach_distance = 0.0f;
- }
- return false;
- }
- bool AC_Fence::check_fence_polygon()
- {
- const bool was_breached = _breached_fences & AC_FENCE_TYPE_POLYGON;
- const bool breached = polygon_fence_is_breached();
- if (breached) {
- if (!was_breached) {
- record_breach(AC_FENCE_TYPE_POLYGON);
- return true;
- }
- return false;
- }
- if (was_breached) {
- clear_breach(AC_FENCE_TYPE_POLYGON);
- }
- return false;
- }
- bool AC_Fence::polygon_fence_is_breached()
- {
- if (!(_enabled_fences & AC_FENCE_TYPE_POLYGON)) {
-
- return false;
- }
-
- if (_boundary_num_points != _total) {
-
- load_polygon_from_eeprom();
- return false;
- }
- if (!_boundary_valid) {
-
- return false;
- }
-
- Vector2f position;
- if (!AP::ahrs().get_relative_position_NE_origin(position)) {
-
- return false;
- }
- position = position * 100.0f;
- return _poly_loader.boundary_breached(position, _boundary_num_points, _boundary);
- }
- bool AC_Fence::check_fence_circle()
- {
- if (!(_enabled_fences & AC_FENCE_TYPE_CIRCLE)) {
-
- return false;
- }
- Vector2f home;
- if (AP::ahrs().get_relative_position_NE_home(home)) {
-
- _home_distance = home.length();
- }
-
- if (_home_distance >= _circle_radius) {
-
- _circle_breach_distance = _home_distance - _circle_radius;
-
- if (!(_breached_fences & AC_FENCE_TYPE_CIRCLE) ||
- (!is_zero(_circle_radius_backup) && _home_distance >= _circle_radius_backup)) {
-
-
- record_breach(AC_FENCE_TYPE_CIRCLE);
- _circle_radius_backup = _home_distance + AC_FENCE_CIRCLE_RADIUS_BACKUP_DISTANCE;
- return true;
- }
- return false;
- }
-
-
- if (_breached_fences & AC_FENCE_TYPE_CIRCLE) {
- clear_breach(AC_FENCE_TYPE_CIRCLE);
- _circle_radius_backup = 0.0f;
- _circle_breach_distance = 0.0f;
- }
- return false;
- }
- uint8_t AC_Fence::check()
- {
- uint8_t ret = 0;
-
- if (!_enabled || !_enabled_fences) {
- return 0;
- }
-
- if (_manual_recovery_start_ms != 0) {
-
- if ((AP_HAL::millis() - _manual_recovery_start_ms) < AC_FENCE_MANUAL_RECOVERY_TIME_MIN) {
- return 0;
- }
-
-
- _manual_recovery_start_ms = 0;
- }
-
- if (check_fence_alt_max()) {
- ret |= AC_FENCE_TYPE_ALT_MAX;
- }
-
- if (check_fence_circle()) {
- ret |= AC_FENCE_TYPE_CIRCLE;
- }
-
- if (check_fence_polygon()) {
- ret |= AC_FENCE_TYPE_POLYGON;
- }
-
- return ret;
- }
- bool AC_Fence::check_destination_within_fence(const Location& loc)
- {
-
- if ((get_enabled_fences() & AC_FENCE_TYPE_ALT_MAX)) {
- int32_t alt_above_home_cm;
- if (loc.get_alt_cm(Location::AltFrame::ABOVE_HOME, alt_above_home_cm)) {
- if ((alt_above_home_cm * 0.01f) > _alt_max) {
- return false;
- }
- }
- }
-
- if ((get_enabled_fences() & AC_FENCE_TYPE_CIRCLE)) {
- if (AP::ahrs().get_home().get_distance(loc) > _circle_radius) {
- return false;
- }
- }
-
- if ((get_enabled_fences() & AC_FENCE_TYPE_POLYGON) && _boundary_num_points > 0) {
-
- Vector2f posNE;
- if (loc.get_vector_xy_from_origin_NE(posNE)) {
- if (_poly_loader.boundary_breached(posNE, _boundary_num_points, _boundary)) {
- return false;
- }
- }
- }
- return true;
- }
- void AC_Fence::record_breach(uint8_t fence_type)
- {
-
- if (!_breached_fences) {
- _breach_time = AP_HAL::millis();
- }
-
- if (_breach_count < 65500) {
- _breach_count++;
- }
-
- _breached_fences |= fence_type;
- }
- void AC_Fence::clear_breach(uint8_t fence_type)
- {
- _breached_fences &= ~fence_type;
- }
- float AC_Fence::get_breach_distance(uint8_t fence_type) const
- {
- float max = 0.0f;
- if (fence_type & AC_FENCE_TYPE_ALT_MAX) {
- max = MAX(_alt_max_breach_distance, max);
- }
- if (fence_type & AC_FENCE_TYPE_CIRCLE) {
- max = MAX(_circle_breach_distance, max);
- }
- return max;
- }
- void AC_Fence::manual_recovery_start()
- {
-
- if (!_breached_fences) {
- return;
- }
-
- _manual_recovery_start_ms = AP_HAL::millis();
- }
- Vector2f* AC_Fence::get_boundary_points(uint16_t& num_points) const
- {
-
- if (_boundary == nullptr) {
- return nullptr;
- }
- if (!_boundary_valid) {
- return nullptr;
- }
-
-
-
- if (_boundary_num_points < 2) {
- return nullptr;
- }
- num_points = _boundary_num_points - 2;
- return &_boundary[1];
- }
- bool AC_Fence::boundary_breached(const Vector2f& location, uint16_t num_points, const Vector2f* points) const
- {
- return _poly_loader.boundary_breached(location, num_points, points);
- }
- void AC_Fence::handle_msg(GCS_MAVLINK &link, const mavlink_message_t &msg)
- {
- switch (msg.msgid) {
-
- case MAVLINK_MSG_ID_FENCE_POINT: {
- mavlink_fence_point_t packet;
- mavlink_msg_fence_point_decode(&msg, &packet);
- if (!check_latlng(packet.lat,packet.lng)) {
- link.send_text(MAV_SEVERITY_WARNING, "Invalid fence point, lat or lng too large");
- } else {
- Vector2l point;
- point.x = packet.lat*1.0e7f;
- point.y = packet.lng*1.0e7f;
- if (!_poly_loader.save_point_to_eeprom(packet.idx, point)) {
- link.send_text(MAV_SEVERITY_WARNING, "Failed to save polygon point, too many points?");
- } else {
-
- _boundary_num_points = 0;
- }
- }
- break;
- }
-
- case MAVLINK_MSG_ID_FENCE_FETCH_POINT: {
- mavlink_fence_fetch_point_t packet;
- mavlink_msg_fence_fetch_point_decode(&msg, &packet);
-
- Vector2l point;
- if (_poly_loader.load_point_from_eeprom(packet.idx, point)) {
- mavlink_msg_fence_point_send(link.get_chan(), msg.sysid, msg.compid, packet.idx, _total, point.x*1.0e-7f, point.y*1.0e-7f);
- } else {
- link.send_text(MAV_SEVERITY_WARNING, "Bad fence point");
- }
- break;
- }
- default:
-
- break;
- }
- }
- bool AC_Fence::load_polygon_from_eeprom()
- {
-
- if (!_boundary_create_attempted) {
- _boundary = (Vector2f *)_poly_loader.create_point_array(sizeof(Vector2f));
- _boundary_create_attempted = true;
- }
-
- if (_boundary == nullptr) {
- return false;
- }
-
- Location temp_loc;
- if (!AP::ahrs_navekf().get_location(temp_loc)) {
- return false;
- }
- struct Location ekf_origin {};
- if (!AP::ahrs().get_origin(ekf_origin)) {
- return false;
- }
-
- _total = constrain_int16(_total, 0, _poly_loader.max_points());
-
- Vector2l temp_latlon;
- for (uint16_t index=0; index<_total; index++) {
-
- if (!_poly_loader.load_point_from_eeprom(index, temp_latlon)) {
- return false;
- }
-
- temp_loc.lat = temp_latlon.x;
- temp_loc.lng = temp_latlon.y;
- _boundary[index] = ekf_origin.get_distance_NE(temp_loc) * 100.0f;
- }
- _boundary_num_points = _total;
- _boundary_update_ms = AP_HAL::millis();
-
- _boundary_valid = _poly_loader.boundary_valid(_boundary_num_points, _boundary);
- return true;
- }
- bool AC_Fence::sys_status_present() const
- {
- return _enabled;
- }
- bool AC_Fence::sys_status_enabled() const
- {
- if (!sys_status_present()) {
- return false;
- }
- if (_action == AC_FENCE_ACTION_REPORT_ONLY) {
- return false;
- }
- return true;
- }
- bool AC_Fence::sys_status_failed() const
- {
- if (!sys_status_present()) {
-
- return false;
- }
- if (get_breaches() != 0) {
- return true;
- }
- if (_enabled_fences & AC_FENCE_TYPE_POLYGON) {
- if (!_boundary_valid) {
- return true;
- }
- }
- if (_enabled_fences & AC_FENCE_TYPE_CIRCLE) {
- if (_circle_radius < 0) {
- return true;
- }
- }
- if (_enabled_fences & AC_FENCE_TYPE_ALT_MAX) {
- if (_alt_max < 0.0f) {
- return true;
- }
- }
- if ((_enabled_fences & AC_FENCE_TYPE_CIRCLE) ||
- (_enabled_fences & AC_FENCE_TYPE_POLYGON)) {
- Vector2f position;
- if (!AP::ahrs().get_relative_position_NE_home(position)) {
-
- return true;
- }
- }
- return false;
- }
- AC_Fence *AC_Fence::_singleton;
- namespace AP {
- AC_Fence *fence()
- {
- return AC_Fence::get_singleton();
- }
- }
|