ArduPilot开源飞控之AP_Mount_Backend

ArduPilot开源飞控之AP_Mount_Backend

  • 1. 源由
  • 2. 框架设计
    • 2.1 类构造函数
    • 2.2 公共方法
      • 2.2.1 重要方法
      • 2.2.2 运动能力(需要在子类中重写)
      • 2.2.3 模式处理
      • 2.2.4 目标处理
      • 2.2.5 命令处理
      • 2.2.6 消息传递和状态
      • 2.2.7 回调函数
      • 2.2.8 相机控制
      • 2.2.9 测距仪
    • 2.3 保护成员
  • 3. 重要函数
    • 3.1 重要方法
      • 3.1.1 AP_Mount_Backend::AP_Mount_Backend
      • 3.1.2 AP_Mount_Backend::init
      • 3.1.3 AP_Mount_Backend::set_dev_id
      • 3.1.4 AP_Mount_Backend::update/update_fast
    • 3.2 运动能力
      • 3.2.1 AP_Mount_Backend::healthy
      • 3.2.2 AP_Mount_Backend::has_roll_control
      • 3.2.3 AP_Mount_Backend::has_pitch_control
      • 3.2.4 AP_Mount_Backend::has_pan_control
    • 3.3 模式处理
      • 3.3.1 AP_Mount_Backend::valid_mode
      • 3.3.2 AP_Mount_Backend::set_mode
      • 3.3.3 AP_Mount_Backend::get_mode
    • 3.4 目标处理
      • 3.4.1 AP_Mount_Backend::set_roi_target
      • 3.4.2 AP_Mount_Backend::clear_roi_target
      • 3.4.3 AP_Mount_Backend::get_angle_target_to_roi
      • 3.4.4 AP_Mount_Backend::calculate_poi
    • 3.5 命令处理
      • 3.5.1 AP_Mount_Backend::handle_command_do_mount_control
      • 3.5.2 AP_Mount_Backend::handle_command_do_gimbal_manager_configure
    • 3.6 消息传递和状态
      • 3.6.1 AP_Mount_Backend::send_gimbal_device_attitude_status
      • 3.6.2 AP_Mount_Backend::send_gimbal_manager_information
    • 3.7 回调函数
      • 3.7.1 AP_Mount_Backend::handle_gimbal_report
      • 3.7.2 AP_Mount_Backend::handle_param_value
    • 3.8 相机控制
      • 3.8.1 AP_Mount_Backend::take_picture
      • 3.8.2 AP_Mount_Backend::record_video
      • 3.8.3 AP_Mount_Backend::set_zoom
    • 3.9 测距仪
      • 3.9.1 AP_Mount_Backend::get_rangefinder_distance
      • 3.9.2 AP_Mount_Backend::set_rangefinder_enable
    • 3.10 辅助函数
      • 3.10.1 AP_Mount_Backend::get_angle_target_to_location
      • 3.10.2 AP_Mount_Backend::set_angle_target
  • 4. 总结
  • 5. 参考资料

1. 源由

AP_Mount_Backend是云台设备模版,抽象云台设备操作方法,并在该类中得以实现。

提供了一个全面的接口,用于控制和监控安装设备(云台),集成了各种功能,如目标跟踪、模式设置、命令处理和通过 MAVLink 消息与地面控制系统通信。它设计灵活,可能用于适配不同类型的安装设备及其特定需求。

2. 框架设计

2.1 类构造函数

  • 构造函数:初始化后端实例,传入前端引用 (AP_Mount)、参数 (AP_Mount_Params) 和实例编号 (instance)。

2.2 公共方法

2.2.1 重要方法

  • 初始化方法virtual void init(); - 执行实例的初始化。
  • 设备ID设置void set_dev_id(uint32_t id); - 设置设备ID。
  • 更新方法
    • virtual void update() = 0; - 纯虚函数,用于更新安装设备的位置。
    • virtual void update_fast() {} - 可选方法,用于更快速的更新,这里没有具体实现。

2.2.2 运动能力(需要在子类中重写)

  • 健康检查virtual bool healthy() const; - 表示安装设备是否正常工作。
  • 控制能力
    • virtual bool has_roll_control() const; - 是否具有横滚控制能力。
    • virtual bool has_pitch_control() const; - 是否具有俯仰控制能力。
    • virtual bool has_pan_control() const = 0; - 是否可以控制偏航,纯虚函数。

2.2.3 模式处理

  • bool valid_mode(MAV_MOUNT_MODE mode) const; - 检查模式是否有效。
  • enum MAV_MOUNT_MODE get_mode() const; - 获取当前模式。
  • bool set_mode(enum MAV_MOUNT_MODE mode); - 设置模式。

2.2.4 目标处理

  • 方法用于设置角度和速率目标,处理兴趣区域(ROI)目标和系统目标,比如calculate_poi 等。

2.2.5 命令处理

  • 处理来自 MAVLink 消息的命令的方法,例如 do_mount_controldo_gimbal_manager_configure

2.2.6 消息传递和状态

  • 发送状态消息到 MAVLink 通道的方法(send_gimbal_device_attitude_statussend_gimbal_manager_information 等)。

2.2.7 回调函数

  • 处理各种 MAVLink 消息的回调方法(handle_gimbal_reporthandle_param_value 等)。

2.2.8 相机控制

  • 控制相机的方法,例如拍照 (take_picture)、录像 (record_video)、设置变焦 (set_zoom) 等。

2.2.9 测距仪

  • 与测距仪交互的方法(get_rangefinder_distanceset_rangefinder_enable)。

2.3 保护成员

  • 内部使用的枚举和结构体(MountTargetTypeOptionsMountTarget 等)。
  • 辅助方法(option_setyaw_range_valid 等)和内部状态变量(_mode_yaw_lock_roi_target 等)。

3. 重要函数

3.1 重要方法

3.1.1 AP_Mount_Backend::AP_Mount_Backend

构造函数,初始化以下几个成员变量:

  • _frontend
  • _params
  • _instance
    // ConstructorAP_Mount_Backend(class AP_Mount &frontend, class AP_Mount_Params &params, uint8_t instance) :_frontend(frontend),_params(params),_instance(instance){}

3.1.2 AP_Mount_Backend::init

启动线程calculate_poi进行计算

// Default init function for every mount
void AP_Mount_Backend::init()
{// setting default target sysid from parameters_target_sysid = _params.sysid_default.get();#if AP_MOUNT_POI_TO_LATLONALT_ENABLED// create a calculation thread for poi.if (!hal.scheduler->thread_create(FUNCTOR_BIND_MEMBER(&AP_Mount_Backend::calculate_poi, void),"mount_calc_poi",8192, AP_HAL::Scheduler::PRIORITY_IO, -1)) {GCS_SEND_TEXT(MAV_SEVERITY_ERROR, "Mount: failed to start POI thread");}
#endif
}

3.1.3 AP_Mount_Backend::set_dev_id

设置设备DEV_ID。

// set device id of this instance, for MNTx_DEVID parameter
void AP_Mount_Backend::set_dev_id(uint32_t id)
{_params.dev_id.set_and_save(int32_t(id));
}

3.1.4 AP_Mount_Backend::update/update_fast

  • update函数必须在继承设备类中实现
  • update_fast一般不需要实现
    // update mount position - should be called periodicallyvirtual void update() = 0;// used for gimbals that need to read INS data at full ratevirtual void update_fast() {}

3.2 运动能力

3.2.1 AP_Mount_Backend::healthy

stub函数,默认设备健康。

    // return true if healthyvirtual bool healthy() const { return true; }

3.2.2 AP_Mount_Backend::has_roll_control

通过配置roll_angle_minroll_angle_max判断。

// return true if this mount accepts roll targets
bool AP_Mount_Backend::has_roll_control() const
{return (_params.roll_angle_min < _params.roll_angle_max);
}

3.2.3 AP_Mount_Backend::has_pitch_control

通过配置pitch_angle_minpitch_angle_max判断。

// return true if this mount accepts pitch targets
bool AP_Mount_Backend::has_pitch_control() const
{return (_params.pitch_angle_min < _params.pitch_angle_max);
}

3.2.4 AP_Mount_Backend::has_pan_control

必须定义yaw方向的能力。

    // returns true if this mount can control its pan (required for multicopters)virtual bool has_pan_control() const = 0;

3.3 模式处理

3.3.1 AP_Mount_Backend::valid_mode

有效模式

  • MAV_MOUNT_MODE_RETRACT
  • MAV_MOUNT_MODE_NEUTRAL
  • MAV_MOUNT_MODE_MAVLINK_TARGETING
  • MAV_MOUNT_MODE_RC_TARGETING
  • MAV_MOUNT_MODE_GPS_POINT
  • MAV_MOUNT_MODE_SYSID_TARGET
  • MAV_MOUNT_MODE_HOME_LOCATION
bool AP_Mount_Backend::valid_mode(MAV_MOUNT_MODE mode) const
{switch (mode) {case MAV_MOUNT_MODE_RETRACT...MAV_MOUNT_MODE_HOME_LOCATION:return true;case MAV_MOUNT_MODE_ENUM_END:return false;}return false;
}

3.3.2 AP_Mount_Backend::set_mode

设置模式

bool AP_Mount_Backend::set_mode(MAV_MOUNT_MODE mode)
{if (!valid_mode(mode)) {return false;}_mode = mode;return true;
}

3.3.3 AP_Mount_Backend::get_mode

获取模式

    // get mount's modeenum MAV_MOUNT_MODE get_mode() const { return _mode; }

3.4 目标处理

3.4.1 AP_Mount_Backend::set_roi_target

设定ROI区域

// set_roi_target - sets target location that mount should attempt to point towards
void AP_Mount_Backend::set_roi_target(const Location &target_loc)
{// set the target gps location_roi_target = target_loc;_roi_target_set = true;// set the mode to GPS tracking modeset_mode(MAV_MOUNT_MODE_GPS_POINT);// optionally set RC_TARGETING yaw lock stateif (option_set(Options::RCTARGETING_LOCK_FROM_PREVMODE)) {set_yaw_lock(true);}
}

3.4.2 AP_Mount_Backend::clear_roi_target

清除ROI区域

// clear_roi_target - clears target location that mount should attempt to point towards
void AP_Mount_Backend::clear_roi_target()
{// clear the target GPS location_roi_target_set = false;// reset the mode if in GPS tracking modeif (get_mode() == MAV_MOUNT_MODE_GPS_POINT) {MAV_MOUNT_MODE default_mode = (MAV_MOUNT_MODE)_params.default_mode.get();set_mode(default_mode);}
}

3.4.3 AP_Mount_Backend::get_angle_target_to_roi

计算地球坐标系下ROI角度

// get angle targets (in radians) to ROI location
// returns true on success, false on failure
bool AP_Mount_Backend::get_angle_target_to_roi(MountTarget& angle_rad) const
{if (!_roi_target_set) {return false;}return get_angle_target_to_location(_roi_target, angle_rad);
}

3.4.4 AP_Mount_Backend::calculate_poi

定时更新相机ROI角度

// calculate the Location that the gimbal is pointing at
void AP_Mount_Backend::calculate_poi()
{while (true) {// run this loop at 10hzhal.scheduler->delay(100);// calculate poi if requested within last 30 seconds{WITH_SEMAPHORE(poi_calculation.sem);if ((poi_calculation.poi_request_ms == 0) ||(AP_HAL::millis() - poi_calculation.poi_request_ms > AP_MOUNT_POI_REQUEST_TIMEOUT_MS)) {continue;}}// get the current location of vehicleconst AP_AHRS &ahrs = AP::ahrs();Location curr_loc;if (!ahrs.get_location(curr_loc)) {continue;}// change vehicle alt to AMSLcurr_loc.change_alt_frame(Location::AltFrame::ABSOLUTE);// project forward from vehicle looking for terrain// start testing at vehicle's locationLocation test_loc = curr_loc;Location prev_test_loc = curr_loc;// get terrain altitude (AMSL) at test_locauto terrain = AP_Terrain::get_singleton();float terrain_amsl_m;if ((terrain == nullptr) || !terrain->height_amsl(test_loc, terrain_amsl_m, true)) {continue;}// retrieve gimbal attitudeQuaternion quat;if (!get_attitude_quaternion(quat)) {// gimbal attitude unavailablecontinue;}// iteratively move test_loc forward until its alt-above-sea-level is below terrain-alt-above-sea-levelconst float dist_increment_m = MAX(terrain->get_grid_spacing(), 10);const float mount_pitch_deg = degrees(quat.get_euler_pitch());const float mount_yaw_ef_deg = wrap_180(degrees(quat.get_euler_yaw()) + degrees(ahrs.get_yaw()));float total_dist_m = 0;bool get_terrain_alt_success = true;float prev_terrain_amsl_m = terrain_amsl_m;while (total_dist_m < AP_MOUNT_POI_DIST_M_MAX && (test_loc.alt * 0.01) > terrain_amsl_m) {total_dist_m += dist_increment_m;// backup previous test location and terrain amslprev_test_loc = test_loc;prev_terrain_amsl_m = terrain_amsl_m;// move test location forwardtest_loc.offset_bearing_and_pitch(mount_yaw_ef_deg, mount_pitch_deg, dist_increment_m);// get terrain's alt-above-sea-level (at test_loc)// fail if terrain alt cannot be retrievedif (!terrain->height_amsl(test_loc, terrain_amsl_m, true) || std::isnan(terrain_amsl_m)) {get_terrain_alt_success = false;continue;}}// if a fail occurred above when getting terrain alt then restart calculations from the beginningif (!get_terrain_alt_success) {continue;}if (total_dist_m >= AP_MOUNT_POI_DIST_M_MAX) {// unable to find terrain within dist_maxcontinue;}// test location has dropped below terrain// interpolate along line between prev_test_loc and test_locfloat dist_interp_m = linear_interpolate(0, dist_increment_m, 0, prev_test_loc.alt * 0.01 - prev_terrain_amsl_m, test_loc.alt * 0.01 - terrain_amsl_m);{WITH_SEMAPHORE(poi_calculation.sem);poi_calculation.poi_loc = prev_test_loc;poi_calculation.poi_loc.offset_bearing_and_pitch(mount_yaw_ef_deg, mount_pitch_deg, dist_interp_m);poi_calculation.att_quat = {quat[0], quat[1], quat[2], quat[3]};poi_calculation.loc = curr_loc;poi_calculation.poi_update_ms = AP_HAL::millis();}}
}

3.5 命令处理

3.5.1 AP_Mount_Backend::handle_command_do_mount_control

AP_Mount::handle_command //MAV_CMD_DO_MOUNT_CONTROL└──> AP_Mount::handle_command_do_mount_control└──> AP_Mount_Backend::handle_command_do_mount_control
// handle do_mount_control command.  Returns MAV_RESULT_ACCEPTED on success
MAV_RESULT AP_Mount_Backend::handle_command_do_mount_control(const mavlink_command_int_t &packet)
{const MAV_MOUNT_MODE new_mode = (MAV_MOUNT_MODE)packet.z;// interpret message fields based on modeswitch (new_mode) {case MAV_MOUNT_MODE_RETRACT:case MAV_MOUNT_MODE_NEUTRAL:case MAV_MOUNT_MODE_RC_TARGETING:case MAV_MOUNT_MODE_HOME_LOCATION:// simply set modeset_mode(new_mode);return MAV_RESULT_ACCEPTED;case MAV_MOUNT_MODE_MAVLINK_TARGETING: {// set target angles (in degrees) from mavlink messageconst float pitch_deg = packet.param1;  // param1: pitch (earth-frame, degrees)const float roll_deg = packet.param2;   // param2: roll (earth-frame, degrees)const float yaw_deg = packet.param3;    // param3: yaw (body-frame, degrees)// warn if angles are invalid to catch angles sent in centi-degreesif ((fabsf(pitch_deg) > 90) || (fabsf(roll_deg) > 180) || (fabsf(yaw_deg) > 360)) {send_warning_to_GCS("invalid angle targets");return MAV_RESULT_FAILED;}set_angle_target(packet.param2, packet.param1, packet.param3, false);return MAV_RESULT_ACCEPTED;}case MAV_MOUNT_MODE_GPS_POINT: {// set lat, lon, alt position targets from mavlink message// warn if lat, lon appear to be in param1,2 instead of param x,y as this indicates// sender is relying on a bug in AP-4.2's (and earlier) handling of MAV_CMD_DO_MOUNT_CONTROLif (!is_zero(packet.param1) && !is_zero(packet.param2) && packet.x == 0 && packet.y == 0) {send_warning_to_GCS("GPS_POINT target invalid");return MAV_RESULT_FAILED;}// param4: altitude in meters// x: latitude in degrees * 1E7// y: longitude in degrees * 1E7const Location target_location {packet.x,                       // latitude in degrees * 1E7packet.y,                       // longitude in degrees * 1E7(int32_t)packet.param4 * 100,   // alt converted from meters to cmLocation::AltFrame::ABOVE_HOME};set_roi_target(target_location);return MAV_RESULT_ACCEPTED;}default:// invalid modereturn MAV_RESULT_FAILED;}
}

3.5.2 AP_Mount_Backend::handle_command_do_gimbal_manager_configure

AP_Mount::handle_command //MAV_CMD_DO_GIMBAL_MANAGER_CONFIGURE└──> AP_Mount::handle_command_do_gimbal_manager_configure└──> AP_Mount_Backend::handle_command_do_gimbal_manager_configure
// handle do_gimbal_manager_configure.  Returns MAV_RESULT_ACCEPTED on success
// requires original message in order to extract caller's sysid and compid
MAV_RESULT AP_Mount_Backend::handle_command_do_gimbal_manager_configure(const mavlink_command_int_t &packet, const mavlink_message_t &msg)
{// sanity check param1 and param2 valuesif ((packet.param1 < -3) || (packet.param1 > UINT8_MAX) || (packet.param2 < -3) || (packet.param2 > UINT8_MAX)) {return MAV_RESULT_FAILED;}// backup the current values so we can detect a changemavlink_control_id_t prev_control_id = mavlink_control_id;// convert negative packet1 and packet2 valuesint16_t new_sysid = packet.param1;switch (new_sysid) {case -1:// leave unchangedbreak;case -2:// set itself in controlmavlink_control_id.sysid = msg.sysid;mavlink_control_id.compid = msg.compid;break;case -3:// remove control if currently in controlif ((mavlink_control_id.sysid == msg.sysid) && (mavlink_control_id.compid == msg.compid)) {mavlink_control_id.sysid = 0;mavlink_control_id.compid = 0;}break;default:mavlink_control_id.sysid = packet.param1;mavlink_control_id.compid = packet.param2;break;}// send gimbal_manager_status if control has changedif (prev_control_id != mavlink_control_id) {GCS_SEND_MESSAGE(MSG_GIMBAL_MANAGER_STATUS);}return MAV_RESULT_ACCEPTED;
}

3.6 消息传递和状态

3.6.1 AP_Mount_Backend::send_gimbal_device_attitude_status

GCS_MAVLINK::try_send_message  //MSG_GIMBAL_DEVICE_ATTITUDE_STATUS└──> GCS_MAVLINK::send_gimbal_device_attitude_status└──> AP_Mount::send_gimbal_device_attitude_status└──> AP_Mount_Backend::send_gimbal_device_attitude_status
// send a GIMBAL_DEVICE_ATTITUDE_STATUS message to GCS
void AP_Mount_Backend::send_gimbal_device_attitude_status(mavlink_channel_t chan)
{if (suppress_heartbeat()) {// block heartbeat from transmitting to the GCSGCS_MAVLINK::disable_channel_routing(chan);}Quaternion att_quat;if (!get_attitude_quaternion(att_quat)) {return;}Vector3f ang_velocity { nanf(""), nanf(""), nanf("") };IGNORE_RETURN(get_angular_velocity(ang_velocity));// construct quaternion arrayconst float quat_array[4] = {att_quat.q1, att_quat.q2, att_quat.q3, att_quat.q4};mavlink_msg_gimbal_device_attitude_status_send(chan,0,   // target system0,   // target componentAP_HAL::millis(),    // autopilot system timeget_gimbal_device_flags(),quat_array,    // attitude expressed as quaternionang_velocity.x,    // roll axis angular velocity (NaN for unknown)ang_velocity.y,    // pitch axis angular velocity (NaN for unknown)ang_velocity.z,    // yaw axis angular velocity (NaN for unknown)0,                                           // failure flags (not supported)std::numeric_limits<double>::quiet_NaN(),    // delta_yaw (NaN for unknonw)std::numeric_limits<double>::quiet_NaN(),    // delta_yaw_velocity (NaN for unknonw)_instance + 1);  // gimbal_device_id
}

3.6.2 AP_Mount_Backend::send_gimbal_manager_information

GCS_MAVLINK::try_send_message  //MSG_GIMBAL_MANAGER_INFORMATION└──> GCS_MAVLINK::send_gimbal_manager_information└──> AP_Mount::send_gimbal_manager_information└──> AP_Mount_Backend::send_gimbal_manager_information
// send a GIMBAL_MANAGER_INFORMATION message to GCS
void AP_Mount_Backend::send_gimbal_manager_information(mavlink_channel_t chan)
{mavlink_msg_gimbal_manager_information_send(chan,AP_HAL::millis(),                       // autopilot system timeget_gimbal_manager_capability_flags(),  // bitmap of gimbal manager capability flags_instance + 1,                          // gimbal device idradians(_params.roll_angle_min),        // roll_min in radiansradians(_params.roll_angle_max),        // roll_max in radiansradians(_params.pitch_angle_min),       // pitch_min in radiansradians(_params.pitch_angle_max),       // pitch_max in radiansradians(_params.yaw_angle_min),         // yaw_min in radiansradians(_params.yaw_angle_max));        // yaw_max in radians
}

3.7 回调函数

3.7.1 AP_Mount_Backend::handle_gimbal_report

    // handle a GIMBAL_REPORT messagevirtual void handle_gimbal_report(mavlink_channel_t chan, const mavlink_message_t &msg) {}

3.7.2 AP_Mount_Backend::handle_param_value

    // handle a PARAM_VALUE messagevirtual void handle_param_value(const mavlink_message_t &msg) {}

3.8 相机控制

虚函数,根据云台+相机的复合设备都需要在具体的设备驱动后台实现。

3.8.1 AP_Mount_Backend::take_picture

    // take a picture.  returns true on successvirtual bool take_picture() { return false; }

3.8.2 AP_Mount_Backend::record_video

    // start or stop video recording.  returns true on success// set start_recording = true to start record, false to stop recordingvirtual bool record_video(bool start_recording) { return false; }

3.8.3 AP_Mount_Backend::set_zoom

    // set zoom specified as a rate or percentagevirtual bool set_zoom(ZoomType zoom_type, float zoom_value) { return false; }

3.9 测距仪

虚函数,根带测距仪的复合设备都需要在具体的设备驱动后台实现。

3.9.1 AP_Mount_Backend::get_rangefinder_distance

    // get rangefinder distance.  Returns true on successvirtual bool get_rangefinder_distance(float& distance_m) const { return false; }

3.9.2 AP_Mount_Backend::set_rangefinder_enable

    // enable/disable rangefinder.  Returns true on successvirtual bool set_rangefinder_enable(bool enable) { return false; }

3.10 辅助函数

3.10.1 AP_Mount_Backend::get_angle_target_to_location

// get angle targets (in radians) to a Location
// returns true on success, false on failure
bool AP_Mount_Backend::get_angle_target_to_location(const Location &loc, MountTarget& angle_rad) const
{// exit immediately if vehicle's location is unavailableLocation current_loc;if (!AP::ahrs().get_location(current_loc)) {return false;}// exit immediate if location is invalidif (!loc.initialised()) {return false;}const float GPS_vector_x = Location::diff_longitude(loc.lng, current_loc.lng)*cosf(ToRad((current_loc.lat + loc.lat) * 0.00000005f)) * 0.01113195f;const float GPS_vector_y = (loc.lat - current_loc.lat) * 0.01113195f;int32_t target_alt_cm = 0;if (!loc.get_alt_cm(Location::AltFrame::ABOVE_HOME, target_alt_cm)) {return false;}int32_t current_alt_cm = 0;if (!current_loc.get_alt_cm(Location::AltFrame::ABOVE_HOME, current_alt_cm)) {return false;}float GPS_vector_z = target_alt_cm - current_alt_cm;float target_distance = 100.0f*norm(GPS_vector_x, GPS_vector_y);      // Careful , centimeters here locally. Baro/alt is in cm, lat/lon is in meters.// calculate roll, pitch, yaw anglesangle_rad.roll = 0;angle_rad.pitch = atan2f(GPS_vector_z, target_distance);angle_rad.yaw = atan2f(GPS_vector_x, GPS_vector_y);angle_rad.yaw_is_ef = true;return true;
}

3.10.2 AP_Mount_Backend::set_angle_target

// set angle target in degrees
// roll and pitch are in earth-frame
// yaw_is_earth_frame (aka yaw_lock) should be true if yaw angle is earth-frame, false if body-frame
void AP_Mount_Backend::set_angle_target(float roll_deg, float pitch_deg, float yaw_deg, bool yaw_is_earth_frame)
{// enforce angle limitsroll_deg = constrain_float(roll_deg, _params.roll_angle_min, _params.roll_angle_max);pitch_deg = constrain_float(pitch_deg, _params.pitch_angle_min, _params.pitch_angle_max);if (!yaw_is_earth_frame) {// only limit yaw if in body-frame.  earth-frame yaw limiting is backend specific// custom wrap code (instead of wrap_180) to better handle yaw of <= -180if (yaw_deg > 180) {yaw_deg -= 360;}yaw_deg = constrain_float(yaw_deg, _params.yaw_angle_min, _params.yaw_angle_max);}// set angle targetsmnt_target.target_type = MountTargetType::ANGLE;mnt_target.angle_rad.roll = radians(roll_deg);mnt_target.angle_rad.pitch = radians(pitch_deg);mnt_target.angle_rad.yaw = radians(yaw_deg);mnt_target.angle_rad.yaw_is_ef = yaw_is_earth_frame;// set the mode to mavlink targetingset_mode(MAV_MOUNT_MODE_MAVLINK_TARGETING);// optionally set RC_TARGETING yaw lock stateif (option_set(Options::RCTARGETING_LOCK_FROM_PREVMODE)) {set_yaw_lock(yaw_is_earth_frame);}
}

4. 总结

AP_Mount_Backend是在云台+相机+测距+相机跟随的复合设备抽象类。

  • AP_Mount_Backend
  • AP_Mount_Servo
  • AP_Mount_SoloGimbal
  • AP_Mount_Alexmos
  • AP_Mount_SToRM32
  • AP_Mount_SToRM32_serial
  • AP_Mount_Gremsy
  • AP_Mount_Siyi
  • AP_Mount_Scripting
  • AP_Mount_Xacti
  • AP_Mount_Viewpro
  • AP_Mount_Topotek //最近更新的设备类

5. 参考资料

【1】ArduPilot开源飞控系统之简单介绍
【2】ArduPilot之开源代码Task介绍
【3】ArduPilot飞控启动&运行过程简介
【4】ArduPilot之开源代码Library&Sketches设计
【5】ArduPilot之开源代码Sensor Drivers设计
【6】ArduPilot开源飞控之AP_Mount

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/870694.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

samout 结构再优化 收敛速度再加快

代码 import torch import numpy as npclass MaxState(torch.nn.Module):def __init__(self, hidden_dim, heads, win):super(MaxState, self).__init__()assert hidden_dim % heads 0, "Hidden size must be divisible by the number of heads."self.head_size h…

基于python实现并编译提升cpu与内存使用率的脚本

在服务器运维过程中&#xff0c;有很多公司会对服务器的资源使用率进行监测&#xff0c;发现使用率不高了&#xff0c;会对服务器降配。如果你是乙方&#xff0c;你可以尝试一下这种方法&#xff0c;脚本提升cpu与内存的使用率。如果你需要对服务器性能或者服务稳定性进行测试&…

Redis 布隆过滤器性能对比分析

redis 实现布隆过滤器实现方法&#xff1a; 1、redis 的 setbit 和 getbit 特点&#xff1a;对于某个bit 设置0或1&#xff0c;对于大量的值需要存储&#xff0c;非常节省空间&#xff0c;查询速度极快&#xff0c;但是不能查询整个key所有的bit&#xff0c;在一次请求有大量…

240711_昇思学习打卡-Day23-LSTM+CRF序列标注(2)

240711_昇思学习打卡-Day23-LSTMCRF序列标注&#xff08;2&#xff09; 今天记录LSTMCRF序列标注的第二部分。仅作简单记录 Score计算 首先计算正确标签序列所对应的得分&#xff0c;这里需要注意&#xff0c;除了转移概率矩阵&#x1d40f;外&#xff0c;还需要维护两个大小…

担心插座预留的不够用,家里装修留多少开关插座

全屋插座布局,防漏防后悔      家里装修留多少开关插座?留多了费钱      留少了还不够用,给大家整理了全屋开关插座的布局      1,入户门留5个,门外给监控器1个      门旁边给卧室,走廊,客厅,中央空调各留1个      2,客厅留10个,电视留4-5个, 沙发两边各1…

html5——CSS基础选择器

目录 标签选择器 类选择器 id选择器 三种选择器优先级 标签指定式选择器 包含选择器 群组选择器 通配符选择器 Emmet语法&#xff08;扩展补充&#xff09; 标签选择器 HTML标签作为标签选择器的名称&#xff1a; <h1>…<h6>、<p>、<img/> 语…

如何做好漏洞扫描工作提高网络安全

在数字化浪潮席卷全球的今天&#xff0c;企业数字化转型已成为提升竞争力、实现可持续发展的关键路径。然而&#xff0c;这一转型过程并非坦途&#xff0c;其中网络安全问题如同暗礁般潜伏&#xff0c;稍有不慎便可能引发数据泄露、服务中断乃至品牌信誉受损等严重后果。因此&a…

edge 学习工具包 math solver

简介 推荐微软推出的学习工具中的两项工具&#xff1a;数学求解器和 pdf 阅读器。 打开 edge 学习工具包的方法 &#xff1a;右上角三点-更多工具-学习工具包。 math solver 除了基础的计算求解外&#xff0c;还用图标展示公式&#xff0c;清晰直观。 地址&#xff1a;求解…

CentOS7使用yum命令报错

目录结构 前言使用yum命令&#xff0c;报错信息问题排查解决方案参考文章 前言 安装CentOS 7 虚拟机&#xff0c;使用yum命令报错&#xff0c;调查整理如下&#xff1a; 使用yum命令&#xff0c;报错信息 [rootlocalhost ~]# sudo yum install net-tools 已加载插件&#xff…

OPenCV实现直方图均衡化----20240711

# 直方图均衡化import cv2 import numpy as np import matplotlib.pyplot as plt# 读取彩色图像 img = cv2.imread("./pictures/Lena.jpg")# 检查图像是否加载成功 if img is None:print("Could not open or find the i

每天五分钟深度学习:向量化技术在神经网络中的应用

本文重点 向量化技术,简而言之,就是利用矩阵运算(而非传统的for循环)来执行大规模的计算任务。这种技术依赖于单指令多数据(SIMD)架构,允许一个指令同时对多个数据元素执行相同的操作。例如,在向量化加法中,不再需要逐个元素进行加法操作,而是可以一次性对整个向量执…

【电子通识】无源元件与有源元件的定义和区别是什么?

当提到构成电路的电子器件时,许多人可能会想到晶体管、电容器、电感器和电阻器等器件。一般情况下,我们使用的电子器件分为两大类,即“有源元件”和“无源元件”。 有源元件是主动影响(如放大、整流、转换等)所供给电能的元件。 无源元件是对所供给的电能执行被动…

测试驱动开发的艺术:Xcode中实现TDD的全面指南

测试驱动开发的艺术&#xff1a;Xcode中实现TDD的全面指南 在软件开发过程中&#xff0c;测试驱动开发&#xff08;Test-Driven Development&#xff0c;TDD&#xff09;是一种以测试为先导的开发模式&#xff0c;它强调先编写测试用例&#xff0c;再编写功能代码&#xff0c;…

流程图编辑框架LogicFlow-vue-ts和js

LogicFlow官网https://site.logic-flow.cn/LogicFlow 是一款流程图编辑框架&#xff0c;提供了一系列流程图交互、编辑所必需的功能和灵活的节点自定义、插件等拓展机制。LogicFlow支持前端研发自定义开发各种逻辑编排场景&#xff0c;如流程图、ER图、BPMN流程等。在工作审批配…

【zabbix7】开启HTTP authentication实现单点登录

开启HTTP authentication实现单点登录 一、新建http验证用户 htpasswd -c /etc/nginx/.htpasswd another_username # 在提示中输入密码二、新建Nginx配置文件 把zabbix.conf拷贝一份&#xff0c;然后修改listen监听的端口。 cp zabbx.conf zabbix_http.conf 每个location中新…

【Dison夏令营 Day 16】如何使用 Python 中的 PyGame 制作俄罗斯方块游戏

俄罗斯方块(Tetris)是一款经典的益智游戏&#xff0c;游戏的目的是将落下的几何图形片&#xff08;称为 “俄罗斯方块”&#xff09;排列起来&#xff0c;填满水平线&#xff0c;不留空隙。当一条线被完全填满时&#xff0c;它就被清除了&#xff0c;玩家就能获得分数。随着四角…

操作系统——内存管理(面试准备)

虚拟内存 单片机没有操作系统&#xff0c;每次写完代码&#xff0c;都需要借助工具把程序烧录进去&#xff0c;这样程序才能跑起来。 另外&#xff0c;单片机的CPU是直接操作内存的物理地址。 在这种情况下&#xff0c;想在内存中同时运行两个程序是不可能的&#xff0c;如果第…

(CVPR-2024)SwiftBrush:具有变分分数蒸馏的单步文本到图像扩散模型

SwiftBrush&#xff1a;具有变分分数蒸馏的单步文本到图像扩散模型 Paper Title&#xff1a;SwiftBrush: One-Step Text-to-Image Diffusion Model with Variational Score Distillation Paper 是 VinAI Research 发表在 CVPR 24 的工作 Paper地址 Code:地址 Abstract 尽管文本…

Flutter-实现物理小球碰撞效果

效果 引言 在Flutter应用中实现物理动画效果&#xff0c;可以大大提升用户体验。本文将详细介绍如何在Flutter中创建一个模拟物理碰撞的动画小球界面&#xff0c;主要代码实现基于集成sensors_plus插件来获取设备的加速度传感器数据。 准备工作 在开始之前&#xff0c;请确保…

一文详解DDL同步及其应用场景

目录 一、什么是DDL&#xff1f; 二、什么是DDL同步&#xff1f; 三、DDL同步的痛点 1、缺少自动DDL同步机制 2、缺少DDL变更监测预警 四、解决方案 五、应用场景及案例 案例一 案例二 案例三 在现代数据管理中&#xff0c;数据库的结构变更频繁且不可避免&#xff0c;特别是在…