/***************************************************************************** The init_ardupilot function processes everything we need for an in - air restart We will determine later if we are actually on the ground and process a ground start in that case. *****************************************************************************/ #include "Rover.h" static void mavlink_delay_cb_static() { rover.mavlink_delay_cb(); } static void failsafe_check_static() { rover.failsafe_check(); } void Rover::init_ardupilot() { // initialise console serial port serial_manager.init_console(); hal.console->printf("\n\nInit %s" "\n\nFree RAM: %u\n", AP::fwversion().fw_string, (unsigned)hal.util->available_memory()); // // Check the EEPROM format version before loading any parameters from EEPROM. // load_parameters(); #if STATS_ENABLED == ENABLED // initialise stats module g2.stats.init(); #endif mavlink_system.sysid = g.sysid_this_mav; // initialise serial ports serial_manager.init(); // setup first port early to allow BoardConfig to report errors gcs().chan(0).setup_uart(serial_manager, AP_SerialManager::SerialProtocol_MAVLink, 0); // Register mavlink_delay_cb, which will run anytime you have // more than 5ms remaining in your call to hal.scheduler->delay hal.scheduler->register_delay_callback(mavlink_delay_cb_static, 5); BoardConfig.init(); #if HAL_WITH_UAVCAN BoardConfig_CAN.init(); #endif // init gripper #if GRIPPER_ENABLED == ENABLED g2.gripper.init(); #endif // initialise notify system notify.init(); notify_mode(control_mode); battery.init(); // Initialise RPM sensor rpm_sensor.init(); rssi.init(); g2.airspeed.init(); g2.windvane.init(); // 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(serial_manager); // setup frsky telemetry #if FRSKY_TELEM_ENABLED == ENABLED frsky_telemetry.init((is_boat() ? MAV_TYPE_SURFACE_BOAT : MAV_TYPE_GROUND_ROVER)); #endif #if DEVO_TELEM_ENABLED == ENABLED devo_telemetry.init(); #endif #if OSD_ENABLED == ENABLED osd.init(); #endif #if LOGGING_ENABLED == ENABLED log_init(); #endif // initialise compass init_compass(); // initialise rangefinder rangefinder.init(); // init proximity sensor init_proximity(); // init beacons used for non-gps position estimation init_beacon(); // init visual odometry init_visual_odom(); // 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(serial_manager); ins.set_log_raw_bit(MASK_LOG_IMU_RAW); set_control_channels(); // setup radio channels and ouputs ranges init_rc_in(); // sets up rc channels deadzone g2.motors.init(); // init motors including setting servo out channels ranges SRV_Channels::enable_aux_servos(); // init wheel encoders g2.wheel_encoder.init(); relay.init(); #if MOUNT == ENABLED // initialise camera mount camera_mount.init(serial_manager); #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); // give AHRS the range beacon sensor ahrs.set_beacon(&g2.beacon); // initialize SmartRTL g2.smart_rtl.init(); startup_ground(); 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, MODE_REASON_INITIALISED); // initialise rc channels rc().init(); // disable safety if requested BoardConfig.init_safety(); // flag that initialisation has completed initialised = true; } //********************************************************************************* // This function does all the calibrations, etc. that we need during a ground start //********************************************************************************* void Rover::startup_ground(void) { set_mode(mode_initializing, MODE_REASON_INITIALISED); gcs().send_text(MAV_SEVERITY_INFO, " Ground start"); #if(GROUND_START_DELAY > 0) gcs().send_text(MAV_SEVERITY_NOTICE, " With delay"); delay(GROUND_START_DELAY * 1000); #endif // IMU ground start //------------------------ // startup_INS_ground(); // initialise mission library mode_auto.mission.init(); // initialise AP_Logger library #if LOGGING_ENABLED == ENABLED logger.setVehicle_Startup_Writer( FUNCTOR_BIND(&rover, &Rover::Log_Write_Vehicle_Startup_Messages, void) ); #endif #ifdef ENABLE_SCRIPTING if (!g2.scripting.init()) { gcs().send_text(MAV_SEVERITY_ERROR, "Scripting failed to start"); } #endif // ENABLE_SCRIPTING // we don't want writes to the serial port to cause us to pause // so set serial ports non-blocking once we are ready to drive serial_manager.set_blocking_writes_all(false); gcs().send_text(MAV_SEVERITY_INFO, "Ready to drive"); } // 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); } bool Rover::set_mode(Mode &new_mode, mode_reason_t reason) { if (control_mode == &new_mode) { // don't switch modes if we are already in the correct mode. return true; } Mode &old_mode = *control_mode; if (!new_mode.enter()) { // Log error that we failed to enter desired flight mode Log_Write_Error(ERROR_SUBSYSTEM_FLIGHT_MODE, new_mode.mode_number()); gcs().send_text(MAV_SEVERITY_WARNING, "Flight mode change failed"); return false; } control_mode = &new_mode; // 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 g2.fence.manual_recovery_start(); #if FRSKY_TELEM_ENABLED == ENABLED frsky_telemetry.update_control_mode(control_mode->mode_number()); #endif #if DEVO_TELEM_ENABLED == ENABLED devo_telemetry.update_control_mode(control_mode->mode_number()); #endif #if CAMERA == ENABLED camera.set_is_auto_mode(control_mode->mode_number() == Mode::Number::AUTO); #endif old_mode.exit(); control_mode_reason = reason; logger.Write_Mode(control_mode->mode_number(), control_mode_reason); notify_mode(control_mode); return true; } void Rover::startup_INS_ground(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 goind forward ahrs.set_fly_forward(true); ahrs.set_vehicle_class(AHRS_VEHICLE_GROUND); ins.init(scheduler.get_loop_rate_hz()); ahrs.reset(); } // update notify with mode change void Rover::notify_mode(const Mode *mode) { notify.flags.flight_mode = mode->mode_number(); notify.set_flight_mode_str(mode->name4()); } /* check a digitial 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); } /* should we log a message type now? */ bool Rover::should_log(uint32_t mask) { return logger.should_log(mask); } /* update AHRS soft arm state and log as needed */ void Rover::change_arm_state(void) { Log_Write_Arm_Disarm(); update_soft_armed(); } /* arm motors */ bool Rover::arm_motors(AP_Arming::ArmingMethod method) { if (!arming.arm(method)) { AP_Notify::events.arming_failed = true; return false; } // Set the SmartRTL home location. If activated, SmartRTL will ultimately try to land at this point g2.smart_rtl.set_home(true); // initialize simple mode heading rover.mode_simple.init_heading(); // save home heading for use in sail vehicles rover.g2.windvane.record_home_heading(); change_arm_state(); return true; } /* disarm motors */ bool Rover::disarm_motors(void) { if (!arming.disarm()) { return false; } if (control_mode != &mode_auto) { // reset the mission on disarm if we are not in auto mode_auto.mission.reset(); } // only log if disarming was successful change_arm_state(); return true; } // 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); }