mirror of
https://github.com/ArduPilot/ardupilot
synced 2025-01-05 15:38:29 -04:00
f150c645c8
this enables MNT_* parameter control of the camera mount code. It also fixes the conversion of calculated angles between degrees and integers, and fixes stabilised mount control when yaw control is not available.
353 lines
12 KiB
C++
353 lines
12 KiB
C++
// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: t -*-
|
|
|
|
#include <FastSerial.h>
|
|
#include <AP_Common.h>
|
|
#include <AP_Param.h>
|
|
#include <AP_Mount.h>
|
|
|
|
const AP_Param::GroupInfo AP_Mount::var_info[] PROGMEM = {
|
|
// index 0 was used for the old orientation matrix
|
|
AP_GROUPINFO("MODE", 0, AP_Mount, _mount_mode),
|
|
AP_GROUPINFO("RETRACT", 1, AP_Mount, _retract_angles),
|
|
AP_GROUPINFO("NEUTRAL", 2, AP_Mount, _neutral_angles),
|
|
AP_GROUPINFO("CONTROL", 3, AP_Mount, _control_angles),
|
|
AP_GROUPINFO("STAB_ROLL", 4, AP_Mount, _stab_roll),
|
|
AP_GROUPINFO("STAB_PITCH", 5, AP_Mount, _stab_pitch),
|
|
AP_GROUPINFO("STAB_YAW", 6, AP_Mount, _stab_yaw),
|
|
AP_GROUPEND
|
|
};
|
|
|
|
extern RC_Channel_aux* g_rc_function[RC_Channel_aux::k_nr_aux_servo_functions]; // the aux. servo ch. assigned to each function
|
|
|
|
AP_Mount::AP_Mount(const struct Location *current_loc, GPS *&gps, AP_AHRS *ahrs):
|
|
_gps(gps)
|
|
{
|
|
_ahrs = ahrs;
|
|
_current_loc = current_loc;
|
|
|
|
// startup with the mount retracted
|
|
set_mode(MAV_MOUNT_MODE_RETRACT);
|
|
|
|
// default to zero angles
|
|
_retract_angles = Vector3f(0,0,0);
|
|
_neutral_angles = Vector3f(0,0,0);
|
|
_control_angles = Vector3f(0,0,0);
|
|
}
|
|
|
|
//sets the servo angles for retraction, note angles are in degrees
|
|
void AP_Mount::set_retract_angles(float roll, float pitch, float yaw)
|
|
{
|
|
_retract_angles = Vector3f(roll, pitch, yaw);
|
|
}
|
|
|
|
//sets the servo angles for neutral, note angles are in degrees
|
|
void AP_Mount::set_neutral_angles(float roll, float pitch, float yaw)
|
|
{
|
|
_neutral_angles = Vector3f(roll, pitch, yaw);
|
|
}
|
|
|
|
//sets the servo angles for MAVLink, note angles are in degrees
|
|
void AP_Mount::set_control_angles(float roll, float pitch, float yaw)
|
|
{
|
|
_control_angles = Vector3f(roll, pitch, yaw);
|
|
}
|
|
|
|
// used to tell the mount to track GPS location
|
|
void AP_Mount::set_GPS_target_location(Location targetGPSLocation)
|
|
{
|
|
_target_GPS_location=targetGPSLocation;
|
|
}
|
|
|
|
// This one should be called periodically
|
|
void AP_Mount::update_mount_position()
|
|
{
|
|
switch((enum MAV_MOUNT_MODE)_mount_mode.get())
|
|
{
|
|
// move mount to a "retracted position" or to a position where a fourth servo can retract the entire mount into the fuselage
|
|
case MAV_MOUNT_MODE_RETRACT:
|
|
{
|
|
Vector3f vec = _retract_angles.get();
|
|
_roll_angle = vec.x;
|
|
_pitch_angle = vec.y;
|
|
_yaw_angle = vec.z;
|
|
break;
|
|
}
|
|
|
|
// move mount to a neutral position, typically pointing forward
|
|
case MAV_MOUNT_MODE_NEUTRAL:
|
|
{
|
|
Vector3f vec = _neutral_angles.get();
|
|
_roll_angle = vec.x;
|
|
_pitch_angle = vec.y;
|
|
_yaw_angle = vec.z;
|
|
break;
|
|
}
|
|
|
|
// point to the angles given by a mavlink message
|
|
case MAV_MOUNT_MODE_MAVLINK_TARGETING:
|
|
{
|
|
Vector3f vec = _control_angles.get();
|
|
_roll_control_angle = vec.x;
|
|
_pitch_control_angle = vec.y;
|
|
_yaw_control_angle = vec.z;
|
|
calculate();
|
|
break;
|
|
}
|
|
|
|
// RC radio manual angle control, but with stabilization from the AHRS
|
|
case MAV_MOUNT_MODE_RC_TARGETING:
|
|
{
|
|
// rc_input() takes degrees * 100 units
|
|
G_RC_AUX(k_mount_roll)->rc_input(&_roll_control_angle, _roll_angle*100);
|
|
G_RC_AUX(k_mount_pitch)->rc_input(&_pitch_control_angle, _pitch_angle*100);
|
|
G_RC_AUX(k_mount_yaw)->rc_input(&_yaw_control_angle, _yaw_angle*100);
|
|
if (_ahrs){
|
|
calculate();
|
|
} else {
|
|
if (g_rc_function[RC_Channel_aux::k_mount_roll])
|
|
_roll_angle = rc_map(g_rc_function[RC_Channel_aux::k_mount_roll]);
|
|
if (g_rc_function[RC_Channel_aux::k_mount_pitch])
|
|
_pitch_angle = rc_map(g_rc_function[RC_Channel_aux::k_mount_pitch]);
|
|
if (g_rc_function[RC_Channel_aux::k_mount_yaw])
|
|
_yaw_angle = rc_map(g_rc_function[RC_Channel_aux::k_mount_yaw]);
|
|
}
|
|
break;
|
|
}
|
|
|
|
// point mount to a GPS point given by the mission planner
|
|
case MAV_MOUNT_MODE_GPS_POINT:
|
|
{
|
|
if(_gps->fix){
|
|
calc_GPS_target_angle(&_target_GPS_location);
|
|
calculate();
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
//do nothing
|
|
break;
|
|
}
|
|
|
|
// write the results to the servos
|
|
/*
|
|
G_RC_AUX(k_mount_roll)->angle_out(_roll_angle);
|
|
G_RC_AUX(k_mount_pitch)->angle_out(_pitch_angle);
|
|
G_RC_AUX(k_mount_yaw)->angle_out(_yaw_angle);
|
|
*/
|
|
// closest_limit() takes degrees * 10 units
|
|
G_RC_AUX(k_mount_roll)->closest_limit(_roll_angle*10);
|
|
G_RC_AUX(k_mount_pitch)->closest_limit(_pitch_angle*10);
|
|
G_RC_AUX(k_mount_yaw)->closest_limit(_yaw_angle*10);
|
|
}
|
|
|
|
void AP_Mount::set_mode(enum MAV_MOUNT_MODE mode)
|
|
{
|
|
_mount_mode = (int8_t)mode;
|
|
}
|
|
|
|
// Change the configuration of the mount
|
|
// triggered by a MavLink packet.
|
|
void AP_Mount::configure_msg(mavlink_message_t* msg)
|
|
{
|
|
__mavlink_mount_configure_t packet;
|
|
mavlink_msg_mount_configure_decode(msg, &packet);
|
|
if (mavlink_check_target(packet.target_system, packet.target_component)) {
|
|
// not for us
|
|
return;
|
|
}
|
|
set_mode((enum MAV_MOUNT_MODE)packet.mount_mode);
|
|
_stab_pitch = packet.stab_pitch;
|
|
_stab_roll = packet.stab_roll;
|
|
_stab_yaw = packet.stab_yaw;
|
|
}
|
|
|
|
// Control the mount (depends on the previously set mount configuration)
|
|
// triggered by a MavLink packet.
|
|
void AP_Mount::control_msg(mavlink_message_t *msg)
|
|
{
|
|
__mavlink_mount_control_t packet;
|
|
mavlink_msg_mount_control_decode(msg, &packet);
|
|
if (mavlink_check_target(packet.target_system, packet.target_component)) {
|
|
// not for us
|
|
return;
|
|
}
|
|
|
|
switch ((enum MAV_MOUNT_MODE)_mount_mode.get())
|
|
{
|
|
case MAV_MOUNT_MODE_RETRACT: // Load and keep safe position (Roll,Pitch,Yaw) from EEPROM and stop stabilization
|
|
set_retract_angles(packet.input_b*0.01, packet.input_a*0.01, packet.input_c*0.01);
|
|
if (packet.save_position)
|
|
{
|
|
_retract_angles.save();
|
|
}
|
|
break;
|
|
|
|
case MAV_MOUNT_MODE_NEUTRAL: // Load and keep neutral position (Roll,Pitch,Yaw) from EEPROM
|
|
set_neutral_angles(packet.input_b*0.01, packet.input_a*0.01, packet.input_c*0.01);
|
|
if (packet.save_position)
|
|
{
|
|
_neutral_angles.save();
|
|
}
|
|
break;
|
|
|
|
case MAV_MOUNT_MODE_MAVLINK_TARGETING: // Load neutral position and start MAVLink Roll,Pitch,Yaw control with stabilization
|
|
set_control_angles(packet.input_b*0.01, packet.input_a*0.01, packet.input_c*0.01);
|
|
break;
|
|
|
|
case MAV_MOUNT_MODE_RC_TARGETING: // Load neutral position and start RC Roll,Pitch,Yaw control with stabilization
|
|
break;
|
|
|
|
case MAV_MOUNT_MODE_GPS_POINT: // Load neutral position and start to point to Lat,Lon,Alt
|
|
Location targetGPSLocation;
|
|
targetGPSLocation.lat = packet.input_a;
|
|
targetGPSLocation.lng = packet.input_b;
|
|
targetGPSLocation.alt = packet.input_c;
|
|
set_GPS_target_location(targetGPSLocation);
|
|
break;
|
|
|
|
case MAV_MOUNT_MODE_ENUM_END:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Return mount status information (depends on the previously set mount configuration)
|
|
// triggered by a MavLink packet.
|
|
void AP_Mount::status_msg(mavlink_message_t *msg)
|
|
{
|
|
__mavlink_mount_status_t packet;
|
|
mavlink_msg_mount_status_decode(msg, &packet);
|
|
if (mavlink_check_target(packet.target_system, packet.target_component)) {
|
|
// not for us
|
|
return;
|
|
}
|
|
|
|
switch ((enum MAV_MOUNT_MODE)_mount_mode.get())
|
|
{
|
|
case MAV_MOUNT_MODE_RETRACT: // safe position (Roll,Pitch,Yaw) from EEPROM and stop stabilization
|
|
case MAV_MOUNT_MODE_NEUTRAL: // neutral position (Roll,Pitch,Yaw) from EEPROM
|
|
case MAV_MOUNT_MODE_MAVLINK_TARGETING: // neutral position and start MAVLink Roll,Pitch,Yaw control with stabilization
|
|
case MAV_MOUNT_MODE_RC_TARGETING: // neutral position and start RC Roll,Pitch,Yaw control with stabilization
|
|
packet.pointing_b = _roll_angle*100; ///< degrees*100
|
|
packet.pointing_a = _pitch_angle*100; ///< degrees*100
|
|
packet.pointing_c = _yaw_angle*100; ///< degrees*100
|
|
break;
|
|
case MAV_MOUNT_MODE_GPS_POINT: // neutral position and start to point to Lat,Lon,Alt
|
|
packet.pointing_a = _target_GPS_location.lat; ///< latitude
|
|
packet.pointing_b = _target_GPS_location.lng; ///< longitude
|
|
packet.pointing_c = _target_GPS_location.alt; ///< altitude
|
|
break;
|
|
case MAV_MOUNT_MODE_ENUM_END:
|
|
break;
|
|
}
|
|
|
|
// status reply
|
|
// TODO: is COMM_3 correct ?
|
|
mavlink_msg_mount_status_send(MAVLINK_COMM_3, packet.target_system, packet.target_component,
|
|
packet.pointing_a, packet.pointing_b, packet.pointing_c);
|
|
}
|
|
|
|
// Set mount point/region of interest, triggered by mission script commands
|
|
void AP_Mount::set_roi_cmd()
|
|
{
|
|
// TODO get the information out of the mission command and use it
|
|
}
|
|
|
|
// Set mount configuration, triggered by mission script commands
|
|
void AP_Mount::configure_cmd()
|
|
{
|
|
// TODO get the information out of the mission command and use it
|
|
}
|
|
|
|
// Control the mount (depends on the previously set mount configuration), triggered by mission script commands
|
|
void AP_Mount::control_cmd()
|
|
{
|
|
// TODO get the information out of the mission command and use it
|
|
}
|
|
|
|
void
|
|
AP_Mount::calc_GPS_target_angle(struct Location *target)
|
|
{
|
|
float GPS_vector_x = (target->lng-_current_loc->lng)*cos(ToRad((_current_loc->lat+target->lat)/(t7*2.0)))*.01113195;
|
|
float GPS_vector_y = (target->lat-_current_loc->lat)*.01113195;
|
|
float GPS_vector_z = (target->alt-_current_loc->alt); // baro altitude(IN CM) should be adjusted to known home elevation before take off (Set altimeter).
|
|
float target_distance = 100.0*sqrt(GPS_vector_x*GPS_vector_x + GPS_vector_y*GPS_vector_y); // Careful , centimeters here locally. Baro/alt is in cm, lat/lon is in meters.
|
|
_roll_control_angle = 0;
|
|
_pitch_control_angle = atan2(GPS_vector_z, target_distance);
|
|
_yaw_control_angle = atan2(GPS_vector_x, GPS_vector_y);
|
|
// Converts +/- 180 into 0-360.
|
|
if(_yaw_control_angle<0){
|
|
_yaw_control_angle += 2*M_PI;
|
|
}
|
|
}
|
|
|
|
// Inputs desired _roll_control_angle, _pitch_control_angle and _yaw_control_angle stabilizes them relative to the airframe
|
|
// and calculates output _roll_angle, _pitch_angle and _yaw_angle
|
|
void
|
|
AP_Mount::calculate()
|
|
{
|
|
if (_ahrs) {
|
|
// only do the full 3D frame transform if we are doing yaw control
|
|
if (_stab_yaw) {
|
|
Matrix3f m; ///< holds 3 x 3 matrix, var is used as temp in calcs
|
|
Matrix3f cam; ///< Rotation matrix earth to camera. Desired camera from input.
|
|
Matrix3f gimbal_target; ///< Rotation matrix from plane to camera. Then Euler angles to the servos.
|
|
m = _ahrs->get_dcm_matrix();
|
|
m.transpose();
|
|
cam.from_euler(_roll_control_angle, _pitch_control_angle, _yaw_control_angle);
|
|
gimbal_target = m * cam;
|
|
gimbal_target.to_euler(&_roll_angle, &_pitch_angle, &_yaw_angle);
|
|
} else {
|
|
// otherwise base mount roll and pitch on the ahrs
|
|
// roll/pitch attitude, plus any requested angle
|
|
_roll_angle = _roll_control_angle;
|
|
_pitch_angle = _pitch_control_angle;
|
|
_yaw_angle = _yaw_control_angle;
|
|
if (_stab_roll) {
|
|
_roll_angle -= degrees(_ahrs->roll);
|
|
}
|
|
if (_stab_pitch) {
|
|
_pitch_angle -= degrees(_ahrs->pitch);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// This function is needed to let the HIL code compile
|
|
long
|
|
AP_Mount::rc_map(RC_Channel_aux* rc_ch)
|
|
{
|
|
return (rc_ch->radio_in - rc_ch->radio_min) * (rc_ch->angle_max - rc_ch->angle_min) / (rc_ch->radio_max - rc_ch->radio_min) + rc_ch->angle_min;
|
|
}
|
|
|
|
// For testing and development. Called in the medium loop.
|
|
void
|
|
AP_Mount::debug_output()
|
|
{ Serial3.print("current - ");
|
|
Serial3.print("lat ");
|
|
Serial3.print(_current_loc->lat);
|
|
Serial3.print(",lon ");
|
|
Serial3.print(_current_loc->lng);
|
|
Serial3.print(",alt ");
|
|
Serial3.println(_current_loc->alt);
|
|
|
|
Serial3.print("gps - ");
|
|
Serial3.print("lat ");
|
|
Serial3.print(_gps->latitude);
|
|
Serial3.print(",lon ");
|
|
Serial3.print(_gps->longitude);
|
|
Serial3.print(",alt ");
|
|
Serial3.print(_gps->altitude);
|
|
Serial3.println();
|
|
|
|
Serial3.print("target - ");
|
|
Serial3.print("lat ");
|
|
Serial3.print(_target_GPS_location.lat);
|
|
Serial3.print(",lon ");
|
|
Serial3.print(_target_GPS_location.lng);
|
|
Serial3.print(",alt ");
|
|
Serial3.print(_target_GPS_location.alt);
|
|
Serial3.print(" hdg to targ ");
|
|
Serial3.print(degrees(_yaw_control_angle));
|
|
Serial3.println();
|
|
}
|