/* * convert invalid waypoint with useful data. return true if location changed */ bool location_sanitize(const struct Location &defaultLoc, struct Location &loc) { bool has_changed = false; // convert lat/lng=0 to mean current point if (loc.lat == 0 && loc.lng == 0) { loc.lat = defaultLoc.lat; loc.lng = defaultLoc.lng; has_changed = true; } // convert relative alt=0 to mean current alt if (loc.alt == 0 && loc.flags.relative_alt) { loc.flags.relative_alt = false; loc.alt = defaultLoc.alt; has_changed = true; } // limit lat/lng to appropriate ranges if (!check_latlng(loc)) { loc.lat = defaultLoc.lat; loc.lng = defaultLoc.lng; has_changed = true; } return has_changed; }
MAV_RESULT GCS_MAVLINK_Sub::handle_command_do_set_roi(const Location &roi_loc) { if (!check_latlng(roi_loc)) { return MAV_RESULT_FAILED; } sub.set_auto_yaw_roi(roi_loc); return MAV_RESULT_ACCEPTED; }
// sets ahrs home to specified location // returns true if home location set successfully bool Rover::set_home(const Location& loc, bool lock) { // check location is valid if (loc.lat == 0 && loc.lng == 0 && loc.alt == 0) { return false; } if (!check_latlng(loc)) { return false; } // check if EKF origin has been set Location ekf_origin; if (!ahrs.get_origin(ekf_origin)) { return false; } // set ahrs home ahrs.set_home(loc); // init compass declination if (home_is_set == HOME_UNSET) { // record home is set home_is_set = HOME_SET_NOT_LOCKED; // log new home position which mission library will pull from ahrs if (should_log(MASK_LOG_CMD)) { AP_Mission::Mission_Command temp_cmd; if (mission.read_cmd_from_storage(0, temp_cmd)) { DataFlash.Log_Write_Mission_Cmd(mission, temp_cmd); } } } // lock home position if (lock) { home_is_set = HOME_SET_AND_LOCKED; } // Save Home to EEPROM mission.write_home_to_storage(); // log ahrs home and ekf origin dataflash Log_Write_Home_And_Origin(); // send new home and ekf origin to GCS gcs().send_home(loc); gcs().send_ekf_origin(loc); // send text of home position to ground stations gcs().send_text(MAV_SEVERITY_INFO, "Set HOME to %.6f %.6f at %.2fm", static_cast<double>(loc.lat * 1.0e-7f), static_cast<double>(loc.lng * 1.0e-7f), static_cast<double>(loc.alt * 0.01f)); // return success return true; }
MAV_RESULT GCS_MAVLINK_Sub::handle_command_int_packet(const mavlink_command_int_t &packet) { switch (packet.command) { case MAV_CMD_DO_SET_HOME: { // assume failure if (is_equal(packet.param1, 1.0f)) { // if param1 is 1, use current location if (sub.set_home_to_current_location(true)) { return MAV_RESULT_ACCEPTED; } return MAV_RESULT_FAILED; } // ensure param1 is zero if (!is_zero(packet.param1)) { return MAV_RESULT_FAILED; } // check frame type is supported if (packet.frame != MAV_FRAME_GLOBAL && packet.frame != MAV_FRAME_GLOBAL_INT && packet.frame != MAV_FRAME_GLOBAL_RELATIVE_ALT && packet.frame != MAV_FRAME_GLOBAL_RELATIVE_ALT_INT) { return MAV_RESULT_FAILED; } // sanity check location if (!check_latlng(packet.x, packet.y)) { return MAV_RESULT_FAILED; } Location new_home_loc {}; new_home_loc.lat = packet.x; new_home_loc.lng = packet.y; new_home_loc.alt = packet.z * 100; // handle relative altitude if (packet.frame == MAV_FRAME_GLOBAL_RELATIVE_ALT || packet.frame == MAV_FRAME_GLOBAL_RELATIVE_ALT_INT) { if (!AP::ahrs().home_is_set()) { // cannot use relative altitude if home is not set return MAV_RESULT_FAILED; } new_home_loc.alt += sub.ahrs.get_home().alt; } if (sub.set_home(new_home_loc, true)) { return MAV_RESULT_ACCEPTED; } return MAV_RESULT_FAILED; } default: return GCS_MAVLINK::handle_command_int_packet(packet); } }
/// handler for polygon fence messages with GCS void AC_Fence::handle_msg(mavlink_channel_t chan, mavlink_message_t* msg) { // exit immediately if null message if (msg == nullptr) { return; } switch (msg->msgid) { // receive a fence point from GCS and store in EEPROM 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)) { GCS_MAVLINK::send_statustext_chan(MAV_SEVERITY_WARNING, chan, "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)) { GCS_MAVLINK::send_statustext_chan(MAV_SEVERITY_WARNING, chan, "Failed to save polygon point, too many points?"); } else { // trigger reload of points _boundary_loaded = false; } } break; } // send a fence point to GCS case MAVLINK_MSG_ID_FENCE_FETCH_POINT: { mavlink_fence_fetch_point_t packet; mavlink_msg_fence_fetch_point_decode(msg, &packet); // attempt to retrieve from eeprom Vector2l point; if (_poly_loader.load_point_from_eeprom(packet.idx, point)) { mavlink_msg_fence_point_send_buf(msg, chan, msg->sysid, msg->compid, packet.idx, _total, point.x*1.0e-7f, point.y*1.0e-7f); } else { GCS_MAVLINK::send_statustext_chan(MAV_SEVERITY_WARNING, chan, "Bad fence point"); } break; } default: // do nothing break; } }
// sets ahrs home to specified location // returns true if home location set successfully bool Rover::set_home(const Location& loc, bool lock) { // check location is valid if (loc.lat == 0 && loc.lng == 0 && loc.alt == 0) { return false; } if (!check_latlng(loc)) { return false; } const bool home_was_set = ahrs.home_is_set(); // set ahrs home ahrs.set_home(loc); if (!home_was_set) { // log new home position which mission library will pull from ahrs if (should_log(MASK_LOG_CMD)) { AP_Mission::Mission_Command temp_cmd; if (mode_auto.mission.read_cmd_from_storage(0, temp_cmd)) { logger.Write_Mission_Cmd(mode_auto.mission, temp_cmd); } } } // lock home position if (lock) { ahrs.lock_home(); } // Save Home to EEPROM mode_auto.mission.write_home_to_storage(); // send text of home position to ground stations gcs().send_text(MAV_SEVERITY_INFO, "Set HOME to %.6f %.6f at %.2fm", static_cast<double>(loc.lat * 1.0e-7f), static_cast<double>(loc.lng * 1.0e-7f), static_cast<double>(loc.alt * 0.01f)); // return success return true; }
// sets ekf_origin if it has not been set. // should only be used when there is no GPS to provide an absolute position void Rover::set_ekf_origin(const Location& loc) { // check location is valid if (!check_latlng(loc)) { return; } // check if EKF origin has already been set Location ekf_origin; if (ahrs.get_origin(ekf_origin)) { return; } if (!ahrs.set_origin(loc)) { return; } // log ahrs home and ekf origin dataflash Log_Write_Home_And_Origin(); // send ekf origin to GCS gcs().send_ekf_origin(loc); }
MAV_RESULT GCS_MAVLINK_Rover::handle_command_int_packet(const mavlink_command_int_t &packet) { switch (packet.command) { case MAV_CMD_DO_CHANGE_SPEED: // param1 : unused // param2 : new speed in m/s if (!rover.control_mode->set_desired_speed(packet.param2)) { return MAV_RESULT_FAILED; } return MAV_RESULT_ACCEPTED; case MAV_CMD_DO_SET_HOME: { // assume failure if (is_equal(packet.param1, 1.0f)) { // if param1 is 1, use current location if (rover.set_home_to_current_location(true)) { return MAV_RESULT_ACCEPTED; } return MAV_RESULT_FAILED; } // ensure param1 is zero if (!is_zero(packet.param1)) { return MAV_RESULT_FAILED; } // check frame type is supported if (packet.frame != MAV_FRAME_GLOBAL && packet.frame != MAV_FRAME_GLOBAL_INT && packet.frame != MAV_FRAME_GLOBAL_RELATIVE_ALT && packet.frame != MAV_FRAME_GLOBAL_RELATIVE_ALT_INT) { return MAV_RESULT_FAILED; } // sanity check location if (!check_latlng(packet.x, packet.y)) { return MAV_RESULT_FAILED; } Location new_home_loc {}; new_home_loc.lat = packet.x; new_home_loc.lng = packet.y; new_home_loc.alt = packet.z * 100; // handle relative altitude if (packet.frame == MAV_FRAME_GLOBAL_RELATIVE_ALT || packet.frame == MAV_FRAME_GLOBAL_RELATIVE_ALT_INT) { if (!rover.ahrs.home_is_set()) { // cannot use relative altitude if home is not set return MAV_RESULT_FAILED; } new_home_loc.alt += rover.ahrs.get_home().alt; } if (!rover.set_home(new_home_loc, true)) { return MAV_RESULT_FAILED; } return MAV_RESULT_ACCEPTED; } case MAV_CMD_DO_SET_REVERSE: // param1 : Direction (0=Forward, 1=Reverse) rover.control_mode->set_reversed(is_equal(packet.param1,1.0f)); return MAV_RESULT_ACCEPTED; #if MOUNT == ENABLED case MAV_CMD_DO_SET_ROI: { // param1 : /* Region of interest mode (not used)*/ // param2 : /* MISSION index/ target ID (not used)*/ // param3 : /* ROI index (not used)*/ // param4 : /* empty */ // x : lat // y : lon // z : alt // sanity check location if (!check_latlng(packet.x, packet.y)) { return MAV_RESULT_FAILED; } Location roi_loc; roi_loc.lat = packet.x; roi_loc.lng = packet.y; roi_loc.alt = (int32_t)(packet.z * 100.0f); if (roi_loc.lat == 0 && roi_loc.lng == 0 && roi_loc.alt == 0) { // switch off the camera tracking if enabled if (rover.camera_mount.get_mode() == MAV_MOUNT_MODE_GPS_POINT) { rover.camera_mount.set_mode_to_default(); } } else { // send the command to the camera mount rover.camera_mount.set_roi_target(roi_loc); } return MAV_RESULT_ACCEPTED; } #endif default: return GCS_MAVLINK::handle_command_int_packet(packet); } }
void GCS_MAVLINK_Rover::handleMessage(mavlink_message_t* msg) { switch (msg->msgid) { case MAVLINK_MSG_ID_REQUEST_DATA_STREAM: { handle_request_data_stream(msg, true); break; } case MAVLINK_MSG_ID_COMMAND_LONG: { // decode mavlink_command_long_t packet; mavlink_msg_command_long_decode(msg, &packet); uint8_t result = MAV_RESULT_UNSUPPORTED; // do command switch(packet.command) { case MAV_CMD_START_RX_PAIR: // initiate bind procedure if (!hal.rcin->rc_bind(packet.param1)) { result = MAV_RESULT_FAILED; } else { result = MAV_RESULT_ACCEPTED; } break; case MAV_CMD_NAV_RETURN_TO_LAUNCH: rover.set_mode(RTL); result = MAV_RESULT_ACCEPTED; break; #if MOUNT == ENABLED // Sets the region of interest (ROI) for the camera case MAV_CMD_DO_SET_ROI: // sanity check location if (!check_latlng(packet.param5, packet.param6)) { break; } Location roi_loc; roi_loc.lat = (int32_t)(packet.param5 * 1.0e7f); roi_loc.lng = (int32_t)(packet.param6 * 1.0e7f); roi_loc.alt = (int32_t)(packet.param7 * 100.0f); if (roi_loc.lat == 0 && roi_loc.lng == 0 && roi_loc.alt == 0) { // switch off the camera tracking if enabled if (rover.camera_mount.get_mode() == MAV_MOUNT_MODE_GPS_POINT) { rover.camera_mount.set_mode_to_default(); } } else { // send the command to the camera mount rover.camera_mount.set_roi_target(roi_loc); } result = MAV_RESULT_ACCEPTED; break; #endif #if CAMERA == ENABLED case MAV_CMD_DO_DIGICAM_CONFIGURE: rover.camera.configure(packet.param1, packet.param2, packet.param3, packet.param4, packet.param5, packet.param6, packet.param7); result = MAV_RESULT_ACCEPTED; break; case MAV_CMD_DO_DIGICAM_CONTROL: if (rover.camera.control(packet.param1, packet.param2, packet.param3, packet.param4, packet.param5, packet.param6)) { rover.log_picture(); } result = MAV_RESULT_ACCEPTED; break; #endif // CAMERA == ENABLED case MAV_CMD_DO_MOUNT_CONTROL: #if MOUNT == ENABLED rover.camera_mount.control(packet.param1, packet.param2, packet.param3, (MAV_MOUNT_MODE) packet.param7); result = MAV_RESULT_ACCEPTED; #endif break; case MAV_CMD_MISSION_START: rover.set_mode(AUTO); result = MAV_RESULT_ACCEPTED; break; case MAV_CMD_PREFLIGHT_CALIBRATION: if(hal.util->get_soft_armed()) { result = MAV_RESULT_FAILED; break; } if (is_equal(packet.param1,1.0f)) { rover.ins.init_gyro(); if (rover.ins.gyro_calibrated_ok_all()) { rover.ahrs.reset_gyro_drift(); result = MAV_RESULT_ACCEPTED; } else { result = MAV_RESULT_FAILED; } } else if (is_equal(packet.param3,1.0f)) { rover.init_barometer(false); result = MAV_RESULT_ACCEPTED; } else if (is_equal(packet.param4,1.0f)) { rover.trim_radio(); result = MAV_RESULT_ACCEPTED; } else if (is_equal(packet.param5,1.0f)) { result = MAV_RESULT_ACCEPTED; // start with gyro calibration rover.ins.init_gyro(); // reset ahrs gyro bias if (rover.ins.gyro_calibrated_ok_all()) { rover.ahrs.reset_gyro_drift(); } else { result = MAV_RESULT_FAILED; } rover.ins.acal_init(); rover.ins.get_acal()->start(this); } else if (is_equal(packet.param5,2.0f)) { // start with gyro calibration rover.ins.init_gyro(); // accel trim float trim_roll, trim_pitch; if(rover.ins.calibrate_trim(trim_roll, trim_pitch)) { // reset ahrs's trim to suggested values from calibration routine rover.ahrs.set_trim(Vector3f(trim_roll, trim_pitch, 0)); result = MAV_RESULT_ACCEPTED; } else { result = MAV_RESULT_FAILED; } } else { send_text(MAV_SEVERITY_WARNING, "Unsupported preflight calibration"); } break; case MAV_CMD_PREFLIGHT_SET_SENSOR_OFFSETS: { uint8_t compassNumber = -1; if (is_equal(packet.param1, 2.0f)) { compassNumber = 0; } else if (is_equal(packet.param1, 5.0f)) { compassNumber = 1; } else if (is_equal(packet.param1, 6.0f)) { compassNumber = 2; } if (compassNumber != (uint8_t) -1) { rover.compass.set_and_save_offsets(compassNumber, packet.param2, packet.param3, packet.param4); result = MAV_RESULT_ACCEPTED; } break; } case MAV_CMD_DO_SET_MODE: switch ((uint16_t)packet.param1) { case MAV_MODE_MANUAL_ARMED: case MAV_MODE_MANUAL_DISARMED: rover.set_mode(MANUAL); result = MAV_RESULT_ACCEPTED; break; case MAV_MODE_AUTO_ARMED: case MAV_MODE_AUTO_DISARMED: rover.set_mode(AUTO); result = MAV_RESULT_ACCEPTED; break; case MAV_MODE_STABILIZE_DISARMED: case MAV_MODE_STABILIZE_ARMED: rover.set_mode(LEARNING); result = MAV_RESULT_ACCEPTED; break; default: result = MAV_RESULT_UNSUPPORTED; } break; case MAV_CMD_DO_SET_SERVO: if (rover.ServoRelayEvents.do_set_servo(packet.param1, packet.param2)) { result = MAV_RESULT_ACCEPTED; } break; case MAV_CMD_DO_REPEAT_SERVO: if (rover.ServoRelayEvents.do_repeat_servo(packet.param1, packet.param2, packet.param3, packet.param4*1000)) { result = MAV_RESULT_ACCEPTED; } break; case MAV_CMD_DO_SET_RELAY: if (rover.ServoRelayEvents.do_set_relay(packet.param1, packet.param2)) { result = MAV_RESULT_ACCEPTED; } break; case MAV_CMD_DO_REPEAT_RELAY: if (rover.ServoRelayEvents.do_repeat_relay(packet.param1, packet.param2, packet.param3*1000)) { result = MAV_RESULT_ACCEPTED; } break; case MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN: if (is_equal(packet.param1,1.0f) || is_equal(packet.param1,3.0f)) { // when packet.param1 == 3 we reboot to hold in bootloader hal.scheduler->reboot(is_equal(packet.param1,3.0f)); result = MAV_RESULT_ACCEPTED; } break; case MAV_CMD_COMPONENT_ARM_DISARM: if (is_equal(packet.param1,1.0f)) { // run pre_arm_checks and arm_checks and display failures if (rover.arm_motors(AP_Arming::MAVLINK)) { result = MAV_RESULT_ACCEPTED; } else { result = MAV_RESULT_FAILED; } } else if (is_zero(packet.param1)) { if (rover.disarm_motors()) { result = MAV_RESULT_ACCEPTED; } else { result = MAV_RESULT_FAILED; } } else { result = MAV_RESULT_UNSUPPORTED; } break; case MAV_CMD_GET_HOME_POSITION: if (rover.home_is_set != HOME_UNSET) { send_home(rover.ahrs.get_home()); result = MAV_RESULT_ACCEPTED; } break; case MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES: { if (is_equal(packet.param1,1.0f)) { send_autopilot_version(FIRMWARE_VERSION); result = MAV_RESULT_ACCEPTED; } break; } case MAV_CMD_DO_SET_HOME: { // param1 : use current (1=use current location, 0=use specified location) // param5 : latitude // param6 : longitude // param7 : altitude result = MAV_RESULT_FAILED; // assume failure if (is_equal(packet.param1,1.0f)) { rover.init_home(); } else { if (is_zero(packet.param5) && is_zero(packet.param6) && is_zero(packet.param7)) { // don't allow the 0,0 position break; } // sanity check location if (!check_latlng(packet.param5, packet.param6)) { break; } Location new_home_loc {}; new_home_loc.lat = (int32_t)(packet.param5 * 1.0e7f); new_home_loc.lng = (int32_t)(packet.param6 * 1.0e7f); new_home_loc.alt = (int32_t)(packet.param7 * 100.0f); rover.ahrs.set_home(new_home_loc); rover.home_is_set = HOME_SET_NOT_LOCKED; rover.Log_Write_Home_And_Origin(); GCS_MAVLINK::send_home_all(new_home_loc); result = MAV_RESULT_ACCEPTED; rover.gcs_send_text_fmt(MAV_SEVERITY_INFO, "Set HOME to %.6f %.6f at %um", (double)(new_home_loc.lat*1.0e-7f), (double)(new_home_loc.lng*1.0e-7f), (uint32_t)(new_home_loc.alt*0.01f)); } break; } case MAV_CMD_DO_START_MAG_CAL: case MAV_CMD_DO_ACCEPT_MAG_CAL: case MAV_CMD_DO_CANCEL_MAG_CAL: result = rover.compass.handle_mag_cal_command(packet); break; default: break; } mavlink_msg_command_ack_send_buf( msg, chan, packet.command, result); break; } case MAVLINK_MSG_ID_SET_MODE: { handle_set_mode(msg, FUNCTOR_BIND(&rover, &Rover::mavlink_set_mode, bool, uint8_t)); break; } case MAVLINK_MSG_ID_MISSION_REQUEST_LIST: { handle_mission_request_list(rover.mission, msg); break; } // XXX read a WP from EEPROM and send it to the GCS case MAVLINK_MSG_ID_MISSION_REQUEST_INT: case MAVLINK_MSG_ID_MISSION_REQUEST: { handle_mission_request(rover.mission, msg); break; } case MAVLINK_MSG_ID_MISSION_ACK: { // not used break; } case MAVLINK_MSG_ID_PARAM_REQUEST_LIST: { // mark the firmware version in the tlog send_text(MAV_SEVERITY_INFO, FIRMWARE_STRING); #if defined(PX4_GIT_VERSION) && defined(NUTTX_GIT_VERSION) send_text(MAV_SEVERITY_INFO, "PX4: " PX4_GIT_VERSION " NuttX: " NUTTX_GIT_VERSION); #endif handle_param_request_list(msg); break; } case MAVLINK_MSG_ID_PARAM_REQUEST_READ: { handle_param_request_read(msg); break; } case MAVLINK_MSG_ID_MISSION_CLEAR_ALL: { handle_mission_clear_all(rover.mission, msg); break; } case MAVLINK_MSG_ID_MISSION_SET_CURRENT: { handle_mission_set_current(rover.mission, msg); break; } case MAVLINK_MSG_ID_MISSION_COUNT: { handle_mission_count(rover.mission, msg); break; } case MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST: { handle_mission_write_partial_list(rover.mission, msg); break; } // GCS has sent us a mission item, store to EEPROM case MAVLINK_MSG_ID_MISSION_ITEM: { if (handle_mission_item(msg, rover.mission)) { rover.DataFlash.Log_Write_EntireMission(rover.mission); } break; } case MAVLINK_MSG_ID_MISSION_ITEM_INT: { if (handle_mission_item(msg, rover.mission)) { rover.DataFlash.Log_Write_EntireMission(rover.mission); } break; } case MAVLINK_MSG_ID_PARAM_SET: { handle_param_set(msg, &rover.DataFlash); break; } case MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE: { // allow override of RC channel values for HIL // or for complete GCS control of switch position // and RC PWM values. if(msg->sysid != rover.g.sysid_my_gcs) break; // Only accept control from our gcs mavlink_rc_channels_override_t packet; int16_t v[8]; mavlink_msg_rc_channels_override_decode(msg, &packet); v[0] = packet.chan1_raw; v[1] = packet.chan2_raw; v[2] = packet.chan3_raw; v[3] = packet.chan4_raw; v[4] = packet.chan5_raw; v[5] = packet.chan6_raw; v[6] = packet.chan7_raw; v[7] = packet.chan8_raw; hal.rcin->set_overrides(v, 8); rover.failsafe.rc_override_timer = AP_HAL::millis(); rover.failsafe_trigger(FAILSAFE_EVENT_RC, false); break; } case MAVLINK_MSG_ID_HEARTBEAT: { // We keep track of the last time we received a heartbeat from our GCS for failsafe purposes if(msg->sysid != rover.g.sysid_my_gcs) break; rover.last_heartbeat_ms = rover.failsafe.rc_override_timer = AP_HAL::millis(); rover.failsafe_trigger(FAILSAFE_EVENT_GCS, false); break; } case MAVLINK_MSG_ID_GPS_INPUT: { rover.gps.handle_msg(msg); break; } #if HIL_MODE != HIL_MODE_DISABLED case MAVLINK_MSG_ID_HIL_STATE: { mavlink_hil_state_t packet; mavlink_msg_hil_state_decode(msg, &packet); // sanity check location if (!check_latlng(packet.lat, packet.lon)) { break; } // set gps hil sensor Location loc; loc.lat = packet.lat; loc.lng = packet.lon; loc.alt = packet.alt/10; Vector3f vel(packet.vx, packet.vy, packet.vz); vel *= 0.01f; gps.setHIL(0, AP_GPS::GPS_OK_FIX_3D, packet.time_usec/1000, loc, vel, 10, 0); // rad/sec Vector3f gyros; gyros.x = packet.rollspeed; gyros.y = packet.pitchspeed; gyros.z = packet.yawspeed; // m/s/s Vector3f accels; accels.x = packet.xacc * (GRAVITY_MSS/1000.0f); accels.y = packet.yacc * (GRAVITY_MSS/1000.0f); accels.z = packet.zacc * (GRAVITY_MSS/1000.0f); ins.set_gyro(0, gyros); ins.set_accel(0, accels); compass.setHIL(0, packet.roll, packet.pitch, packet.yaw); compass.setHIL(1, packet.roll, packet.pitch, packet.yaw); break; } #endif // HIL_MODE #if CAMERA == ENABLED //deprecated. Use MAV_CMD_DO_DIGICAM_CONFIGURE case MAVLINK_MSG_ID_DIGICAM_CONFIGURE: { break; } //deprecated. Use MAV_CMD_DO_DIGICAM_CONFIGURE case MAVLINK_MSG_ID_DIGICAM_CONTROL: { rover.camera.control_msg(msg); rover.log_picture(); break; } #endif // CAMERA == ENABLED #if MOUNT == ENABLED //deprecated. Use MAV_CMD_DO_MOUNT_CONFIGURE case MAVLINK_MSG_ID_MOUNT_CONFIGURE: { rover.camera_mount.configure_msg(msg); break; } //deprecated. Use MAV_CMD_DO_MOUNT_CONTROL case MAVLINK_MSG_ID_MOUNT_CONTROL: { rover.camera_mount.control_msg(msg); break; } #endif // MOUNT == ENABLED case MAVLINK_MSG_ID_RADIO: case MAVLINK_MSG_ID_RADIO_STATUS: { handle_radio_status(msg, rover.DataFlash, rover.should_log(MASK_LOG_PM)); break; } case MAVLINK_MSG_ID_LOG_REQUEST_DATA: case MAVLINK_MSG_ID_LOG_ERASE: rover.in_log_download = true; /* no break */ case MAVLINK_MSG_ID_LOG_REQUEST_LIST: if (!rover.in_mavlink_delay) { handle_log_message(msg, rover.DataFlash); } break; case MAVLINK_MSG_ID_LOG_REQUEST_END: rover.in_log_download = false; if (!rover.in_mavlink_delay) { handle_log_message(msg, rover.DataFlash); } break; case MAVLINK_MSG_ID_SERIAL_CONTROL: handle_serial_control(msg, rover.gps); break; case MAVLINK_MSG_ID_GPS_INJECT_DATA: handle_gps_inject(msg, rover.gps); break; case MAVLINK_MSG_ID_DISTANCE_SENSOR: rover.sonar.handle_msg(msg); break; case MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS: rover.DataFlash.remote_log_block_status_msg(chan, msg); break; case MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST: send_autopilot_version(FIRMWARE_VERSION); break; case MAVLINK_MSG_ID_SETUP_SIGNING: handle_setup_signing(msg); break; case MAVLINK_MSG_ID_LED_CONTROL: // send message to Notify AP_Notify::handle_led_control(msg); break; case MAVLINK_MSG_ID_PLAY_TUNE: // send message to Notify AP_Notify::handle_play_tune(msg); break; } // end switch } // end handle mavlink
MAV_RESULT GCS_MAVLINK_Rover::handle_command_int_packet(const mavlink_command_int_t &packet) { switch (packet.command) { case MAV_CMD_DO_CHANGE_SPEED: // param1 : unused // param2 : new speed in m/s if (!rover.control_mode->set_desired_speed(packet.param2)) { return MAV_RESULT_FAILED; } return MAV_RESULT_ACCEPTED; case MAV_CMD_DO_SET_HOME: { // assume failure if (is_equal(packet.param1, 1.0f)) { // if param1 is 1, use current location if (rover.set_home_to_current_location(true)) { return MAV_RESULT_ACCEPTED; } return MAV_RESULT_FAILED; } // ensure param1 is zero if (!is_zero(packet.param1)) { return MAV_RESULT_FAILED; } // check frame type is supported if (packet.frame != MAV_FRAME_GLOBAL && packet.frame != MAV_FRAME_GLOBAL_INT && packet.frame != MAV_FRAME_GLOBAL_RELATIVE_ALT && packet.frame != MAV_FRAME_GLOBAL_RELATIVE_ALT_INT) { return MAV_RESULT_FAILED; } // sanity check location if (!check_latlng(packet.x, packet.y)) { return MAV_RESULT_FAILED; } Location new_home_loc {}; new_home_loc.lat = packet.x; new_home_loc.lng = packet.y; new_home_loc.alt = packet.z * 100; // handle relative altitude if (packet.frame == MAV_FRAME_GLOBAL_RELATIVE_ALT || packet.frame == MAV_FRAME_GLOBAL_RELATIVE_ALT_INT) { if (!rover.ahrs.home_is_set()) { // cannot use relative altitude if home is not set return MAV_RESULT_FAILED; } new_home_loc.alt += rover.ahrs.get_home().alt; } if (!rover.set_home(new_home_loc, true)) { return MAV_RESULT_FAILED; } return MAV_RESULT_ACCEPTED; } case MAV_CMD_DO_SET_REVERSE: // param1 : Direction (0=Forward, 1=Reverse) rover.control_mode->set_reversed(is_equal(packet.param1,1.0f)); return MAV_RESULT_ACCEPTED; default: return GCS_MAVLINK::handle_command_int_packet(packet); } }
void GCS_MAVLINK_Plane::handleMessage(mavlink_message_t* msg) { switch (msg->msgid) { #if GEOFENCE_ENABLED == ENABLED // receive a fence point from GCS and store in EEPROM case MAVLINK_MSG_ID_FENCE_POINT: { mavlink_fence_point_t packet; mavlink_msg_fence_point_decode(msg, &packet); if (plane.g.fence_action != FENCE_ACTION_NONE) { send_text(MAV_SEVERITY_WARNING,"Fencing must be disabled"); } else if (packet.count != plane.g.fence_total) { send_text(MAV_SEVERITY_WARNING,"Bad fence point"); } else if (!check_latlng(packet.lat,packet.lng)) { send_text(MAV_SEVERITY_WARNING,"Invalid fence point, lat or lng too large"); } else { plane.set_fence_point_with_index(Vector2l(packet.lat*1.0e7f, packet.lng*1.0e7f), packet.idx); } break; } // send a fence point to GCS case MAVLINK_MSG_ID_FENCE_FETCH_POINT: { mavlink_fence_fetch_point_t packet; mavlink_msg_fence_fetch_point_decode(msg, &packet); if (packet.idx >= plane.g.fence_total) { send_text(MAV_SEVERITY_WARNING,"Bad fence point"); } else { Vector2l point = plane.get_fence_point_with_index(packet.idx); mavlink_msg_fence_point_send_buf(msg, chan, msg->sysid, msg->compid, packet.idx, plane.g.fence_total, point.x*1.0e-7f, point.y*1.0e-7f); } break; } #endif // GEOFENCE_ENABLED case MAVLINK_MSG_ID_MANUAL_CONTROL: { if (msg->sysid != plane.g.sysid_my_gcs) { break; // only accept control from our gcs } mavlink_manual_control_t packet; mavlink_msg_manual_control_decode(msg, &packet); if (packet.target != plane.g.sysid_this_mav) { break; // only accept messages aimed at us } uint32_t tnow = AP_HAL::millis(); manual_override(plane.channel_roll, packet.y, 1000, 2000, tnow); manual_override(plane.channel_pitch, packet.x, 1000, 2000, tnow, true); manual_override(plane.channel_throttle, packet.z, 0, 1000, tnow); manual_override(plane.channel_rudder, packet.r, 1000, 2000, tnow); // a manual control message is considered to be a 'heartbeat' from the ground station for failsafe purposes plane.failsafe.last_heartbeat_ms = tnow; break; } case MAVLINK_MSG_ID_HEARTBEAT: { // We keep track of the last time we received a heartbeat from // our GCS for failsafe purposes if (msg->sysid != plane.g.sysid_my_gcs) break; plane.failsafe.last_heartbeat_ms = AP_HAL::millis(); break; } case MAVLINK_MSG_ID_HIL_STATE: { #if HIL_SUPPORT if (plane.g.hil_mode != 1) { break; } mavlink_hil_state_t packet; mavlink_msg_hil_state_decode(msg, &packet); // sanity check location if (!check_latlng(packet.lat, packet.lon)) { break; } last_hil_state = packet; // set gps hil sensor const Location loc{packet.lat, packet.lon, packet.alt/10, Location::AltFrame::ABSOLUTE}; Vector3f vel(packet.vx, packet.vy, packet.vz); vel *= 0.01f; // setup airspeed pressure based on 3D speed, no wind plane.airspeed.setHIL(sq(vel.length()) / 2.0f + 2013); plane.gps.setHIL(0, AP_GPS::GPS_OK_FIX_3D, packet.time_usec/1000, loc, vel, 10, 0); // rad/sec Vector3f gyros; gyros.x = packet.rollspeed; gyros.y = packet.pitchspeed; gyros.z = packet.yawspeed; // m/s/s Vector3f accels; accels.x = packet.xacc * GRAVITY_MSS*0.001f; accels.y = packet.yacc * GRAVITY_MSS*0.001f; accels.z = packet.zacc * GRAVITY_MSS*0.001f; plane.ins.set_gyro(0, gyros); plane.ins.set_accel(0, accels); plane.barometer.setHIL(packet.alt*0.001f); plane.compass.setHIL(0, packet.roll, packet.pitch, packet.yaw); plane.compass.setHIL(1, packet.roll, packet.pitch, packet.yaw); // cope with DCM getting badly off due to HIL lag if (plane.g.hil_err_limit > 0 && (fabsf(packet.roll - plane.ahrs.roll) > ToRad(plane.g.hil_err_limit) || fabsf(packet.pitch - plane.ahrs.pitch) > ToRad(plane.g.hil_err_limit) || wrap_PI(fabsf(packet.yaw - plane.ahrs.yaw)) > ToRad(plane.g.hil_err_limit))) { plane.ahrs.reset_attitude(packet.roll, packet.pitch, packet.yaw); } #endif break; } case MAVLINK_MSG_ID_RADIO: case MAVLINK_MSG_ID_RADIO_STATUS: { handle_radio_status(msg, plane.should_log(MASK_LOG_PM)); break; } case MAVLINK_MSG_ID_DISTANCE_SENSOR: plane.rangefinder.handle_msg(msg); break; case MAVLINK_MSG_ID_TERRAIN_DATA: case MAVLINK_MSG_ID_TERRAIN_CHECK: #if AP_TERRAIN_AVAILABLE plane.terrain.handle_data(chan, msg); #endif break; case MAVLINK_MSG_ID_SET_ATTITUDE_TARGET: { // Only allow companion computer (or other external controller) to // control attitude in GUIDED mode. We DON'T want external control // in e.g., RTL, CICLE. Specifying a single mode for companion // computer control is more safe (even more so when using // FENCE_ACTION = 4 for geofence failures). if ((plane.control_mode != &plane.mode_guided) && (plane.control_mode != &plane.mode_avoidADSB)) { // don't screw up failsafes break; } mavlink_set_attitude_target_t att_target; mavlink_msg_set_attitude_target_decode(msg, &att_target); // Mappings: If any of these bits are set, the corresponding input should be ignored. // NOTE, when parsing the bits we invert them for easier interpretation but transport has them inverted // bit 1: body roll rate // bit 2: body pitch rate // bit 3: body yaw rate // bit 4: unknown // bit 5: unknown // bit 6: reserved // bit 7: throttle // bit 8: attitude // if not setting all Quaternion values, use _rate flags to indicate which fields. // Extract the Euler roll angle from the Quaternion. Quaternion q(att_target.q[0], att_target.q[1], att_target.q[2], att_target.q[3]); // NOTE: att_target.type_mask is inverted for easier interpretation att_target.type_mask = att_target.type_mask ^ 0xFF; uint8_t attitude_mask = att_target.type_mask & 0b10000111; // q plus rpy uint32_t now = AP_HAL::millis(); if ((attitude_mask & 0b10000001) || // partial, including roll (attitude_mask == 0b10000000)) { // all angles plane.guided_state.forced_rpy_cd.x = degrees(q.get_euler_roll()) * 100.0f; // Update timer for external roll to the nav control plane.guided_state.last_forced_rpy_ms.x = now; } if ((attitude_mask & 0b10000010) || // partial, including pitch (attitude_mask == 0b10000000)) { // all angles plane.guided_state.forced_rpy_cd.y = degrees(q.get_euler_pitch()) * 100.0f; // Update timer for external pitch to the nav control plane.guided_state.last_forced_rpy_ms.y = now; } if ((attitude_mask & 0b10000100) || // partial, including yaw (attitude_mask == 0b10000000)) { // all angles plane.guided_state.forced_rpy_cd.z = degrees(q.get_euler_yaw()) * 100.0f; // Update timer for external yaw to the nav control plane.guided_state.last_forced_rpy_ms.z = now; } if (att_target.type_mask & 0b01000000) { // throttle plane.guided_state.forced_throttle = att_target.thrust * 100.0f; // Update timer for external throttle plane.guided_state.last_forced_throttle_ms = now; } break; } case MAVLINK_MSG_ID_SET_HOME_POSITION: { mavlink_set_home_position_t packet; mavlink_msg_set_home_position_decode(msg, &packet); Location new_home_loc {}; new_home_loc.lat = packet.latitude; new_home_loc.lng = packet.longitude; new_home_loc.alt = packet.altitude / 10; if (!set_home(new_home_loc, false)) { // silently fails... break; } break; } case MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED: { // decode packet mavlink_set_position_target_local_ned_t packet; mavlink_msg_set_position_target_local_ned_decode(msg, &packet); // exit if vehicle is not in Guided mode if (plane.control_mode != &plane.mode_guided) { break; } // only local moves for now if (packet.coordinate_frame != MAV_FRAME_LOCAL_OFFSET_NED) { break; } // just do altitude for now plane.next_WP_loc.alt += -packet.z*100.0; gcs().send_text(MAV_SEVERITY_INFO, "Change alt to %.1f", (double)((plane.next_WP_loc.alt - plane.home.alt)*0.01)); break; } case MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT: { // Only want to allow companion computer position control when // in a certain mode to avoid inadvertently sending these // kinds of commands when the autopilot is responding to problems // in modes such as RTL, CIRCLE, etc. Specifying ONLY one mode // for companion computer control is more safe (provided // one uses the FENCE_ACTION = 4 (RTL) for geofence failures). if (plane.control_mode != &plane.mode_guided && plane.control_mode != &plane.mode_avoidADSB) { //don't screw up failsafes break; } mavlink_set_position_target_global_int_t pos_target; mavlink_msg_set_position_target_global_int_decode(msg, &pos_target); // Unexpectedly, the mask is expecting "ones" for dimensions that should // be IGNORNED rather than INCLUDED. See mavlink documentation of the // SET_POSITION_TARGET_GLOBAL_INT message, type_mask field. const uint16_t alt_mask = 0b1111111111111011; // (z mask at bit 3) bool msg_valid = true; AP_Mission::Mission_Command cmd = {0}; if (pos_target.type_mask & alt_mask) { cmd.content.location.alt = pos_target.alt * 100; cmd.content.location.relative_alt = false; cmd.content.location.terrain_alt = false; switch (pos_target.coordinate_frame) { case MAV_FRAME_GLOBAL_INT: break; //default to MSL altitude case MAV_FRAME_GLOBAL_RELATIVE_ALT_INT: cmd.content.location.relative_alt = true; break; case MAV_FRAME_GLOBAL_TERRAIN_ALT_INT: cmd.content.location.relative_alt = true; cmd.content.location.terrain_alt = true; break; default: gcs().send_text(MAV_SEVERITY_WARNING, "Invalid coord frame in SET_POSTION_TARGET_GLOBAL_INT"); msg_valid = false; break; } if (msg_valid) { handle_change_alt_request(cmd); } } // end if alt_mask break; } case MAVLINK_MSG_ID_ADSB_VEHICLE: case MAVLINK_MSG_ID_UAVIONIX_ADSB_OUT_CFG: case MAVLINK_MSG_ID_UAVIONIX_ADSB_OUT_DYNAMIC: case MAVLINK_MSG_ID_UAVIONIX_ADSB_TRANSCEIVER_HEALTH_REPORT: plane.adsb.handle_message(chan, msg); break; default: handle_common_message(msg); break; } // end switch } // end handle mavlink
void GCS_MAVLINK_Rover::handleMessage(mavlink_message_t* msg) { switch (msg->msgid) { case MAVLINK_MSG_ID_REQUEST_DATA_STREAM: { handle_request_data_stream(msg, true); break; } case MAVLINK_MSG_ID_COMMAND_INT: { // decode packet mavlink_command_int_t packet; mavlink_msg_command_int_decode(msg, &packet); MAV_RESULT result = MAV_RESULT_UNSUPPORTED; switch (packet.command) { case MAV_CMD_DO_SET_HOME: { // assume failure result = MAV_RESULT_FAILED; if (is_equal(packet.param1, 1.0f)) { // if param1 is 1, use current location if (rover.set_home_to_current_location(true)) { result = MAV_RESULT_ACCEPTED; } break; } // ensure param1 is zero if (!is_zero(packet.param1)) { break; } // check frame type is supported if (packet.frame != MAV_FRAME_GLOBAL && packet.frame != MAV_FRAME_GLOBAL_INT && packet.frame != MAV_FRAME_GLOBAL_RELATIVE_ALT && packet.frame != MAV_FRAME_GLOBAL_RELATIVE_ALT_INT) { break; } // sanity check location if (!check_latlng(packet.x, packet.y)) { break; } Location new_home_loc {}; new_home_loc.lat = packet.x; new_home_loc.lng = packet.y; new_home_loc.alt = packet.z * 100; // handle relative altitude if (packet.frame == MAV_FRAME_GLOBAL_RELATIVE_ALT || packet.frame == MAV_FRAME_GLOBAL_RELATIVE_ALT_INT) { if (!rover.ahrs.home_is_set()) { // cannot use relative altitude if home is not set break; } new_home_loc.alt += rover.ahrs.get_home().alt; } if (rover.set_home(new_home_loc, true)) { result = MAV_RESULT_ACCEPTED; } break; } #if MOUNT == ENABLED case MAV_CMD_DO_SET_ROI: { // param1 : /* Region of interest mode (not used)*/ // param2 : /* MISSION index/ target ID (not used)*/ // param3 : /* ROI index (not used)*/ // param4 : /* empty */ // x : lat // y : lon // z : alt // sanity check location if (!check_latlng(packet.x, packet.y)) { break; } Location roi_loc; roi_loc.lat = packet.x; roi_loc.lng = packet.y; roi_loc.alt = (int32_t)(packet.z * 100.0f); if (roi_loc.lat == 0 && roi_loc.lng == 0 && roi_loc.alt == 0) { // switch off the camera tracking if enabled if (rover.camera_mount.get_mode() == MAV_MOUNT_MODE_GPS_POINT) { rover.camera_mount.set_mode_to_default(); } } else { // send the command to the camera mount rover.camera_mount.set_roi_target(roi_loc); } result = MAV_RESULT_ACCEPTED; break; } #endif default: result = MAV_RESULT_UNSUPPORTED; break; } // send ACK or NAK mavlink_msg_command_ack_send_buf(msg, chan, packet.command, result); break; } case MAVLINK_MSG_ID_COMMAND_LONG: { // decode mavlink_command_long_t packet; mavlink_msg_command_long_decode(msg, &packet); MAV_RESULT result = MAV_RESULT_UNSUPPORTED; // do command switch (packet.command) { case MAV_CMD_NAV_RETURN_TO_LAUNCH: rover.set_mode(rover.mode_rtl, MODE_REASON_GCS_COMMAND); result = MAV_RESULT_ACCEPTED; break; #if MOUNT == ENABLED // Sets the region of interest (ROI) for the camera case MAV_CMD_DO_SET_ROI: // sanity check location if (!check_latlng(packet.param5, packet.param6)) { break; } Location roi_loc; roi_loc.lat = (int32_t)(packet.param5 * 1.0e7f); roi_loc.lng = (int32_t)(packet.param6 * 1.0e7f); roi_loc.alt = (int32_t)(packet.param7 * 100.0f); if (roi_loc.lat == 0 && roi_loc.lng == 0 && roi_loc.alt == 0) { // switch off the camera tracking if enabled if (rover.camera_mount.get_mode() == MAV_MOUNT_MODE_GPS_POINT) { rover.camera_mount.set_mode_to_default(); } } else { // send the command to the camera mount rover.camera_mount.set_roi_target(roi_loc); } result = MAV_RESULT_ACCEPTED; break; #endif case MAV_CMD_DO_MOUNT_CONTROL: #if MOUNT == ENABLED rover.camera_mount.control(packet.param1, packet.param2, packet.param3, (MAV_MOUNT_MODE) packet.param7); result = MAV_RESULT_ACCEPTED; #endif break; case MAV_CMD_MISSION_START: rover.set_mode(rover.mode_auto, MODE_REASON_GCS_COMMAND); result = MAV_RESULT_ACCEPTED; break; case MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN: if (is_equal(packet.param1, 1.0f) || is_equal(packet.param1, 3.0f)) { // when packet.param1 == 3 we reboot to hold in bootloader hal.scheduler->reboot(is_equal(packet.param1, 3.0f)); result = MAV_RESULT_ACCEPTED; } break; case MAV_CMD_COMPONENT_ARM_DISARM: if (is_equal(packet.param1, 1.0f)) { // run pre_arm_checks and arm_checks and display failures if (rover.arm_motors(AP_Arming::MAVLINK)) { result = MAV_RESULT_ACCEPTED; } else { result = MAV_RESULT_FAILED; } } else if (is_zero(packet.param1)) { if (rover.disarm_motors()) { result = MAV_RESULT_ACCEPTED; } else { result = MAV_RESULT_FAILED; } } else { result = MAV_RESULT_UNSUPPORTED; } break; case MAV_CMD_DO_FENCE_ENABLE: result = MAV_RESULT_ACCEPTED; switch ((uint16_t)packet.param1) { case 0: rover.g2.fence.enable(false); break; case 1: rover.g2.fence.enable(true); break; default: result = MAV_RESULT_FAILED; break; } break; case MAV_CMD_DO_SET_HOME: { // param1 : use current (1=use current location, 0=use specified location) // param5 : latitude // param6 : longitude // param7 : altitude result = MAV_RESULT_FAILED; // assume failure if (is_equal(packet.param1, 1.0f)) { if (rover.set_home_to_current_location(true)) { result = MAV_RESULT_ACCEPTED; } } else { // ensure param1 is zero if (!is_zero(packet.param1)) { break; } Location new_home_loc {}; new_home_loc.lat = static_cast<int32_t>(packet.param5 * 1.0e7f); new_home_loc.lng = static_cast<int32_t>(packet.param6 * 1.0e7f); new_home_loc.alt = static_cast<int32_t>(packet.param7 * 100.0f); if (rover.set_home(new_home_loc, true)) { result = MAV_RESULT_ACCEPTED; } } break; } case MAV_CMD_NAV_SET_YAW_SPEED: { // param1 : yaw angle to adjust direction by in centidegress // param2 : Speed - normalized to 0 .. 1 // exit if vehicle is not in Guided mode if (rover.control_mode != &rover.mode_guided) { break; } // send yaw change and target speed to guided mode controller const float speed_max = rover.control_mode->get_speed_default(); const float target_speed = constrain_float(packet.param2 * speed_max, -speed_max, speed_max); rover.mode_guided.set_desired_heading_delta_and_speed(packet.param1, target_speed); result = MAV_RESULT_ACCEPTED; break; } case MAV_CMD_ACCELCAL_VEHICLE_POS: result = MAV_RESULT_FAILED; if (rover.ins.get_acal()->gcs_vehicle_position(packet.param1)) { result = MAV_RESULT_ACCEPTED; } break; case MAV_CMD_DO_MOTOR_TEST: // param1 : motor sequence number (a number from 1 to max number of motors on the vehicle) // param2 : throttle type (0=throttle percentage, 1=PWM, 2=pilot throttle channel pass-through. See MOTOR_TEST_THROTTLE_TYPE enum) // param3 : throttle (range depends upon param2) // param4 : timeout (in seconds) result = rover.mavlink_motor_test_start(chan, static_cast<uint8_t>(packet.param1), static_cast<uint8_t>(packet.param2), static_cast<int16_t>(packet.param3), packet.param4); break; default: result = handle_command_long_message(packet); break; } mavlink_msg_command_ack_send_buf( msg, chan, packet.command, result); break; } case MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE: { // allow override of RC channel values for HIL // or for complete GCS control of switch position // and RC PWM values. if (msg->sysid != rover.g.sysid_my_gcs) { // Only accept control from our gcs break; } mavlink_rc_channels_override_t packet; mavlink_msg_rc_channels_override_decode(msg, &packet); RC_Channels::set_override(0, packet.chan1_raw); RC_Channels::set_override(1, packet.chan2_raw); RC_Channels::set_override(2, packet.chan3_raw); RC_Channels::set_override(3, packet.chan4_raw); RC_Channels::set_override(4, packet.chan5_raw); RC_Channels::set_override(5, packet.chan6_raw); RC_Channels::set_override(6, packet.chan7_raw); RC_Channels::set_override(7, packet.chan8_raw); rover.failsafe.rc_override_timer = AP_HAL::millis(); rover.failsafe_trigger(FAILSAFE_EVENT_RC, false); break; } case MAVLINK_MSG_ID_MANUAL_CONTROL: { if (msg->sysid != rover.g.sysid_my_gcs) { // Only accept control from our gcs break; } mavlink_manual_control_t packet; mavlink_msg_manual_control_decode(msg, &packet); if (packet.target != rover.g.sysid_this_mav) { break; // only accept control aimed at us } const int16_t roll = (packet.y == INT16_MAX) ? 0 : rover.channel_steer->get_radio_min() + (rover.channel_steer->get_radio_max() - rover.channel_steer->get_radio_min()) * (packet.y + 1000) / 2000.0f; const int16_t throttle = (packet.z == INT16_MAX) ? 0 : rover.channel_throttle->get_radio_min() + (rover.channel_throttle->get_radio_max() - rover.channel_throttle->get_radio_min()) * (packet.z + 1000) / 2000.0f; RC_Channels::set_override(uint8_t(rover.rcmap.roll() - 1), roll); RC_Channels::set_override(uint8_t(rover.rcmap.throttle() - 1), throttle); rover.failsafe.rc_override_timer = AP_HAL::millis(); rover.failsafe_trigger(FAILSAFE_EVENT_RC, false); break; } case MAVLINK_MSG_ID_HEARTBEAT: { // We keep track of the last time we received a heartbeat from our GCS for failsafe purposes if (msg->sysid != rover.g.sysid_my_gcs) { break; } rover.last_heartbeat_ms = rover.failsafe.rc_override_timer = AP_HAL::millis(); rover.failsafe_trigger(FAILSAFE_EVENT_GCS, false); break; } case MAVLINK_MSG_ID_SET_ATTITUDE_TARGET: // MAV ID: 82 { // decode packet mavlink_set_attitude_target_t packet; mavlink_msg_set_attitude_target_decode(msg, &packet); // exit if vehicle is not in Guided mode if (rover.control_mode != &rover.mode_guided) { break; } // ensure type_mask specifies to use thrust if ((packet.type_mask & MAVLINK_SET_ATT_TYPE_MASK_THROTTLE_IGNORE) != 0) { break; } // convert thrust to ground speed packet.thrust = constrain_float(packet.thrust, -1.0f, 1.0f); const float target_speed = rover.control_mode->get_speed_default() * packet.thrust; // if the body_yaw_rate field is ignored, convert quaternion to heading if ((packet.type_mask & MAVLINK_SET_ATT_TYPE_MASK_YAW_RATE_IGNORE) != 0) { // convert quaternion to heading float target_heading_cd = degrees(Quaternion(packet.q[0], packet.q[1], packet.q[2], packet.q[3]).get_euler_yaw()) * 100.0f; rover.mode_guided.set_desired_heading_and_speed(target_heading_cd, target_speed); } else { // use body_yaw_rate field rover.mode_guided.set_desired_turn_rate_and_speed((RAD_TO_DEG * packet.body_yaw_rate) * 100.0f, target_speed); } break; } case MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED: // MAV ID: 84 { // decode packet mavlink_set_position_target_local_ned_t packet; mavlink_msg_set_position_target_local_ned_decode(msg, &packet); // exit if vehicle is not in Guided mode if (rover.control_mode != &rover.mode_guided) { break; } // check for supported coordinate frames if (packet.coordinate_frame != MAV_FRAME_LOCAL_NED && packet.coordinate_frame != MAV_FRAME_LOCAL_OFFSET_NED && packet.coordinate_frame != MAV_FRAME_BODY_NED && packet.coordinate_frame != MAV_FRAME_BODY_OFFSET_NED) { break; } bool pos_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_POS_IGNORE; bool vel_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_VEL_IGNORE; bool acc_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_ACC_IGNORE; bool yaw_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_YAW_IGNORE; bool yaw_rate_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_YAW_RATE_IGNORE; // prepare target position Location target_loc = rover.current_loc; if (!pos_ignore) { switch (packet.coordinate_frame) { case MAV_FRAME_BODY_NED: case MAV_FRAME_BODY_OFFSET_NED: { // rotate from body-frame to NE frame const float ne_x = packet.x * rover.ahrs.cos_yaw() - packet.y * rover.ahrs.sin_yaw(); const float ne_y = packet.x * rover.ahrs.sin_yaw() + packet.y * rover.ahrs.cos_yaw(); // add offset to current location location_offset(target_loc, ne_x, ne_y); } break; case MAV_FRAME_LOCAL_OFFSET_NED: // add offset to current location location_offset(target_loc, packet.x, packet.y); break; default: // MAV_FRAME_LOCAL_NED interpret as an offset from home target_loc = rover.ahrs.get_home(); location_offset(target_loc, packet.x, packet.y); break; } } float target_speed = 0.0f; float target_yaw_cd = 0.0f; // consume velocity and convert to target speed and heading if (!vel_ignore) { const float speed_max = rover.control_mode->get_speed_default(); // convert vector length into a speed target_speed = constrain_float(safe_sqrt(sq(packet.vx) + sq(packet.vy)), -speed_max, speed_max); // convert vector direction to target yaw target_yaw_cd = degrees(atan2f(packet.vy, packet.vx)) * 100.0f; // rotate target yaw if provided in body-frame if (packet.coordinate_frame == MAV_FRAME_BODY_NED || packet.coordinate_frame == MAV_FRAME_BODY_OFFSET_NED) { target_yaw_cd = wrap_180_cd(target_yaw_cd + rover.ahrs.yaw_sensor); } } // consume yaw heading if (!yaw_ignore) { target_yaw_cd = ToDeg(packet.yaw) * 100.0f; // rotate target yaw if provided in body-frame if (packet.coordinate_frame == MAV_FRAME_BODY_NED || packet.coordinate_frame == MAV_FRAME_BODY_OFFSET_NED) { target_yaw_cd = wrap_180_cd(target_yaw_cd + rover.ahrs.yaw_sensor); } } // consume yaw rate float target_turn_rate_cds = 0.0f; if (!yaw_rate_ignore) { target_turn_rate_cds = ToDeg(packet.yaw_rate) * 100.0f; } // handling case when both velocity and either yaw or yaw-rate are provided // by default, we consider that the rover will drive forward float speed_dir = 1.0f; if (!vel_ignore && (!yaw_ignore || !yaw_rate_ignore)) { // Note: we are using the x-axis velocity to determine direction even though // the frame may have been provided in MAV_FRAME_LOCAL_OFFSET_NED or MAV_FRAME_LOCAL_NED if (is_negative(packet.vx)) { speed_dir = -1.0f; } } // set guided mode targets if (!pos_ignore && vel_ignore && acc_ignore && yaw_ignore && yaw_rate_ignore) { // consume position target rover.mode_guided.set_desired_location(target_loc); } else if (pos_ignore && !vel_ignore && acc_ignore && yaw_ignore && yaw_rate_ignore) { // consume velocity rover.mode_guided.set_desired_heading_and_speed(target_yaw_cd, speed_dir * target_speed); } else if (pos_ignore && !vel_ignore && acc_ignore && yaw_ignore && !yaw_rate_ignore) { // consume velocity and turn rate rover.mode_guided.set_desired_turn_rate_and_speed(target_turn_rate_cds, speed_dir * target_speed); } else if (pos_ignore && !vel_ignore && acc_ignore && !yaw_ignore && yaw_rate_ignore) { // consume velocity rover.mode_guided.set_desired_heading_and_speed(target_yaw_cd, speed_dir * target_speed); } else if (pos_ignore && vel_ignore && acc_ignore && !yaw_ignore && yaw_rate_ignore) { // consume just target heading (probably only skid steering vehicles can do this) rover.mode_guided.set_desired_heading_and_speed(target_yaw_cd, 0.0f); } else if (pos_ignore && vel_ignore && acc_ignore && yaw_ignore && !yaw_rate_ignore) { // consume just turn rate(probably only skid steering vehicles can do this) rover.mode_guided.set_desired_turn_rate_and_speed(target_turn_rate_cds, 0.0f); } break; } case MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT: // MAV ID: 86 { // decode packet mavlink_set_position_target_global_int_t packet; mavlink_msg_set_position_target_global_int_decode(msg, &packet); // exit if vehicle is not in Guided mode if (rover.control_mode != &rover.mode_guided) { break; } // check for supported coordinate frames if (packet.coordinate_frame != MAV_FRAME_GLOBAL && packet.coordinate_frame != MAV_FRAME_GLOBAL_INT && packet.coordinate_frame != MAV_FRAME_GLOBAL_RELATIVE_ALT && packet.coordinate_frame != MAV_FRAME_GLOBAL_RELATIVE_ALT_INT && packet.coordinate_frame != MAV_FRAME_GLOBAL_TERRAIN_ALT && packet.coordinate_frame != MAV_FRAME_GLOBAL_TERRAIN_ALT_INT) { break; } bool pos_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_POS_IGNORE; bool vel_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_VEL_IGNORE; bool acc_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_ACC_IGNORE; bool yaw_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_YAW_IGNORE; bool yaw_rate_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_YAW_RATE_IGNORE; // prepare target position Location target_loc = rover.current_loc; if (!pos_ignore) { // sanity check location if (!check_latlng(packet.lat_int, packet.lon_int)) { // result = MAV_RESULT_FAILED; break; } target_loc.lat = packet.lat_int; target_loc.lng = packet.lon_int; } float target_speed = 0.0f; float target_yaw_cd = 0.0f; // consume velocity and convert to target speed and heading if (!vel_ignore) { const float speed_max = rover.control_mode->get_speed_default(); // convert vector length into a speed target_speed = constrain_float(safe_sqrt(sq(packet.vx) + sq(packet.vy)), -speed_max, speed_max); // convert vector direction to target yaw target_yaw_cd = degrees(atan2f(packet.vy, packet.vx)) * 100.0f; // rotate target yaw if provided in body-frame if (packet.coordinate_frame == MAV_FRAME_BODY_NED || packet.coordinate_frame == MAV_FRAME_BODY_OFFSET_NED) { target_yaw_cd = wrap_180_cd(target_yaw_cd + rover.ahrs.yaw_sensor); } } // consume yaw heading if (!yaw_ignore) { target_yaw_cd = ToDeg(packet.yaw) * 100.0f; // rotate target yaw if provided in body-frame if (packet.coordinate_frame == MAV_FRAME_BODY_NED || packet.coordinate_frame == MAV_FRAME_BODY_OFFSET_NED) { target_yaw_cd = wrap_180_cd(target_yaw_cd + rover.ahrs.yaw_sensor); } } // consume yaw rate float target_turn_rate_cds = 0.0f; if (!yaw_rate_ignore) { target_turn_rate_cds = ToDeg(packet.yaw_rate) * 100.0f; } // handling case when both velocity and either yaw or yaw-rate are provided // by default, we consider that the rover will drive forward float speed_dir = 1.0f; if (!vel_ignore && (!yaw_ignore || !yaw_rate_ignore)) { // Note: we are using the x-axis velocity to determine direction even though // the frame is provided in MAV_FRAME_GLOBAL_xxx if (is_negative(packet.vx)) { speed_dir = -1.0f; } } // set guided mode targets if (!pos_ignore && vel_ignore && acc_ignore && yaw_ignore && yaw_rate_ignore) { // consume position target rover.mode_guided.set_desired_location(target_loc); } else if (pos_ignore && !vel_ignore && acc_ignore && yaw_ignore && yaw_rate_ignore) { // consume velocity rover.mode_guided.set_desired_heading_and_speed(target_yaw_cd, speed_dir * target_speed); } else if (pos_ignore && !vel_ignore && acc_ignore && yaw_ignore && !yaw_rate_ignore) { // consume velocity and turn rate rover.mode_guided.set_desired_turn_rate_and_speed(target_turn_rate_cds, speed_dir * target_speed); } else if (pos_ignore && !vel_ignore && acc_ignore && !yaw_ignore && yaw_rate_ignore) { // consume velocity rover.mode_guided.set_desired_heading_and_speed(target_yaw_cd, speed_dir * target_speed); } else if (pos_ignore && vel_ignore && acc_ignore && !yaw_ignore && yaw_rate_ignore) { // consume just target heading (probably only skid steering vehicles can do this) rover.mode_guided.set_desired_heading_and_speed(target_yaw_cd, 0.0f); } else if (pos_ignore && vel_ignore && acc_ignore && yaw_ignore && !yaw_rate_ignore) { // consume just turn rate(probably only skid steering vehicles can do this) rover.mode_guided.set_desired_turn_rate_and_speed(target_turn_rate_cds, 0.0f); } break; } #if HIL_MODE != HIL_MODE_DISABLED case MAVLINK_MSG_ID_HIL_STATE: { mavlink_hil_state_t packet; mavlink_msg_hil_state_decode(msg, &packet); // sanity check location if (!check_latlng(packet.lat, packet.lon)) { break; } // set gps hil sensor Location loc; loc.lat = packet.lat; loc.lng = packet.lon; loc.alt = packet.alt/10; Vector3f vel(packet.vx, packet.vy, packet.vz); vel *= 0.01f; gps.setHIL(0, AP_GPS::GPS_OK_FIX_3D, packet.time_usec/1000, loc, vel, 10, 0); // rad/sec Vector3f gyros; gyros.x = packet.rollspeed; gyros.y = packet.pitchspeed; gyros.z = packet.yawspeed; // m/s/s Vector3f accels; accels.x = packet.xacc * (GRAVITY_MSS/1000.0f); accels.y = packet.yacc * (GRAVITY_MSS/1000.0f); accels.z = packet.zacc * (GRAVITY_MSS/1000.0f); ins.set_gyro(0, gyros); ins.set_accel(0, accels); compass.setHIL(0, packet.roll, packet.pitch, packet.yaw); compass.setHIL(1, packet.roll, packet.pitch, packet.yaw); break; } #endif // HIL_MODE #if MOUNT == ENABLED // deprecated. Use MAV_CMD_DO_MOUNT_CONFIGURE case MAVLINK_MSG_ID_MOUNT_CONFIGURE: { rover.camera_mount.configure_msg(msg); break; } // deprecated. Use MAV_CMD_DO_MOUNT_CONTROL case MAVLINK_MSG_ID_MOUNT_CONTROL: { rover.camera_mount.control_msg(msg); break; } #endif // MOUNT == ENABLED case MAVLINK_MSG_ID_RADIO: case MAVLINK_MSG_ID_RADIO_STATUS: { handle_radio_status(msg, rover.DataFlash, rover.should_log(MASK_LOG_PM)); break; } // send or receive fence points with GCS case MAVLINK_MSG_ID_FENCE_POINT: // MAV ID: 160 case MAVLINK_MSG_ID_FENCE_FETCH_POINT: rover.g2.fence.handle_msg(*this, msg); break; case MAVLINK_MSG_ID_DISTANCE_SENSOR: rover.rangefinder.handle_msg(msg); rover.g2.proximity.handle_msg(msg); break; default: handle_common_message(msg); break; } // end switch } // end handle mavlink
void GCS_MAVLINK_Copter::handleMessage(mavlink_message_t* msg) { switch (msg->msgid) { case MAVLINK_MSG_ID_HEARTBEAT: // MAV ID: 0 { // We keep track of the last time we received a heartbeat from our GCS for failsafe purposes if(msg->sysid != copter.g.sysid_my_gcs) break; copter.failsafe.last_heartbeat_ms = AP_HAL::millis(); break; } case MAVLINK_MSG_ID_MANUAL_CONTROL: { if (msg->sysid != copter.g.sysid_my_gcs) { break; // only accept control from our gcs } mavlink_manual_control_t packet; mavlink_msg_manual_control_decode(msg, &packet); if (packet.target != copter.g.sysid_this_mav) { break; // only accept control aimed at us } if (packet.z < 0) { // Copter doesn't do negative thrust break; } uint32_t tnow = AP_HAL::millis(); manual_override(copter.channel_roll, packet.y, 1000, 2000, tnow); manual_override(copter.channel_pitch, packet.x, 1000, 2000, tnow, true); manual_override(copter.channel_throttle, packet.z, 0, 1000, tnow); manual_override(copter.channel_yaw, packet.r, 1000, 2000, tnow); // a manual control message is considered to be a 'heartbeat' from the ground station for failsafe purposes copter.failsafe.last_heartbeat_ms = tnow; break; } #if MODE_GUIDED_ENABLED == ENABLED case MAVLINK_MSG_ID_SET_ATTITUDE_TARGET: // MAV ID: 82 { // decode packet mavlink_set_attitude_target_t packet; mavlink_msg_set_attitude_target_decode(msg, &packet); // exit if vehicle is not in Guided mode or Auto-Guided mode if (!copter.flightmode->in_guided_mode()) { break; } // ensure type_mask specifies to use attitude and thrust if ((packet.type_mask & ((1<<7)|(1<<6))) != 0) { break; } // convert thrust to climb rate packet.thrust = constrain_float(packet.thrust, 0.0f, 1.0f); float climb_rate_cms = 0.0f; if (is_equal(packet.thrust, 0.5f)) { climb_rate_cms = 0.0f; } else if (packet.thrust > 0.5f) { // climb at up to WPNAV_SPEED_UP climb_rate_cms = (packet.thrust - 0.5f) * 2.0f * copter.wp_nav->get_default_speed_up(); } else { // descend at up to WPNAV_SPEED_DN climb_rate_cms = (0.5f - packet.thrust) * 2.0f * -fabsf(copter.wp_nav->get_default_speed_down()); } // if the body_yaw_rate field is ignored, use the commanded yaw position // otherwise use the commanded yaw rate bool use_yaw_rate = false; if ((packet.type_mask & (1<<2)) == 0) { use_yaw_rate = true; } copter.mode_guided.set_angle(Quaternion(packet.q[0],packet.q[1],packet.q[2],packet.q[3]), climb_rate_cms, use_yaw_rate, packet.body_yaw_rate); break; } case MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED: // MAV ID: 84 { // decode packet mavlink_set_position_target_local_ned_t packet; mavlink_msg_set_position_target_local_ned_decode(msg, &packet); // exit if vehicle is not in Guided mode or Auto-Guided mode if (!copter.flightmode->in_guided_mode()) { break; } // check for supported coordinate frames if (packet.coordinate_frame != MAV_FRAME_LOCAL_NED && packet.coordinate_frame != MAV_FRAME_LOCAL_OFFSET_NED && packet.coordinate_frame != MAV_FRAME_BODY_NED && packet.coordinate_frame != MAV_FRAME_BODY_OFFSET_NED) { break; } bool pos_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_POS_IGNORE; bool vel_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_VEL_IGNORE; bool acc_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_ACC_IGNORE; bool yaw_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_YAW_IGNORE; bool yaw_rate_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_YAW_RATE_IGNORE; /* * for future use: * bool force = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_FORCE; */ // prepare position Vector3f pos_vector; if (!pos_ignore) { // convert to cm pos_vector = Vector3f(packet.x * 100.0f, packet.y * 100.0f, -packet.z * 100.0f); // rotate to body-frame if necessary if (packet.coordinate_frame == MAV_FRAME_BODY_NED || packet.coordinate_frame == MAV_FRAME_BODY_OFFSET_NED) { copter.rotate_body_frame_to_NE(pos_vector.x, pos_vector.y); } // add body offset if necessary if (packet.coordinate_frame == MAV_FRAME_LOCAL_OFFSET_NED || packet.coordinate_frame == MAV_FRAME_BODY_NED || packet.coordinate_frame == MAV_FRAME_BODY_OFFSET_NED) { pos_vector += copter.inertial_nav.get_position(); } else { // convert from alt-above-home to alt-above-ekf-origin if (!AP::ahrs().home_is_set()) { break; } const Location &origin = copter.inertial_nav.get_origin(); pos_vector.z += AP::ahrs().get_home().alt; pos_vector.z -= origin.alt; } } // prepare velocity Vector3f vel_vector; if (!vel_ignore) { // convert to cm vel_vector = Vector3f(packet.vx * 100.0f, packet.vy * 100.0f, -packet.vz * 100.0f); // rotate to body-frame if necessary if (packet.coordinate_frame == MAV_FRAME_BODY_NED || packet.coordinate_frame == MAV_FRAME_BODY_OFFSET_NED) { copter.rotate_body_frame_to_NE(vel_vector.x, vel_vector.y); } } // prepare yaw float yaw_cd = 0.0f; bool yaw_relative = false; float yaw_rate_cds = 0.0f; if (!yaw_ignore) { yaw_cd = ToDeg(packet.yaw) * 100.0f; yaw_relative = packet.coordinate_frame == MAV_FRAME_BODY_NED || packet.coordinate_frame == MAV_FRAME_BODY_OFFSET_NED; } if (!yaw_rate_ignore) { yaw_rate_cds = ToDeg(packet.yaw_rate) * 100.0f; } // send request if (!pos_ignore && !vel_ignore && acc_ignore) { copter.mode_guided.set_destination_posvel(pos_vector, vel_vector, !yaw_ignore, yaw_cd, !yaw_rate_ignore, yaw_rate_cds, yaw_relative); } else if (pos_ignore && !vel_ignore && acc_ignore) { copter.mode_guided.set_velocity(vel_vector, !yaw_ignore, yaw_cd, !yaw_rate_ignore, yaw_rate_cds, yaw_relative); } else if (!pos_ignore && vel_ignore && acc_ignore) { copter.mode_guided.set_destination(pos_vector, !yaw_ignore, yaw_cd, !yaw_rate_ignore, yaw_rate_cds, yaw_relative); } break; } case MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT: // MAV ID: 86 { // decode packet mavlink_set_position_target_global_int_t packet; mavlink_msg_set_position_target_global_int_decode(msg, &packet); // exit if vehicle is not in Guided mode or Auto-Guided mode if (!copter.flightmode->in_guided_mode()) { break; } bool pos_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_POS_IGNORE; bool vel_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_VEL_IGNORE; bool acc_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_ACC_IGNORE; bool yaw_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_YAW_IGNORE; bool yaw_rate_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_YAW_RATE_IGNORE; /* * for future use: * bool force = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_FORCE; */ Vector3f pos_neu_cm; // position (North, East, Up coordinates) in centimeters if(!pos_ignore) { // sanity check location if (!check_latlng(packet.lat_int, packet.lon_int)) { break; } Location::AltFrame frame; if (!mavlink_coordinate_frame_to_location_alt_frame(packet.coordinate_frame, frame)) { // unknown coordinate frame break; } const Location loc{ packet.lat_int, packet.lon_int, int32_t(packet.alt*100), frame, }; if (!loc.get_vector_from_origin_NEU(pos_neu_cm)) { break; } } // prepare yaw float yaw_cd = 0.0f; bool yaw_relative = false; float yaw_rate_cds = 0.0f; if (!yaw_ignore) { yaw_cd = ToDeg(packet.yaw) * 100.0f; yaw_relative = packet.coordinate_frame == MAV_FRAME_BODY_NED || packet.coordinate_frame == MAV_FRAME_BODY_OFFSET_NED; } if (!yaw_rate_ignore) { yaw_rate_cds = ToDeg(packet.yaw_rate) * 100.0f; } if (!pos_ignore && !vel_ignore && acc_ignore) { copter.mode_guided.set_destination_posvel(pos_neu_cm, Vector3f(packet.vx * 100.0f, packet.vy * 100.0f, -packet.vz * 100.0f), !yaw_ignore, yaw_cd, !yaw_rate_ignore, yaw_rate_cds, yaw_relative); } else if (pos_ignore && !vel_ignore && acc_ignore) { copter.mode_guided.set_velocity(Vector3f(packet.vx * 100.0f, packet.vy * 100.0f, -packet.vz * 100.0f), !yaw_ignore, yaw_cd, !yaw_rate_ignore, yaw_rate_cds, yaw_relative); } else if (!pos_ignore && vel_ignore && acc_ignore) { copter.mode_guided.set_destination(pos_neu_cm, !yaw_ignore, yaw_cd, !yaw_rate_ignore, yaw_rate_cds, yaw_relative); } break; } #endif case MAVLINK_MSG_ID_DISTANCE_SENSOR: { copter.rangefinder.handle_msg(msg); #if PROXIMITY_ENABLED == ENABLED copter.g2.proximity.handle_msg(msg); #endif break; } case MAVLINK_MSG_ID_OBSTACLE_DISTANCE: { #if PROXIMITY_ENABLED == ENABLED copter.g2.proximity.handle_msg(msg); #endif break; } #if HIL_MODE != HIL_MODE_DISABLED case MAVLINK_MSG_ID_HIL_STATE: // MAV ID: 90 { mavlink_hil_state_t packet; mavlink_msg_hil_state_decode(msg, &packet); // sanity check location if (!check_latlng(packet.lat, packet.lon)) { break; } // set gps hil sensor Location loc; loc.lat = packet.lat; loc.lng = packet.lon; loc.alt = packet.alt/10; Vector3f vel(packet.vx, packet.vy, packet.vz); vel *= 0.01f; gps.setHIL(0, AP_GPS::GPS_OK_FIX_3D, packet.time_usec/1000, loc, vel, 10, 0); // rad/sec Vector3f gyros; gyros.x = packet.rollspeed; gyros.y = packet.pitchspeed; gyros.z = packet.yawspeed; // m/s/s Vector3f accels; accels.x = packet.xacc * (GRAVITY_MSS/1000.0f); accels.y = packet.yacc * (GRAVITY_MSS/1000.0f); accels.z = packet.zacc * (GRAVITY_MSS/1000.0f); ins.set_gyro(0, gyros); ins.set_accel(0, accels); AP::baro().setHIL(packet.alt*0.001f); copter.compass.setHIL(0, packet.roll, packet.pitch, packet.yaw); copter.compass.setHIL(1, packet.roll, packet.pitch, packet.yaw); break; } #endif // HIL_MODE != HIL_MODE_DISABLED case MAVLINK_MSG_ID_RADIO: case MAVLINK_MSG_ID_RADIO_STATUS: // MAV ID: 109 { handle_radio_status(msg, copter.should_log(MASK_LOG_PM)); break; } #if PRECISION_LANDING == ENABLED case MAVLINK_MSG_ID_LANDING_TARGET: copter.precland.handle_msg(msg); break; #endif case MAVLINK_MSG_ID_TERRAIN_DATA: case MAVLINK_MSG_ID_TERRAIN_CHECK: #if AP_TERRAIN_AVAILABLE && AC_TERRAIN copter.terrain.handle_data(chan, msg); #endif break; case MAVLINK_MSG_ID_SET_HOME_POSITION: { mavlink_set_home_position_t packet; mavlink_msg_set_home_position_decode(msg, &packet); if((packet.latitude == 0) && (packet.longitude == 0) && (packet.altitude == 0)) { if (!copter.set_home_to_current_location(true)) { // silently ignored } } else { Location new_home_loc; new_home_loc.lat = packet.latitude; new_home_loc.lng = packet.longitude; new_home_loc.alt = packet.altitude / 10; if (!copter.set_home(new_home_loc, true)) { // silently ignored } } break; } case MAVLINK_MSG_ID_ADSB_VEHICLE: case MAVLINK_MSG_ID_UAVIONIX_ADSB_OUT_CFG: case MAVLINK_MSG_ID_UAVIONIX_ADSB_OUT_DYNAMIC: case MAVLINK_MSG_ID_UAVIONIX_ADSB_TRANSCEIVER_HEALTH_REPORT: #if ADSB_ENABLED == ENABLED copter.adsb.handle_message(chan, msg); #endif break; #if TOY_MODE_ENABLED == ENABLED case MAVLINK_MSG_ID_NAMED_VALUE_INT: copter.g2.toy_mode.handle_message(msg); break; #endif default: handle_common_message(msg); break; } // end switch } // end handle mavlink
void GCS_MAVLINK_Sub::handleMessage(mavlink_message_t* msg) { switch (msg->msgid) { case MAVLINK_MSG_ID_HEARTBEAT: { // MAV ID: 0 // We keep track of the last time we received a heartbeat from our GCS for failsafe purposes if (msg->sysid != sub.g.sysid_my_gcs) { break; } sub.failsafe.last_heartbeat_ms = AP_HAL::millis(); break; } case MAVLINK_MSG_ID_MANUAL_CONTROL: { // MAV ID: 69 if (msg->sysid != sub.g.sysid_my_gcs) { break; // Only accept control from our gcs } mavlink_manual_control_t packet; mavlink_msg_manual_control_decode(msg, &packet); if (packet.target != sub.g.sysid_this_mav) { break; // only accept control aimed at us } sub.transform_manual_control_to_rc_override(packet.x,packet.y,packet.z,packet.r,packet.buttons); sub.failsafe.last_pilot_input_ms = AP_HAL::millis(); // a RC override message is considered to be a 'heartbeat' from the ground station for failsafe purposes sub.failsafe.last_heartbeat_ms = AP_HAL::millis(); break; } case MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE: { // MAV ID: 70 // allow override of RC input if (msg->sysid != sub.g.sysid_my_gcs) { break; // Only accept control from our gcs } uint32_t tnow = AP_HAL::millis(); mavlink_rc_channels_override_t packet; mavlink_msg_rc_channels_override_decode(msg, &packet); RC_Channels::set_override(0, packet.chan1_raw, tnow); RC_Channels::set_override(1, packet.chan2_raw, tnow); RC_Channels::set_override(2, packet.chan3_raw, tnow); RC_Channels::set_override(3, packet.chan4_raw, tnow); RC_Channels::set_override(4, packet.chan5_raw, tnow); RC_Channels::set_override(5, packet.chan6_raw, tnow); RC_Channels::set_override(6, packet.chan7_raw, tnow); RC_Channels::set_override(7, packet.chan8_raw, tnow); sub.failsafe.last_pilot_input_ms = tnow; // a RC override message is considered to be a 'heartbeat' from the ground station for failsafe purposes sub.failsafe.last_heartbeat_ms = tnow; break; } case MAVLINK_MSG_ID_SET_ATTITUDE_TARGET: { // MAV ID: 82 // decode packet mavlink_set_attitude_target_t packet; mavlink_msg_set_attitude_target_decode(msg, &packet); // ensure type_mask specifies to use attitude // the thrust can be used from the altitude hold if (packet.type_mask & (1<<6)) { sub.set_attitude_target_no_gps = {AP_HAL::millis(), packet}; } // ensure type_mask specifies to use attitude and thrust if ((packet.type_mask & ((1<<7)|(1<<6))) != 0) { break; } // convert thrust to climb rate packet.thrust = constrain_float(packet.thrust, 0.0f, 1.0f); float climb_rate_cms = 0.0f; if (is_equal(packet.thrust, 0.5f)) { climb_rate_cms = 0.0f; } else if (packet.thrust > 0.5f) { // climb at up to WPNAV_SPEED_UP climb_rate_cms = (packet.thrust - 0.5f) * 2.0f * sub.wp_nav.get_default_speed_up(); } else { // descend at up to WPNAV_SPEED_DN climb_rate_cms = (packet.thrust - 0.5f) * 2.0f * fabsf(sub.wp_nav.get_default_speed_down()); } sub.guided_set_angle(Quaternion(packet.q[0],packet.q[1],packet.q[2],packet.q[3]), climb_rate_cms); break; } case MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED: { // MAV ID: 84 // decode packet mavlink_set_position_target_local_ned_t packet; mavlink_msg_set_position_target_local_ned_decode(msg, &packet); // exit if vehicle is not in Guided mode or Auto-Guided mode if ((sub.control_mode != GUIDED) && !(sub.control_mode == AUTO && sub.auto_mode == Auto_NavGuided)) { break; } // check for supported coordinate frames if (packet.coordinate_frame != MAV_FRAME_LOCAL_NED && packet.coordinate_frame != MAV_FRAME_LOCAL_OFFSET_NED && packet.coordinate_frame != MAV_FRAME_BODY_NED && packet.coordinate_frame != MAV_FRAME_BODY_OFFSET_NED) { break; } bool pos_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_POS_IGNORE; bool vel_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_VEL_IGNORE; bool acc_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_ACC_IGNORE; /* * for future use: * bool force = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_FORCE; * bool yaw_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_YAW_IGNORE; * bool yaw_rate_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_YAW_RATE_IGNORE; */ // prepare position Vector3f pos_vector; if (!pos_ignore) { // convert to cm pos_vector = Vector3f(packet.x * 100.0f, packet.y * 100.0f, -packet.z * 100.0f); // rotate to body-frame if necessary if (packet.coordinate_frame == MAV_FRAME_BODY_NED || packet.coordinate_frame == MAV_FRAME_BODY_OFFSET_NED) { sub.rotate_body_frame_to_NE(pos_vector.x, pos_vector.y); } // add body offset if necessary if (packet.coordinate_frame == MAV_FRAME_LOCAL_OFFSET_NED || packet.coordinate_frame == MAV_FRAME_BODY_NED || packet.coordinate_frame == MAV_FRAME_BODY_OFFSET_NED) { pos_vector += sub.inertial_nav.get_position(); } else { // convert from alt-above-home to alt-above-ekf-origin pos_vector.z = sub.pv_alt_above_origin(pos_vector.z); } } // prepare velocity Vector3f vel_vector; if (!vel_ignore) { // convert to cm vel_vector = Vector3f(packet.vx * 100.0f, packet.vy * 100.0f, -packet.vz * 100.0f); // rotate to body-frame if necessary if (packet.coordinate_frame == MAV_FRAME_BODY_NED || packet.coordinate_frame == MAV_FRAME_BODY_OFFSET_NED) { sub.rotate_body_frame_to_NE(vel_vector.x, vel_vector.y); } } // send request if (!pos_ignore && !vel_ignore && acc_ignore) { sub.guided_set_destination_posvel(pos_vector, vel_vector); } else if (pos_ignore && !vel_ignore && acc_ignore) { sub.guided_set_velocity(vel_vector); } else if (!pos_ignore && vel_ignore && acc_ignore) { sub.guided_set_destination(pos_vector); } break; } case MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT: { // MAV ID: 86 // decode packet mavlink_set_position_target_global_int_t packet; mavlink_msg_set_position_target_global_int_decode(msg, &packet); // exit if vehicle is not in Guided mode or Auto-Guided mode if ((sub.control_mode != GUIDED) && !(sub.control_mode == AUTO && sub.auto_mode == Auto_NavGuided)) { break; } // check for supported coordinate frames if (packet.coordinate_frame != MAV_FRAME_GLOBAL && packet.coordinate_frame != MAV_FRAME_GLOBAL_INT && packet.coordinate_frame != MAV_FRAME_GLOBAL_RELATIVE_ALT && // solo shot manager incorrectly sends RELATIVE_ALT instead of RELATIVE_ALT_INT packet.coordinate_frame != MAV_FRAME_GLOBAL_RELATIVE_ALT_INT && packet.coordinate_frame != MAV_FRAME_GLOBAL_TERRAIN_ALT && packet.coordinate_frame != MAV_FRAME_GLOBAL_TERRAIN_ALT_INT) { break; } bool pos_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_POS_IGNORE; bool vel_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_VEL_IGNORE; bool acc_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_ACC_IGNORE; /* * for future use: * bool force = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_FORCE; * bool yaw_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_YAW_IGNORE; * bool yaw_rate_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_YAW_RATE_IGNORE; */ Vector3f pos_neu_cm; // position (North, East, Up coordinates) in centimeters if (!pos_ignore) { // sanity check location if (!check_latlng(packet.lat_int, packet.lon_int)) { break; } Location loc; loc.lat = packet.lat_int; loc.lng = packet.lon_int; loc.alt = packet.alt*100; switch (packet.coordinate_frame) { case MAV_FRAME_GLOBAL_RELATIVE_ALT: // solo shot manager incorrectly sends RELATIVE_ALT instead of RELATIVE_ALT_INT case MAV_FRAME_GLOBAL_RELATIVE_ALT_INT: loc.relative_alt = true; loc.terrain_alt = false; break; case MAV_FRAME_GLOBAL_TERRAIN_ALT: case MAV_FRAME_GLOBAL_TERRAIN_ALT_INT: loc.relative_alt = true; loc.terrain_alt = true; break; case MAV_FRAME_GLOBAL: case MAV_FRAME_GLOBAL_INT: default: loc.relative_alt = false; loc.terrain_alt = false; break; } pos_neu_cm = sub.pv_location_to_vector(loc); } if (!pos_ignore && !vel_ignore && acc_ignore) { sub.guided_set_destination_posvel(pos_neu_cm, Vector3f(packet.vx * 100.0f, packet.vy * 100.0f, -packet.vz * 100.0f)); } else if (pos_ignore && !vel_ignore && acc_ignore) { sub.guided_set_velocity(Vector3f(packet.vx * 100.0f, packet.vy * 100.0f, -packet.vz * 100.0f)); } else if (!pos_ignore && vel_ignore && acc_ignore) { sub.guided_set_destination(pos_neu_cm); } break; } case MAVLINK_MSG_ID_DISTANCE_SENSOR: { sub.rangefinder.handle_msg(msg); break; } #if AC_FENCE == ENABLED // send or receive fence points with GCS case MAVLINK_MSG_ID_FENCE_POINT: // MAV ID: 160 case MAVLINK_MSG_ID_FENCE_FETCH_POINT: sub.fence.handle_msg(*this, msg); break; #endif // AC_FENCE == ENABLED case MAVLINK_MSG_ID_TERRAIN_DATA: case MAVLINK_MSG_ID_TERRAIN_CHECK: #if AP_TERRAIN_AVAILABLE && AC_TERRAIN sub.terrain.handle_data(chan, msg); #endif break; case MAVLINK_MSG_ID_SET_HOME_POSITION: { mavlink_set_home_position_t packet; mavlink_msg_set_home_position_decode(msg, &packet); if ((packet.latitude == 0) && (packet.longitude == 0) && (packet.altitude == 0)) { sub.set_home_to_current_location(true); } else { // sanity check location if (!check_latlng(packet.latitude, packet.longitude)) { break; } Location new_home_loc; new_home_loc.lat = packet.latitude; new_home_loc.lng = packet.longitude; new_home_loc.alt = packet.altitude / 10; if (sub.far_from_EKF_origin(new_home_loc)) { break; } sub.set_home(new_home_loc, true); } break; } // This adds support for leak detectors in a separate enclosure // connected to a mavlink enabled subsystem case MAVLINK_MSG_ID_SYS_STATUS: { uint32_t MAV_SENSOR_WATER = 0x20000000; mavlink_sys_status_t packet; mavlink_msg_sys_status_decode(msg, &packet); if ((packet.onboard_control_sensors_enabled & MAV_SENSOR_WATER) && !(packet.onboard_control_sensors_health & MAV_SENSOR_WATER)) { sub.leak_detector.set_detect(); } } break; default: handle_common_message(msg); break; } // end switch } // end handle mavlink
MAV_RESULT GCS_MAVLINK_Sub::handle_command_long_packet(const mavlink_command_long_t &packet) { switch (packet.command) { case MAV_CMD_NAV_LOITER_UNLIM: if (!sub.set_mode(POSHOLD, MODE_REASON_GCS_COMMAND)) { return MAV_RESULT_FAILED; } return MAV_RESULT_ACCEPTED; case MAV_CMD_NAV_LAND: if (!sub.set_mode(SURFACE, MODE_REASON_GCS_COMMAND)) { return MAV_RESULT_FAILED; } return MAV_RESULT_ACCEPTED; case MAV_CMD_CONDITION_YAW: // param1 : target angle [0-360] // param2 : speed during change [deg per second] // param3 : direction (-1:ccw, +1:cw) // param4 : relative offset (1) or absolute angle (0) if ((packet.param1 >= 0.0f) && (packet.param1 <= 360.0f) && (is_zero(packet.param4) || is_equal(packet.param4,1.0f))) { sub.set_auto_yaw_look_at_heading(packet.param1, packet.param2, (int8_t)packet.param3, (uint8_t)packet.param4); return MAV_RESULT_ACCEPTED; } return MAV_RESULT_FAILED; case MAV_CMD_DO_CHANGE_SPEED: // param1 : unused // param2 : new speed in m/s // param3 : unused // param4 : unused if (packet.param2 > 0.0f) { sub.wp_nav.set_speed_xy(packet.param2 * 100.0f); return MAV_RESULT_ACCEPTED; } return MAV_RESULT_FAILED; case MAV_CMD_DO_SET_HOME: // param1 : use current (1=use current location, 0=use specified location) // param5 : latitude // param6 : longitude // param7 : altitude (absolute) if (is_equal(packet.param1,1.0f) || (is_zero(packet.param5) && is_zero(packet.param6) && is_zero(packet.param7))) { if (sub.set_home_to_current_location(true)) { return MAV_RESULT_ACCEPTED; } } else { // ensure param1 is zero if (!is_zero(packet.param1)) { return MAV_RESULT_FAILED; } // sanity check location if (!check_latlng(packet.param5, packet.param6)) { return MAV_RESULT_FAILED; } Location new_home_loc; new_home_loc.lat = (int32_t)(packet.param5 * 1.0e7f); new_home_loc.lng = (int32_t)(packet.param6 * 1.0e7f); new_home_loc.alt = (int32_t)(packet.param7 * 100.0f); if (!sub.far_from_EKF_origin(new_home_loc)) { if (sub.set_home(new_home_loc, true)) { return MAV_RESULT_ACCEPTED; } } } return MAV_RESULT_FAILED; case MAV_CMD_MISSION_START: if (sub.motors.armed() && sub.set_mode(AUTO, MODE_REASON_GCS_COMMAND)) { return MAV_RESULT_ACCEPTED; } return MAV_RESULT_FAILED; case MAV_CMD_COMPONENT_ARM_DISARM: if (is_equal(packet.param1,1.0f)) { // attempt to arm and return success or failure if (sub.init_arm_motors(AP_Arming::ArmingMethod::MAVLINK)) { return MAV_RESULT_ACCEPTED; } } else if (is_zero(packet.param1)) { // force disarming by setting param2 = 21196 is deprecated // see COMMAND_LONG DO_FLIGHTTERMINATION sub.init_disarm_motors(); return MAV_RESULT_ACCEPTED; } else { return MAV_RESULT_UNSUPPORTED; } return MAV_RESULT_FAILED; #if AC_FENCE == ENABLED case MAV_CMD_DO_FENCE_ENABLE: switch ((uint16_t)packet.param1) { case 0: sub.fence.enable(false); return MAV_RESULT_ACCEPTED; case 1: sub.fence.enable(true); return MAV_RESULT_ACCEPTED; default: break; } return MAV_RESULT_FAILED; #endif case MAV_CMD_DO_MOTOR_TEST: // param1 : motor sequence number (a number from 1 to max number of motors on the vehicle) // param2 : throttle type (0=throttle percentage, 1=PWM, 2=pilot throttle channel pass-through. See MOTOR_TEST_THROTTLE_TYPE enum) // param3 : throttle (range depends upon param2) // param4 : timeout (in seconds) if (!sub.handle_do_motor_test(packet)) { return MAV_RESULT_FAILED; } return MAV_RESULT_ACCEPTED; default: return GCS_MAVLINK::handle_command_long_packet(packet); } }
MAV_RESULT GCS_MAVLINK_Rover::handle_command_long_packet(const mavlink_command_long_t &packet) { switch (packet.command) { case MAV_CMD_NAV_RETURN_TO_LAUNCH: rover.set_mode(rover.mode_rtl, MODE_REASON_GCS_COMMAND); return MAV_RESULT_ACCEPTED; #if MOUNT == ENABLED // Sets the region of interest (ROI) for the camera case MAV_CMD_DO_SET_ROI: // sanity check location if (!check_latlng(packet.param5, packet.param6)) { return MAV_RESULT_FAILED; } Location roi_loc; roi_loc.lat = (int32_t)(packet.param5 * 1.0e7f); roi_loc.lng = (int32_t)(packet.param6 * 1.0e7f); roi_loc.alt = (int32_t)(packet.param7 * 100.0f); if (roi_loc.lat == 0 && roi_loc.lng == 0 && roi_loc.alt == 0) { // switch off the camera tracking if enabled if (rover.camera_mount.get_mode() == MAV_MOUNT_MODE_GPS_POINT) { rover.camera_mount.set_mode_to_default(); } } else { // send the command to the camera mount rover.camera_mount.set_roi_target(roi_loc); } return MAV_RESULT_ACCEPTED; #endif #if MOUNT == ENABLED case MAV_CMD_DO_MOUNT_CONTROL: rover.camera_mount.control(packet.param1, packet.param2, packet.param3, (MAV_MOUNT_MODE) packet.param7); return MAV_RESULT_ACCEPTED; #endif case MAV_CMD_MISSION_START: rover.set_mode(rover.mode_auto, MODE_REASON_GCS_COMMAND); return MAV_RESULT_ACCEPTED; case MAV_CMD_COMPONENT_ARM_DISARM: if (is_equal(packet.param1, 1.0f)) { // run pre_arm_checks and arm_checks and display failures if (rover.arm_motors(AP_Arming::MAVLINK)) { return MAV_RESULT_ACCEPTED; } else { return MAV_RESULT_FAILED; } } else if (is_zero(packet.param1)) { if (rover.disarm_motors()) { return MAV_RESULT_ACCEPTED; } else { return MAV_RESULT_FAILED; } } return MAV_RESULT_UNSUPPORTED; case MAV_CMD_DO_FENCE_ENABLE: switch ((uint16_t)packet.param1) { case 0: rover.g2.fence.enable(false); return MAV_RESULT_ACCEPTED; case 1: rover.g2.fence.enable(true); return MAV_RESULT_ACCEPTED; default: break; } return MAV_RESULT_FAILED; case MAV_CMD_DO_CHANGE_SPEED: // param1 : unused // param2 : new speed in m/s if (!rover.control_mode->set_desired_speed(packet.param2)) { return MAV_RESULT_FAILED; } return MAV_RESULT_ACCEPTED; case MAV_CMD_DO_SET_HOME: { // param1 : use current (1=use current location, 0=use specified location) // param5 : latitude // param6 : longitude // param7 : altitude if (is_equal(packet.param1, 1.0f)) { if (rover.set_home_to_current_location(true)) { return MAV_RESULT_ACCEPTED; } } else { // ensure param1 is zero if (!is_zero(packet.param1)) { return MAV_RESULT_FAILED; } Location new_home_loc {}; new_home_loc.lat = static_cast<int32_t>(packet.param5 * 1.0e7f); new_home_loc.lng = static_cast<int32_t>(packet.param6 * 1.0e7f); new_home_loc.alt = static_cast<int32_t>(packet.param7 * 100.0f); if (rover.set_home(new_home_loc, true)) { return MAV_RESULT_ACCEPTED; } } return MAV_RESULT_FAILED; } case MAV_CMD_DO_SET_REVERSE: // param1 : Direction (0=Forward, 1=Reverse) rover.control_mode->set_reversed(is_equal(packet.param1,1.0f)); return MAV_RESULT_ACCEPTED; case MAV_CMD_NAV_SET_YAW_SPEED: { // param1 : yaw angle to adjust direction by in centidegress // param2 : Speed - normalized to 0 .. 1 // exit if vehicle is not in Guided mode if (rover.control_mode != &rover.mode_guided) { return MAV_RESULT_UNSUPPORTED; } // send yaw change and target speed to guided mode controller const float speed_max = rover.control_mode->get_speed_default(); const float target_speed = constrain_float(packet.param2 * speed_max, -speed_max, speed_max); rover.mode_guided.set_desired_heading_delta_and_speed(packet.param1, target_speed); return MAV_RESULT_ACCEPTED; } case MAV_CMD_DO_MOTOR_TEST: // param1 : motor sequence number (a number from 1 to max number of motors on the vehicle) // param2 : throttle type (0=throttle percentage, 1=PWM, 2=pilot throttle channel pass-through. See MOTOR_TEST_THROTTLE_TYPE enum) // param3 : throttle (range depends upon param2) // param4 : timeout (in seconds) return rover.mavlink_motor_test_start(chan, static_cast<uint8_t>(packet.param1), static_cast<uint8_t>(packet.param2), static_cast<int16_t>(packet.param3), packet.param4); default: return GCS_MAVLINK::handle_command_long_packet(packet); } }
void GCS_MAVLINK_Rover::handleMessage(mavlink_message_t* msg) { switch (msg->msgid) { case MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE: { // allow override of RC channel values for HIL // or for complete GCS control of switch position // and RC PWM values. if (msg->sysid != rover.g.sysid_my_gcs) { // Only accept control from our gcs break; } uint32_t tnow = AP_HAL::millis(); mavlink_rc_channels_override_t packet; mavlink_msg_rc_channels_override_decode(msg, &packet); RC_Channels::set_override(0, packet.chan1_raw, tnow); RC_Channels::set_override(1, packet.chan2_raw, tnow); RC_Channels::set_override(2, packet.chan3_raw, tnow); RC_Channels::set_override(3, packet.chan4_raw, tnow); RC_Channels::set_override(4, packet.chan5_raw, tnow); RC_Channels::set_override(5, packet.chan6_raw, tnow); RC_Channels::set_override(6, packet.chan7_raw, tnow); RC_Channels::set_override(7, packet.chan8_raw, tnow); break; } case MAVLINK_MSG_ID_MANUAL_CONTROL: { if (msg->sysid != rover.g.sysid_my_gcs) { // Only accept control from our gcs break; } mavlink_manual_control_t packet; mavlink_msg_manual_control_decode(msg, &packet); if (packet.target != rover.g.sysid_this_mav) { break; // only accept control aimed at us } uint32_t tnow = AP_HAL::millis(); const int16_t roll = (packet.y == INT16_MAX) ? 0 : rover.channel_steer->get_radio_min() + (rover.channel_steer->get_radio_max() - rover.channel_steer->get_radio_min()) * (packet.y + 1000) / 2000.0f; const int16_t throttle = (packet.z == INT16_MAX) ? 0 : rover.channel_throttle->get_radio_min() + (rover.channel_throttle->get_radio_max() - rover.channel_throttle->get_radio_min()) * (packet.z + 1000) / 2000.0f; RC_Channels::set_override(uint8_t(rover.rcmap.roll() - 1), roll, tnow); RC_Channels::set_override(uint8_t(rover.rcmap.throttle() - 1), throttle, tnow); break; } case MAVLINK_MSG_ID_HEARTBEAT: { // We keep track of the last time we received a heartbeat from our GCS for failsafe purposes if (msg->sysid != rover.g.sysid_my_gcs) { break; } rover.last_heartbeat_ms = AP_HAL::millis(); rover.failsafe_trigger(FAILSAFE_EVENT_GCS, false); break; } case MAVLINK_MSG_ID_SET_ATTITUDE_TARGET: // MAV ID: 82 { // decode packet mavlink_set_attitude_target_t packet; mavlink_msg_set_attitude_target_decode(msg, &packet); // exit if vehicle is not in Guided mode if (rover.control_mode != &rover.mode_guided) { break; } // ensure type_mask specifies to use thrust if ((packet.type_mask & MAVLINK_SET_ATT_TYPE_MASK_THROTTLE_IGNORE) != 0) { break; } // convert thrust to ground speed packet.thrust = constrain_float(packet.thrust, -1.0f, 1.0f); const float target_speed = rover.control_mode->get_speed_default() * packet.thrust; // if the body_yaw_rate field is ignored, convert quaternion to heading if ((packet.type_mask & MAVLINK_SET_ATT_TYPE_MASK_YAW_RATE_IGNORE) != 0) { // convert quaternion to heading float target_heading_cd = degrees(Quaternion(packet.q[0], packet.q[1], packet.q[2], packet.q[3]).get_euler_yaw()) * 100.0f; rover.mode_guided.set_desired_heading_and_speed(target_heading_cd, target_speed); } else { // use body_yaw_rate field rover.mode_guided.set_desired_turn_rate_and_speed((RAD_TO_DEG * packet.body_yaw_rate) * 100.0f, target_speed); } break; } case MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED: // MAV ID: 84 { // decode packet mavlink_set_position_target_local_ned_t packet; mavlink_msg_set_position_target_local_ned_decode(msg, &packet); // exit if vehicle is not in Guided mode if (rover.control_mode != &rover.mode_guided) { break; } // check for supported coordinate frames if (packet.coordinate_frame != MAV_FRAME_LOCAL_NED && packet.coordinate_frame != MAV_FRAME_LOCAL_OFFSET_NED && packet.coordinate_frame != MAV_FRAME_BODY_NED && packet.coordinate_frame != MAV_FRAME_BODY_OFFSET_NED) { break; } bool pos_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_POS_IGNORE; bool vel_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_VEL_IGNORE; bool acc_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_ACC_IGNORE; bool yaw_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_YAW_IGNORE; bool yaw_rate_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_YAW_RATE_IGNORE; // prepare target position Location target_loc = rover.current_loc; if (!pos_ignore) { switch (packet.coordinate_frame) { case MAV_FRAME_BODY_NED: case MAV_FRAME_BODY_OFFSET_NED: { // rotate from body-frame to NE frame const float ne_x = packet.x * rover.ahrs.cos_yaw() - packet.y * rover.ahrs.sin_yaw(); const float ne_y = packet.x * rover.ahrs.sin_yaw() + packet.y * rover.ahrs.cos_yaw(); // add offset to current location location_offset(target_loc, ne_x, ne_y); } break; case MAV_FRAME_LOCAL_OFFSET_NED: // add offset to current location location_offset(target_loc, packet.x, packet.y); break; default: // MAV_FRAME_LOCAL_NED interpret as an offset from home target_loc = rover.ahrs.get_home(); location_offset(target_loc, packet.x, packet.y); break; } } float target_speed = 0.0f; float target_yaw_cd = 0.0f; // consume velocity and convert to target speed and heading if (!vel_ignore) { const float speed_max = rover.control_mode->get_speed_default(); // convert vector length into a speed target_speed = constrain_float(safe_sqrt(sq(packet.vx) + sq(packet.vy)), -speed_max, speed_max); // convert vector direction to target yaw target_yaw_cd = degrees(atan2f(packet.vy, packet.vx)) * 100.0f; // rotate target yaw if provided in body-frame if (packet.coordinate_frame == MAV_FRAME_BODY_NED || packet.coordinate_frame == MAV_FRAME_BODY_OFFSET_NED) { target_yaw_cd = wrap_180_cd(target_yaw_cd + rover.ahrs.yaw_sensor); } } // consume yaw heading if (!yaw_ignore) { target_yaw_cd = ToDeg(packet.yaw) * 100.0f; // rotate target yaw if provided in body-frame if (packet.coordinate_frame == MAV_FRAME_BODY_NED || packet.coordinate_frame == MAV_FRAME_BODY_OFFSET_NED) { target_yaw_cd = wrap_180_cd(target_yaw_cd + rover.ahrs.yaw_sensor); } } // consume yaw rate float target_turn_rate_cds = 0.0f; if (!yaw_rate_ignore) { target_turn_rate_cds = ToDeg(packet.yaw_rate) * 100.0f; } // handling case when both velocity and either yaw or yaw-rate are provided // by default, we consider that the rover will drive forward float speed_dir = 1.0f; if (!vel_ignore && (!yaw_ignore || !yaw_rate_ignore)) { // Note: we are using the x-axis velocity to determine direction even though // the frame may have been provided in MAV_FRAME_LOCAL_OFFSET_NED or MAV_FRAME_LOCAL_NED if (is_negative(packet.vx)) { speed_dir = -1.0f; } } // set guided mode targets if (!pos_ignore) { // consume position target rover.mode_guided.set_desired_location(target_loc); } else if (pos_ignore && !vel_ignore && acc_ignore && yaw_ignore && yaw_rate_ignore) { // consume velocity rover.mode_guided.set_desired_heading_and_speed(target_yaw_cd, speed_dir * target_speed); } else if (pos_ignore && !vel_ignore && acc_ignore && yaw_ignore && !yaw_rate_ignore) { // consume velocity and turn rate rover.mode_guided.set_desired_turn_rate_and_speed(target_turn_rate_cds, speed_dir * target_speed); } else if (pos_ignore && !vel_ignore && acc_ignore && !yaw_ignore && yaw_rate_ignore) { // consume velocity rover.mode_guided.set_desired_heading_and_speed(target_yaw_cd, speed_dir * target_speed); } else if (pos_ignore && vel_ignore && acc_ignore && !yaw_ignore && yaw_rate_ignore) { // consume just target heading (probably only skid steering vehicles can do this) rover.mode_guided.set_desired_heading_and_speed(target_yaw_cd, 0.0f); } else if (pos_ignore && vel_ignore && acc_ignore && yaw_ignore && !yaw_rate_ignore) { // consume just turn rate(probably only skid steering vehicles can do this) rover.mode_guided.set_desired_turn_rate_and_speed(target_turn_rate_cds, 0.0f); } break; } case MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT: // MAV ID: 86 { // decode packet mavlink_set_position_target_global_int_t packet; mavlink_msg_set_position_target_global_int_decode(msg, &packet); // exit if vehicle is not in Guided mode if (rover.control_mode != &rover.mode_guided) { break; } // check for supported coordinate frames if (packet.coordinate_frame != MAV_FRAME_GLOBAL && packet.coordinate_frame != MAV_FRAME_GLOBAL_INT && packet.coordinate_frame != MAV_FRAME_GLOBAL_RELATIVE_ALT && packet.coordinate_frame != MAV_FRAME_GLOBAL_RELATIVE_ALT_INT && packet.coordinate_frame != MAV_FRAME_GLOBAL_TERRAIN_ALT && packet.coordinate_frame != MAV_FRAME_GLOBAL_TERRAIN_ALT_INT) { break; } bool pos_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_POS_IGNORE; bool vel_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_VEL_IGNORE; bool acc_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_ACC_IGNORE; bool yaw_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_YAW_IGNORE; bool yaw_rate_ignore = packet.type_mask & MAVLINK_SET_POS_TYPE_MASK_YAW_RATE_IGNORE; // prepare target position Location target_loc = rover.current_loc; if (!pos_ignore) { // sanity check location if (!check_latlng(packet.lat_int, packet.lon_int)) { // result = MAV_RESULT_FAILED; break; } target_loc.lat = packet.lat_int; target_loc.lng = packet.lon_int; } float target_speed = 0.0f; float target_yaw_cd = 0.0f; // consume velocity and convert to target speed and heading if (!vel_ignore) { const float speed_max = rover.control_mode->get_speed_default(); // convert vector length into a speed target_speed = constrain_float(safe_sqrt(sq(packet.vx) + sq(packet.vy)), -speed_max, speed_max); // convert vector direction to target yaw target_yaw_cd = degrees(atan2f(packet.vy, packet.vx)) * 100.0f; // rotate target yaw if provided in body-frame if (packet.coordinate_frame == MAV_FRAME_BODY_NED || packet.coordinate_frame == MAV_FRAME_BODY_OFFSET_NED) { target_yaw_cd = wrap_180_cd(target_yaw_cd + rover.ahrs.yaw_sensor); } } // consume yaw heading if (!yaw_ignore) { target_yaw_cd = ToDeg(packet.yaw) * 100.0f; // rotate target yaw if provided in body-frame if (packet.coordinate_frame == MAV_FRAME_BODY_NED || packet.coordinate_frame == MAV_FRAME_BODY_OFFSET_NED) { target_yaw_cd = wrap_180_cd(target_yaw_cd + rover.ahrs.yaw_sensor); } } // consume yaw rate float target_turn_rate_cds = 0.0f; if (!yaw_rate_ignore) { target_turn_rate_cds = ToDeg(packet.yaw_rate) * 100.0f; } // handling case when both velocity and either yaw or yaw-rate are provided // by default, we consider that the rover will drive forward float speed_dir = 1.0f; if (!vel_ignore && (!yaw_ignore || !yaw_rate_ignore)) { // Note: we are using the x-axis velocity to determine direction even though // the frame is provided in MAV_FRAME_GLOBAL_xxx if (is_negative(packet.vx)) { speed_dir = -1.0f; } } // set guided mode targets if (!pos_ignore) { // consume position target rover.mode_guided.set_desired_location(target_loc); } else if (pos_ignore && !vel_ignore && acc_ignore && yaw_ignore && yaw_rate_ignore) { // consume velocity rover.mode_guided.set_desired_heading_and_speed(target_yaw_cd, speed_dir * target_speed); } else if (pos_ignore && !vel_ignore && acc_ignore && yaw_ignore && !yaw_rate_ignore) { // consume velocity and turn rate rover.mode_guided.set_desired_turn_rate_and_speed(target_turn_rate_cds, speed_dir * target_speed); } else if (pos_ignore && !vel_ignore && acc_ignore && !yaw_ignore && yaw_rate_ignore) { // consume velocity rover.mode_guided.set_desired_heading_and_speed(target_yaw_cd, speed_dir * target_speed); } else if (pos_ignore && vel_ignore && acc_ignore && !yaw_ignore && yaw_rate_ignore) { // consume just target heading (probably only skid steering vehicles can do this) rover.mode_guided.set_desired_heading_and_speed(target_yaw_cd, 0.0f); } else if (pos_ignore && vel_ignore && acc_ignore && yaw_ignore && !yaw_rate_ignore) { // consume just turn rate(probably only skid steering vehicles can do this) rover.mode_guided.set_desired_turn_rate_and_speed(target_turn_rate_cds, 0.0f); } break; } #if HIL_MODE != HIL_MODE_DISABLED case MAVLINK_MSG_ID_HIL_STATE: { mavlink_hil_state_t packet; mavlink_msg_hil_state_decode(msg, &packet); // sanity check location if (!check_latlng(packet.lat, packet.lon)) { break; } // set gps hil sensor Location loc; loc.lat = packet.lat; loc.lng = packet.lon; loc.alt = packet.alt/10; Vector3f vel(packet.vx, packet.vy, packet.vz); vel *= 0.01f; gps.setHIL(0, AP_GPS::GPS_OK_FIX_3D, packet.time_usec/1000, loc, vel, 10, 0); // rad/sec Vector3f gyros; gyros.x = packet.rollspeed; gyros.y = packet.pitchspeed; gyros.z = packet.yawspeed; // m/s/s Vector3f accels; accels.x = packet.xacc * (GRAVITY_MSS/1000.0f); accels.y = packet.yacc * (GRAVITY_MSS/1000.0f); accels.z = packet.zacc * (GRAVITY_MSS/1000.0f); ins.set_gyro(0, gyros); ins.set_accel(0, accels); compass.setHIL(0, packet.roll, packet.pitch, packet.yaw); compass.setHIL(1, packet.roll, packet.pitch, packet.yaw); break; } #endif // HIL_MODE #if MOUNT == ENABLED // deprecated. Use MAV_CMD_DO_MOUNT_CONFIGURE case MAVLINK_MSG_ID_MOUNT_CONFIGURE: { rover.camera_mount.configure_msg(msg); break; } // deprecated. Use MAV_CMD_DO_MOUNT_CONTROL case MAVLINK_MSG_ID_MOUNT_CONTROL: { rover.camera_mount.control_msg(msg); break; } #endif // MOUNT == ENABLED case MAVLINK_MSG_ID_RADIO: case MAVLINK_MSG_ID_RADIO_STATUS: { handle_radio_status(msg, rover.DataFlash, rover.should_log(MASK_LOG_PM)); break; } // send or receive fence points with GCS case MAVLINK_MSG_ID_FENCE_POINT: // MAV ID: 160 case MAVLINK_MSG_ID_FENCE_FETCH_POINT: rover.g2.fence.handle_msg(*this, msg); break; case MAVLINK_MSG_ID_DISTANCE_SENSOR: rover.rangefinder.handle_msg(msg); rover.g2.proximity.handle_msg(msg); break; default: handle_common_message(msg); break; } // end switch } // end handle mavlink
MAV_RESULT GCS_MAVLINK_Plane::handle_command_int_packet(const mavlink_command_int_t &packet) { switch(packet.command) { case MAV_CMD_DO_REPOSITION: { // sanity check location if (!check_latlng(packet.x, packet.y)) { return MAV_RESULT_FAILED; } Location requested_position {}; requested_position.lat = packet.x; requested_position.lng = packet.y; // check the floating representation for overflow of altitude if (fabsf(packet.z * 100.0f) >= 0x7fffff) { return MAV_RESULT_FAILED; } requested_position.alt = (int32_t)(packet.z * 100.0f); // load option flags if (packet.frame == MAV_FRAME_GLOBAL_RELATIVE_ALT_INT) { requested_position.relative_alt = 1; } else if (packet.frame == MAV_FRAME_GLOBAL_TERRAIN_ALT_INT) { requested_position.terrain_alt = 1; } else if (packet.frame != MAV_FRAME_GLOBAL_INT) { // not a supported frame return MAV_RESULT_FAILED; } if (is_zero(packet.param4)) { requested_position.loiter_ccw = 0; } else { requested_position.loiter_ccw = 1; } if (requested_position.sanitize(plane.current_loc)) { // if the location wasn't already sane don't load it return MAV_RESULT_FAILED; // failed as the location is not valid } // location is valid load and set if (((int32_t)packet.param2 & MAV_DO_REPOSITION_FLAGS_CHANGE_MODE) || (plane.control_mode == &plane.mode_guided)) { plane.set_mode(plane.mode_guided, MODE_REASON_GCS_COMMAND); plane.guided_WP_loc = requested_position; // add home alt if needed if (plane.guided_WP_loc.relative_alt) { plane.guided_WP_loc.alt += plane.home.alt; plane.guided_WP_loc.relative_alt = 0; } plane.set_guided_WP(); return MAV_RESULT_ACCEPTED; } return MAV_RESULT_FAILED; } default: return GCS_MAVLINK::handle_command_int_packet(packet); } }