mirror of
https://github.com/ArduPilot/ardupilot.git
synced 2026-10-02 10:23:25 +08:00
Rewrote a stored RCn_OPTION of ARMDISARM_UNUSED (41) to ARMDISARM (153), and Rover's SAVE_TRIM (5) to TRIM_TO_CURRENT_SERVO_RC (155). Both were added Sep-2021 and are present in Rover-4.2.0, so anybody moving from Rover-4.4.0 - the oldest release a Rover user can be moving from once the migration floor is 4.3, as Rover has no 4.3 - has already had them applied. A stored 41 or 5 which survives becomes an unhandled auxiliary function on Rover and does nothing, which is the same outcome as any other option number this firmware does not know.
366 lines
9.9 KiB
C++
366 lines
9.9 KiB
C++
#include "Rover.h"
|
|
|
|
static void failsafe_check_static()
|
|
{
|
|
rover.failsafe_check();
|
|
}
|
|
|
|
void Rover::init_ardupilot()
|
|
{
|
|
// initialise notify system
|
|
notify.init();
|
|
notify_mode(control_mode);
|
|
|
|
battery.init();
|
|
|
|
#if AP_RSSI_ENABLED
|
|
rssi.init();
|
|
#endif
|
|
|
|
g2.windvane.init(serial_manager);
|
|
|
|
// init baro before we start the GCS, so that the CLI baro test works
|
|
barometer.init();
|
|
|
|
// setup telem slots with serial ports
|
|
gcs().setup_uarts();
|
|
|
|
#if OSD_ENABLED
|
|
osd.init();
|
|
#endif
|
|
|
|
// initialise compass
|
|
AP::compass().set_log_bit(MASK_LOG_COMPASS);
|
|
AP::compass().init();
|
|
|
|
#if AP_AIRSPEED_ENABLED
|
|
airspeed.set_log_bit(MASK_LOG_IMU);
|
|
#endif
|
|
|
|
#if AP_RANGEFINDER_ENABLED
|
|
// initialise rangefinder
|
|
rangefinder.set_log_rfnd_bit(MASK_LOG_RANGEFINDER);
|
|
rangefinder.init(ROTATION_NONE);
|
|
#endif
|
|
|
|
#if HAL_PROXIMITY_ENABLED
|
|
// init proximity sensor
|
|
g2.proximity.init();
|
|
#endif
|
|
|
|
// and baro for EKF
|
|
barometer.set_log_baro_bit(MASK_LOG_IMU);
|
|
barometer.calibrate();
|
|
|
|
// Do GPS init
|
|
gps.set_log_gps_bit(MASK_LOG_GPS);
|
|
gps.init();
|
|
|
|
ins.set_log_raw_bit(MASK_LOG_IMU_RAW);
|
|
|
|
init_rc_in(); // sets up rc channels deadzone
|
|
g2.motors.init(get_frame_type()); // init motors including setting servo out channels ranges
|
|
AP::srv().enable_aux_servos();
|
|
|
|
// init wheel encoders
|
|
g2.wheel_encoder.init();
|
|
|
|
#if HAL_TORQEEDO_ENABLED
|
|
// init torqeedo motor driver
|
|
g2.torqeedo.init();
|
|
#endif
|
|
|
|
#if AP_OPTICALFLOW_ENABLED
|
|
// initialise optical flow sensor
|
|
optflow.init(MASK_LOG_OPTFLOW);
|
|
#endif // AP_OPTICALFLOW_ENABLED
|
|
|
|
#if AP_RELAY_ENABLED
|
|
relay.init();
|
|
#endif
|
|
|
|
#if HAL_MOUNT_ENABLED
|
|
// initialise camera mount
|
|
camera_mount.init();
|
|
#endif
|
|
|
|
#if AP_CAMERA_ENABLED
|
|
// initialise camera
|
|
camera.init();
|
|
#endif
|
|
|
|
#if AC_PRECLAND_ENABLED
|
|
// initialise precision landing
|
|
init_precland();
|
|
#endif
|
|
|
|
/*
|
|
setup the 'main loop is dead' check. Note that this relies on
|
|
the RC library being initialised.
|
|
*/
|
|
hal.scheduler->register_timer_failsafe(failsafe_check_static, 1000);
|
|
|
|
// initialize SmartRTL
|
|
g2.smart_rtl.init();
|
|
|
|
#if AP_OAPATHPLANNER_ENABLED
|
|
// initialise object avoidance
|
|
g2.oa.init();
|
|
#endif
|
|
|
|
set_mode(mode_initializing, ModeReason::INITIALISED);
|
|
|
|
startup_INS();
|
|
|
|
#if AP_MISSION_ENABLED
|
|
// initialise mission library
|
|
mode_auto.mission.init();
|
|
#if HAL_LOGGING_ENABLED
|
|
mode_auto.mission.set_log_start_mission_item_bit(MASK_LOG_CMD);
|
|
#endif
|
|
#endif
|
|
|
|
// initialise AP_Logger library
|
|
#if HAL_LOGGING_ENABLED
|
|
logger.setVehicle_Startup_Writer(
|
|
FUNCTOR_BIND(&rover, &Rover::Log_Write_Vehicle_Startup_Messages, void)
|
|
);
|
|
#endif
|
|
|
|
Mode *initial_mode = mode_from_mode_num((enum Mode::Number)g.initial_mode.get());
|
|
if (initial_mode == nullptr) {
|
|
initial_mode = &mode_initializing;
|
|
}
|
|
set_mode(*initial_mode, ModeReason::INITIALISED);
|
|
|
|
// initialise rc channels
|
|
rc().init();
|
|
|
|
rover.g2.sailboat.init();
|
|
|
|
// boat should loiter after completing a mission to avoid drifting off
|
|
if (is_boat()) {
|
|
rover.g2.mis_done_behave.set_default(uint8_t(ModeAuto::DoneBehaviour::LOITER));
|
|
}
|
|
|
|
// flag that initialisation has completed
|
|
initialised = true;
|
|
}
|
|
|
|
// update the ahrs flyforward setting which can allow
|
|
// the vehicle's movements to be used to estimate heading
|
|
void Rover::update_ahrs_flyforward()
|
|
{
|
|
bool flyforward = false;
|
|
|
|
// boats never use movement to estimate heading
|
|
if (!is_boat()) {
|
|
// throttle threshold is 15% or 1/2 cruise throttle
|
|
bool throttle_over_thresh = g2.motors.get_throttle() > MIN(g.throttle_cruise * 0.50f, 15.0f);
|
|
// desired speed threshold of 1m/s
|
|
bool desired_speed_over_thresh = g2.attitude_control.speed_control_active() && (g2.attitude_control.get_desired_speed() > 0.5f);
|
|
if (throttle_over_thresh || (is_positive(g2.motors.get_throttle()) && desired_speed_over_thresh)) {
|
|
uint32_t now = AP_HAL::millis();
|
|
// if throttle over threshold start timer
|
|
if (flyforward_start_ms == 0) {
|
|
flyforward_start_ms = now;
|
|
}
|
|
// if throttle over threshold for 2 seconds set flyforward to true
|
|
flyforward = (now - flyforward_start_ms > 2000);
|
|
} else {
|
|
// reset timer
|
|
flyforward_start_ms = 0;
|
|
}
|
|
}
|
|
|
|
ahrs.set_fly_forward(flyforward);
|
|
}
|
|
|
|
// Check if this mode can be entered from the GCS
|
|
bool Rover::gcs_mode_enabled(const Mode::Number mode_num) const
|
|
{
|
|
// List of modes that can be blocked, index is bit number in parameter bitmask
|
|
static const uint8_t mode_list [] {
|
|
(uint8_t)Mode::Number::MANUAL,
|
|
(uint8_t)Mode::Number::ACRO,
|
|
(uint8_t)Mode::Number::STEERING,
|
|
(uint8_t)Mode::Number::LOITER,
|
|
(uint8_t)Mode::Number::FOLLOW,
|
|
(uint8_t)Mode::Number::SIMPLE,
|
|
(uint8_t)Mode::Number::CIRCLE,
|
|
(uint8_t)Mode::Number::AUTO,
|
|
(uint8_t)Mode::Number::RTL,
|
|
(uint8_t)Mode::Number::SMART_RTL,
|
|
(uint8_t)Mode::Number::GUIDED,
|
|
#if MODE_DOCK_ENABLED
|
|
(uint8_t)Mode::Number::DOCK
|
|
#endif
|
|
};
|
|
|
|
return !block_GCS_mode_change((uint8_t)mode_num, mode_list, ARRAY_SIZE(mode_list));
|
|
}
|
|
|
|
// Return mask of enabled modes, order does not matter, its just for tracking changes
|
|
uint32_t Rover::get_available_mode_enabled_mask() const
|
|
{
|
|
const Mode* flight_modes[] {
|
|
&rover.mode_manual,
|
|
&rover.mode_acro,
|
|
&rover.mode_steering,
|
|
&rover.mode_hold,
|
|
&rover.mode_loiter,
|
|
#if MODE_FOLLOW_ENABLED
|
|
&rover.mode_follow,
|
|
#endif
|
|
&rover.mode_simple,
|
|
&rover.g2.mode_circle,
|
|
&rover.mode_auto,
|
|
&rover.mode_rtl,
|
|
&rover.mode_smartrtl,
|
|
&rover.mode_guided,
|
|
&rover.mode_initializing,
|
|
#if MODE_DOCK_ENABLED
|
|
(Mode *)rover.g2.mode_dock_ptr,
|
|
#endif
|
|
};
|
|
|
|
static_assert(ARRAY_SIZE(flight_modes) <= 32, "Flight modes must fit in 32 bit bitmask");
|
|
|
|
uint32_t mask = 0;
|
|
for (uint8_t i = 0; i < ARRAY_SIZE(flight_modes); i++) {
|
|
const Mode* mode = flight_modes[i];
|
|
|
|
// the check here must be the same as the one in `send_available_mode`
|
|
const bool user_selectable = mode->enabled() && rover.gcs_mode_enabled(mode->mode_number());
|
|
|
|
if (user_selectable) {
|
|
mask |= 1U << i;
|
|
}
|
|
}
|
|
|
|
return mask;
|
|
}
|
|
|
|
|
|
bool Rover::set_mode(Mode &new_mode, ModeReason reason)
|
|
{
|
|
if (control_mode == &new_mode) {
|
|
// don't switch modes if we are already in the correct mode.
|
|
return true;
|
|
}
|
|
|
|
// Check if GCS mode change is disabled via parameter
|
|
if ((reason == ModeReason::GCS_COMMAND) && !gcs_mode_enabled((Mode::Number)new_mode.mode_number())) {
|
|
GCS_SEND_TEXT(MAV_SEVERITY_NOTICE,"Mode change to %s denied, GCS entry disabled (FLTMODE_GCSBLOCK)", new_mode.name());
|
|
return false;
|
|
}
|
|
|
|
Mode &old_mode = *control_mode;
|
|
if (!new_mode.enter()) {
|
|
// Log error that we failed to enter desired flight mode
|
|
LOGGER_WRITE_ERROR(LogErrorSubsystem::FLIGHT_MODE,
|
|
LogErrorCode(new_mode.mode_number()));
|
|
GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "Flight mode change failed");
|
|
return false;
|
|
}
|
|
|
|
control_mode = &new_mode;
|
|
|
|
#if AP_FENCE_ENABLED
|
|
// pilot requested flight mode change during a fence breach indicates pilot is attempting to manually recover
|
|
// this flight mode change could be automatic (i.e. fence, battery, GPS or GCS failsafe)
|
|
// but it should be harmless to disable the fence temporarily in these situations as well
|
|
fence.manual_recovery_start();
|
|
#endif
|
|
|
|
#if AP_CAMERA_ENABLED
|
|
camera.set_is_auto_mode(control_mode->mode_number() == Mode::Number::AUTO);
|
|
#endif
|
|
|
|
old_mode.exit();
|
|
|
|
control_mode_reason = reason;
|
|
#if HAL_LOGGING_ENABLED
|
|
logger.Write_Mode((uint8_t)control_mode->mode_number(), control_mode_reason);
|
|
#endif
|
|
gcs().send_message(MSG_HEARTBEAT);
|
|
|
|
notify_mode(control_mode);
|
|
return true;
|
|
}
|
|
|
|
bool Rover::set_mode(const uint8_t new_mode, ModeReason reason)
|
|
{
|
|
static_assert(sizeof(Mode::Number) == sizeof(new_mode), "The new mode can't be mapped to the vehicles mode number");
|
|
return rover.set_mode(static_cast<Mode::Number>(new_mode), reason);
|
|
}
|
|
|
|
bool Rover::set_mode(Mode::Number new_mode, ModeReason reason)
|
|
{
|
|
Mode *mode = rover.mode_from_mode_num(new_mode);
|
|
if (mode == nullptr) {
|
|
notify_no_such_mode((uint8_t)new_mode);
|
|
return false;
|
|
}
|
|
return rover.set_mode(*mode, reason);
|
|
}
|
|
|
|
void Rover::startup_INS(void)
|
|
{
|
|
GCS_SEND_TEXT(MAV_SEVERITY_INFO, "Beginning INS calibration. Do not move vehicle");
|
|
hal.scheduler->delay(100);
|
|
|
|
ahrs.init();
|
|
// say to EKF that rover only move by going forward
|
|
ahrs.set_fly_forward(true);
|
|
ahrs.set_vehicle_class(AP_AHRS::VehicleClass::GROUND);
|
|
|
|
ins.init(scheduler.get_loop_rate_hz());
|
|
ahrs.reset();
|
|
}
|
|
|
|
// update notify with mode change
|
|
void Rover::notify_mode(const Mode *mode)
|
|
{
|
|
AP_Notify::flags.autopilot_mode = mode->is_autopilot_mode();
|
|
notify.flags.flight_mode = (uint8_t)mode->mode_number();
|
|
notify.set_flight_mode_str(mode->name4());
|
|
}
|
|
|
|
/*
|
|
check a digital pin for high,low (1/0)
|
|
*/
|
|
uint8_t Rover::check_digital_pin(uint8_t pin)
|
|
{
|
|
// ensure we are in input mode
|
|
hal.gpio->pinMode(pin, HAL_GPIO_INPUT);
|
|
|
|
// enable pullup
|
|
hal.gpio->write(pin, 1);
|
|
|
|
return hal.gpio->read(pin);
|
|
}
|
|
|
|
#if HAL_LOGGING_ENABLED
|
|
/*
|
|
should we log a message type now?
|
|
*/
|
|
bool Rover::should_log(uint32_t mask)
|
|
{
|
|
return logger.should_log(mask);
|
|
}
|
|
#endif
|
|
|
|
// returns true if vehicle is a boat
|
|
// this affects whether the vehicle tries to maintain position after reaching waypoints
|
|
bool Rover::is_boat() const
|
|
{
|
|
return ((enum frame_class)g2.frame_class.get() == FRAME_BOAT);
|
|
}
|
|
|
|
#include <AP_Avoidance/AP_Avoidance.h>
|
|
#if AP_ADSB_AVOIDANCE_ENABLED
|
|
// dummy method to avoid linking AP_Avoidance
|
|
AP_Avoidance *AP::ap_avoidance() { return nullptr; }
|
|
#endif // AP_ADSB_AVOIDANCE_ENABLED
|