mirror of https://github.com/ArduPilot/ardupilot
Tools/AntennaTracker: completed intial tracker code
Now works with 2 servo alt-azimuth mounted antenna tracking mount. Tested on Flymaple, with Eagle Tree antenna tracker.
This commit is contained in:
parent
8251cf32fb
commit
0885d55905
|
@ -28,9 +28,9 @@ static NOINLINE void send_heartbeat(mavlink_channel_t chan)
|
||||||
chan,
|
chan,
|
||||||
MAV_TYPE_ANTENNA_TRACKER,
|
MAV_TYPE_ANTENNA_TRACKER,
|
||||||
MAV_AUTOPILOT_ARDUPILOTMEGA,
|
MAV_AUTOPILOT_ARDUPILOTMEGA,
|
||||||
|
MAV_MODE_FLAG_AUTO_ENABLED,
|
||||||
0,
|
0,
|
||||||
0,
|
MAV_STATE_ACTIVE);
|
||||||
0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static NOINLINE void send_attitude(mavlink_channel_t chan)
|
static NOINLINE void send_attitude(mavlink_channel_t chan)
|
||||||
|
@ -56,16 +56,12 @@ static void NOINLINE send_location(mavlink_channel_t chan)
|
||||||
} else {
|
} else {
|
||||||
fix_time = hal.scheduler->millis();
|
fix_time = hal.scheduler->millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
Location loc;
|
|
||||||
ahrs.get_position(loc);
|
|
||||||
|
|
||||||
mavlink_msg_global_position_int_send(
|
mavlink_msg_global_position_int_send(
|
||||||
chan,
|
chan,
|
||||||
fix_time,
|
fix_time,
|
||||||
loc.lat, // in 1E7 degrees
|
current_loc.lat, // in 1E7 degrees
|
||||||
loc.lng, // in 1E7 degrees
|
current_loc.lng, // in 1E7 degrees
|
||||||
g_gps->altitude_cm * 10, // millimeters above sea level
|
current_loc.alt * 10, // millimeters above sea level
|
||||||
0,
|
0,
|
||||||
g_gps->velocity_north() * 100, // X speed cm/s (+ve North)
|
g_gps->velocity_north() * 100, // X speed cm/s (+ve North)
|
||||||
g_gps->velocity_east() * 100, // Y speed cm/s (+ve East)
|
g_gps->velocity_east() * 100, // Y speed cm/s (+ve East)
|
||||||
|
@ -75,6 +71,11 @@ static void NOINLINE send_location(mavlink_channel_t chan)
|
||||||
|
|
||||||
static void NOINLINE send_gps_raw(mavlink_channel_t chan)
|
static void NOINLINE send_gps_raw(mavlink_channel_t chan)
|
||||||
{
|
{
|
||||||
|
static uint32_t last_send_time;
|
||||||
|
if (last_send_time != 0 && last_send_time == g_gps->last_fix_time && g_gps->status() >= GPS::GPS_OK_FIX_3D) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
last_send_time = g_gps->last_fix_time;
|
||||||
mavlink_msg_gps_raw_int_send(
|
mavlink_msg_gps_raw_int_send(
|
||||||
chan,
|
chan,
|
||||||
g_gps->last_fix_time*(uint64_t)1000,
|
g_gps->last_fix_time*(uint64_t)1000,
|
||||||
|
@ -209,6 +210,14 @@ static void NOINLINE send_hwstatus(mavlink_channel_t chan)
|
||||||
hal.i2c->lockup_count());
|
hal.i2c->lockup_count());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void NOINLINE send_waypoint_request(mavlink_channel_t chan)
|
||||||
|
{
|
||||||
|
if (chan == MAVLINK_COMM_0)
|
||||||
|
gcs0.queued_waypoint_send();
|
||||||
|
else
|
||||||
|
gcs3.queued_waypoint_send();
|
||||||
|
}
|
||||||
|
|
||||||
static void NOINLINE send_statustext(mavlink_channel_t chan)
|
static void NOINLINE send_statustext(mavlink_channel_t chan)
|
||||||
{
|
{
|
||||||
mavlink_statustext_t *s = (chan == MAVLINK_COMM_0?&gcs0.pending_status:&gcs3.pending_status);
|
mavlink_statustext_t *s = (chan == MAVLINK_COMM_0?&gcs0.pending_status:&gcs3.pending_status);
|
||||||
|
@ -292,6 +301,11 @@ static bool mavlink_try_send_message(mavlink_channel_t chan, enum ap_message id,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MSG_NEXT_WAYPOINT:
|
||||||
|
CHECK_PAYLOAD_SIZE(MISSION_REQUEST);
|
||||||
|
send_waypoint_request(chan);
|
||||||
|
break;
|
||||||
|
|
||||||
case MSG_STATUSTEXT:
|
case MSG_STATUSTEXT:
|
||||||
CHECK_PAYLOAD_SIZE(STATUSTEXT);
|
CHECK_PAYLOAD_SIZE(STATUSTEXT);
|
||||||
send_statustext(chan);
|
send_statustext(chan);
|
||||||
|
@ -315,7 +329,6 @@ static bool mavlink_try_send_message(mavlink_channel_t chan, enum ap_message id,
|
||||||
case MSG_VFR_HUD:
|
case MSG_VFR_HUD:
|
||||||
case MSG_RADIO_IN:
|
case MSG_RADIO_IN:
|
||||||
case MSG_SYSTEM_TIME:
|
case MSG_SYSTEM_TIME:
|
||||||
case MSG_NEXT_WAYPOINT:
|
|
||||||
case MSG_LIMITS_STATUS:
|
case MSG_LIMITS_STATUS:
|
||||||
case MSG_FENCE_STATUS:
|
case MSG_FENCE_STATUS:
|
||||||
case MSG_SIMSTATE:
|
case MSG_SIMSTATE:
|
||||||
|
@ -514,6 +527,7 @@ GCS_MAVLINK::update(void)
|
||||||
|
|
||||||
// Update packet drops counter
|
// Update packet drops counter
|
||||||
packet_drops += status.packet_rx_drop_count;
|
packet_drops += status.packet_rx_drop_count;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// see if we should send a stream now. Called at 50Hz
|
// see if we should send a stream now. Called at 50Hz
|
||||||
|
@ -624,6 +638,8 @@ GCS_MAVLINK::send_text_P(gcs_severity severity, const prog_char_t *str)
|
||||||
|
|
||||||
void GCS_MAVLINK::handleMessage(mavlink_message_t* msg)
|
void GCS_MAVLINK::handleMessage(mavlink_message_t* msg)
|
||||||
{
|
{
|
||||||
|
// hal.uartA->printf("handleMessage %d\n", msg->msgid);
|
||||||
|
|
||||||
switch (msg->msgid) {
|
switch (msg->msgid) {
|
||||||
|
|
||||||
case MAVLINK_MSG_ID_REQUEST_DATA_STREAM:
|
case MAVLINK_MSG_ID_REQUEST_DATA_STREAM:
|
||||||
|
@ -811,7 +827,182 @@ void GCS_MAVLINK::handleMessage(mavlink_message_t* msg)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case MAVLINK_MSG_ID_GLOBAL_POSITION_INT: {
|
case MAVLINK_MSG_ID_COMMAND_LONG:
|
||||||
|
{
|
||||||
|
// decode
|
||||||
|
mavlink_command_long_t packet;
|
||||||
|
mavlink_msg_command_long_decode(msg, &packet);
|
||||||
|
if (mavlink_check_target(packet.target_system, packet.target_component)) break;
|
||||||
|
|
||||||
|
uint8_t result = MAV_RESULT_UNSUPPORTED;
|
||||||
|
|
||||||
|
// do command
|
||||||
|
send_text_P(SEVERITY_LOW,PSTR("command received: "));
|
||||||
|
|
||||||
|
switch(packet.command) {
|
||||||
|
|
||||||
|
case MAV_CMD_PREFLIGHT_CALIBRATION:
|
||||||
|
{
|
||||||
|
if (packet.param1 == 1 ||
|
||||||
|
packet.param2 == 1) {
|
||||||
|
calibrate_ins();
|
||||||
|
} else if (packet.param3 == 1) {
|
||||||
|
init_barometer();
|
||||||
|
}
|
||||||
|
if (packet.param4 == 1) {
|
||||||
|
// Cant trim radio
|
||||||
|
}
|
||||||
|
#if !defined( __AVR_ATmega1280__ )
|
||||||
|
if (packet.param5 == 1) {
|
||||||
|
float trim_roll, trim_pitch;
|
||||||
|
AP_InertialSensor_UserInteract_MAVLink interact(chan);
|
||||||
|
if(ins.calibrate_accel(&interact, trim_roll, trim_pitch)) {
|
||||||
|
// reset ahrs's trim to suggested values from calibration routine
|
||||||
|
ahrs.set_trim(Vector3f(trim_roll, trim_pitch, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
result = MAV_RESULT_ACCEPTED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN:
|
||||||
|
{
|
||||||
|
if (packet.param1 == 1 || packet.param1 == 3) {
|
||||||
|
// when packet.param1 == 3 we reboot to hold in bootloader
|
||||||
|
hal.scheduler->reboot(packet.param1 == 3);
|
||||||
|
result = MAV_RESULT_ACCEPTED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mavlink_msg_command_ack_send(
|
||||||
|
chan,
|
||||||
|
packet.command,
|
||||||
|
result);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When mavproxy 'wp sethome'
|
||||||
|
case MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST:
|
||||||
|
{
|
||||||
|
// decode
|
||||||
|
mavlink_mission_write_partial_list_t packet;
|
||||||
|
mavlink_msg_mission_write_partial_list_decode(msg, &packet);
|
||||||
|
if (mavlink_check_target(packet.target_system,packet.target_component)) break;
|
||||||
|
|
||||||
|
if (packet.start_index == 0)
|
||||||
|
{
|
||||||
|
// New home at wp index 0. Ask for it
|
||||||
|
waypoint_receiving = true;
|
||||||
|
waypoint_request_i = 0;
|
||||||
|
waypoint_request_last = 0;
|
||||||
|
send_message(MSG_NEXT_WAYPOINT);
|
||||||
|
waypoint_receiving = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX receive a WP from GCS and store in EEPROM if it is HOME
|
||||||
|
case MAVLINK_MSG_ID_MISSION_ITEM:
|
||||||
|
{
|
||||||
|
// decode
|
||||||
|
mavlink_mission_item_t packet;
|
||||||
|
uint8_t result = MAV_MISSION_ACCEPTED;
|
||||||
|
|
||||||
|
mavlink_msg_mission_item_decode(msg, &packet);
|
||||||
|
if (mavlink_check_target(packet.target_system,packet.target_component)) break;
|
||||||
|
|
||||||
|
struct Location tell_command = {};
|
||||||
|
|
||||||
|
// defaults
|
||||||
|
tell_command.id = packet.command;
|
||||||
|
|
||||||
|
switch (packet.frame)
|
||||||
|
{
|
||||||
|
case MAV_FRAME_MISSION:
|
||||||
|
case MAV_FRAME_GLOBAL:
|
||||||
|
{
|
||||||
|
tell_command.lat = 1.0e7f*packet.x; // in as DD converted to * t7
|
||||||
|
tell_command.lng = 1.0e7f*packet.y; // in as DD converted to * t7
|
||||||
|
tell_command.alt = packet.z*1.0e2f; // in as m converted to cm
|
||||||
|
tell_command.options = 0; // absolute altitude
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MAV_FRAME_LOCAL_NED
|
||||||
|
case MAV_FRAME_LOCAL_NED: // local (relative to home position)
|
||||||
|
{
|
||||||
|
tell_command.lat = 1.0e7f*ToDeg(packet.x/
|
||||||
|
(RADIUS_OF_EARTH*cosf(ToRad(home.lat/1.0e7f)))) + home.lat;
|
||||||
|
tell_command.lng = 1.0e7f*ToDeg(packet.y/RADIUS_OF_EARTH) + home.lng;
|
||||||
|
tell_command.alt = -packet.z*1.0e2f;
|
||||||
|
tell_command.options = MASK_OPTIONS_RELATIVE_ALT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MAV_FRAME_LOCAL
|
||||||
|
case MAV_FRAME_LOCAL: // local (relative to home position)
|
||||||
|
{
|
||||||
|
tell_command.lat = 1.0e7f*ToDeg(packet.x/
|
||||||
|
(RADIUS_OF_EARTH*cosf(ToRad(home.lat/1.0e7f)))) + home.lat;
|
||||||
|
tell_command.lng = 1.0e7f*ToDeg(packet.y/RADIUS_OF_EARTH) + home.lng;
|
||||||
|
tell_command.alt = packet.z*1.0e2f;
|
||||||
|
tell_command.options = MASK_OPTIONS_RELATIVE_ALT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
case MAV_FRAME_GLOBAL_RELATIVE_ALT: // absolute lat/lng, relative altitude
|
||||||
|
{
|
||||||
|
tell_command.lat = 1.0e7f * packet.x; // in as DD converted to * t7
|
||||||
|
tell_command.lng = 1.0e7f * packet.y; // in as DD converted to * t7
|
||||||
|
tell_command.alt = packet.z * 1.0e2f;
|
||||||
|
tell_command.options = MASK_OPTIONS_RELATIVE_ALT; // store altitude relative!! Always!!
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
result = MAV_MISSION_UNSUPPORTED_FRAME;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != MAV_MISSION_ACCEPTED) goto mission_failed;
|
||||||
|
|
||||||
|
// Check if receiving waypoints (mission upload expected)
|
||||||
|
if (!waypoint_receiving) {
|
||||||
|
result = MAV_MISSION_ERROR;
|
||||||
|
goto mission_failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if this is the HOME wp
|
||||||
|
if (packet.seq == 0) {
|
||||||
|
set_home(tell_command); // New home in EEPROM
|
||||||
|
send_text_P(SEVERITY_LOW,PSTR("new HOME received"));
|
||||||
|
waypoint_receiving = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
mission_failed:
|
||||||
|
// we are rejecting the mission/waypoint
|
||||||
|
mavlink_msg_mission_ack_send(
|
||||||
|
chan,
|
||||||
|
msg->sysid,
|
||||||
|
msg->compid,
|
||||||
|
result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
case MAVLINK_MSG_ID_GLOBAL_POSITION_INT:
|
||||||
|
{
|
||||||
// decode
|
// decode
|
||||||
mavlink_global_position_int_t packet;
|
mavlink_global_position_int_t packet;
|
||||||
mavlink_msg_global_position_int_decode(msg, &packet);
|
mavlink_msg_global_position_int_decode(msg, &packet);
|
||||||
|
|
|
@ -69,7 +69,12 @@ public:
|
||||||
k_param_pidYaw2Srv,
|
k_param_pidYaw2Srv,
|
||||||
|
|
||||||
k_param_channel_yaw = 200,
|
k_param_channel_yaw = 200,
|
||||||
k_param_channel_pitch
|
k_param_channel_pitch,
|
||||||
|
|
||||||
|
//
|
||||||
|
// 220: Waypoint data
|
||||||
|
//
|
||||||
|
k_param_command_total = 220,
|
||||||
|
|
||||||
// 254,255: reserved
|
// 254,255: reserved
|
||||||
};
|
};
|
||||||
|
@ -86,6 +91,10 @@ public:
|
||||||
|
|
||||||
AP_Int8 compass_enabled;
|
AP_Int8 compass_enabled;
|
||||||
|
|
||||||
|
// Waypoints
|
||||||
|
//
|
||||||
|
AP_Int8 command_total; // 1 if HOME is set
|
||||||
|
|
||||||
// PID controllers
|
// PID controllers
|
||||||
PID pidPitch2Srv;
|
PID pidPitch2Srv;
|
||||||
PID pidYaw2Srv;
|
PID pidYaw2Srv;
|
||||||
|
|
|
@ -100,6 +100,14 @@ const AP_Param::Info var_info[] PROGMEM = {
|
||||||
GGROUP(pidPitch2Srv, "PITCH2SRV_", PID),
|
GGROUP(pidPitch2Srv, "PITCH2SRV_", PID),
|
||||||
GGROUP(pidYaw2Srv, "YAW2SRV_", PID),
|
GGROUP(pidYaw2Srv, "YAW2SRV_", PID),
|
||||||
|
|
||||||
|
// @Param: CMD_TOTAL
|
||||||
|
// @DisplayName: Number of loaded mission items
|
||||||
|
// @Description: Set to 1 if HOME location has been loaded by the ground station. Do not change this manually.
|
||||||
|
// @Range: 1 255
|
||||||
|
// @User: Advanced
|
||||||
|
GSCALAR(command_total, "CMD_TOTAL", 0),
|
||||||
|
|
||||||
|
|
||||||
AP_VAREND
|
AP_VAREND
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -81,3 +81,13 @@
|
||||||
#ifndef SERIAL2_BUFSIZE
|
#ifndef SERIAL2_BUFSIZE
|
||||||
# define SERIAL2_BUFSIZE 256
|
# define SERIAL2_BUFSIZE 256
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Developer Items
|
||||||
|
//
|
||||||
|
|
||||||
|
// use this to completely disable the CLI
|
||||||
|
#ifndef CLI_ENABLED
|
||||||
|
# define CLI_ENABLED ENABLED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -30,4 +30,25 @@
|
||||||
#define AP_COMPASS_PX4 2
|
#define AP_COMPASS_PX4 2
|
||||||
#define AP_COMPASS_HIL 3
|
#define AP_COMPASS_HIL 3
|
||||||
|
|
||||||
|
// In AntennaTracker, EEPROM is used to store waypoint 0 = HOME location, if available
|
||||||
|
// EEPROM addresses
|
||||||
|
#define EEPROM_MAX_ADDR 4096
|
||||||
|
// parameters get the first 1280 bytes of EEPROM, remainder is for waypoints
|
||||||
|
#define WP_START_BYTE 0x500 // where in memory home WP is stored + all other
|
||||||
|
// WP
|
||||||
|
#define WP_SIZE 15
|
||||||
|
|
||||||
|
// Commands - Note that APM now uses a subset of the MAVLink protocol commands. See enum MAV_CMD in the GCS_Mavlink library
|
||||||
|
#define CMD_BLANK 0 // there is no command stored in the mem location requested
|
||||||
|
#define NO_COMMAND 0
|
||||||
|
#define WAIT_COMMAND 255
|
||||||
|
|
||||||
|
// Command/Waypoint/Location Options Bitmask
|
||||||
|
//--------------------
|
||||||
|
#define MASK_OPTIONS_RELATIVE_ALT (1<<0) // 1 = Relative
|
||||||
|
// altitude
|
||||||
|
#define MASK_OPTIONS_LOITER_DIRECTION (1<<2) // 0 = CW
|
||||||
|
// 1 = CCW
|
||||||
|
|
||||||
#endif // _DEFINES_H
|
#endif // _DEFINES_H
|
||||||
|
|
||||||
|
|
|
@ -61,5 +61,7 @@ static void barometer_accumulate(void)
|
||||||
static void update_GPS(void)
|
static void update_GPS(void)
|
||||||
{
|
{
|
||||||
g_gps->update();
|
g_gps->update();
|
||||||
|
// REVISIT: add compass variation with compass.set_initial_location(g_gps->latitude, g_gps->longitude);
|
||||||
|
// when have a solid GPS fix. Also init_home();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,8 +63,8 @@ static void init_tracker()
|
||||||
hal.uartC->set_blocking_writes(false);
|
hal.uartC->set_blocking_writes(false);
|
||||||
|
|
||||||
// setup antenna control PWM channels
|
// setup antenna control PWM channels
|
||||||
channel_yaw.set_angle(4500);
|
channel_yaw.set_angle(18000); // Yaw is expected to drive antenna azimuth -180-0-180
|
||||||
channel_pitch.set_angle(4500);
|
channel_pitch.set_angle(9000); // Pitch is expected to drive elevation -90-0-90
|
||||||
|
|
||||||
channel_yaw.output_trim();
|
channel_yaw.output_trim();
|
||||||
channel_pitch.output_trim();
|
channel_pitch.output_trim();
|
||||||
|
@ -75,8 +75,24 @@ static void init_tracker()
|
||||||
channel_yaw.enable_out();
|
channel_yaw.enable_out();
|
||||||
channel_pitch.enable_out();
|
channel_pitch.enable_out();
|
||||||
|
|
||||||
|
home_loc = get_home_eeprom(); // GPS may update this later
|
||||||
|
|
||||||
gcs_send_text_P(SEVERITY_LOW,PSTR("\nReady to track."));
|
gcs_send_text_P(SEVERITY_LOW,PSTR("\nReady to track."));
|
||||||
hal.scheduler->delay(1000);
|
hal.scheduler->delay(1000); // Why????
|
||||||
|
}
|
||||||
|
|
||||||
|
// Level the tracker by calibrating the INS
|
||||||
|
// Requires that the tracker be physically 'level' and horizontal
|
||||||
|
static void calibrate_ins()
|
||||||
|
{
|
||||||
|
gcs_send_text_P(SEVERITY_MEDIUM, PSTR("Beginning INS calibration; do not move tracker"));
|
||||||
|
ahrs.init();
|
||||||
|
ahrs.set_fly_forward(true);
|
||||||
|
ins.init(AP_InertialSensor::COLD_START, ins_sample_rate);
|
||||||
|
ins.init_accel();
|
||||||
|
ahrs.set_trim(Vector3f(0, 0, 0));
|
||||||
|
ahrs.reset();
|
||||||
|
init_barometer();
|
||||||
}
|
}
|
||||||
|
|
||||||
// updates the status of the notify objects
|
// updates the status of the notify objects
|
||||||
|
@ -106,4 +122,72 @@ static uint32_t map_baudrate(int8_t rate, uint32_t default_baud)
|
||||||
return default_baud;
|
return default_baud;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
fetch HOME from EEPROM
|
||||||
|
*/
|
||||||
|
static struct Location get_home_eeprom()
|
||||||
|
{
|
||||||
|
struct Location temp;
|
||||||
|
uint16_t mem;
|
||||||
|
|
||||||
|
// Find out proper location in memory by using the start_byte position + the index
|
||||||
|
// --------------------------------------------------------------------------------
|
||||||
|
if (g.command_total.get() == 0) {
|
||||||
|
memset(&temp, 0, sizeof(temp));
|
||||||
|
temp.id = CMD_BLANK;
|
||||||
|
}else{
|
||||||
|
// read WP position
|
||||||
|
mem = WP_START_BYTE;
|
||||||
|
temp.id = hal.storage->read_byte(mem);
|
||||||
|
|
||||||
|
mem++;
|
||||||
|
temp.options = hal.storage->read_byte(mem);
|
||||||
|
|
||||||
|
mem++;
|
||||||
|
temp.p1 = hal.storage->read_byte(mem);
|
||||||
|
|
||||||
|
mem++;
|
||||||
|
temp.alt = hal.storage->read_dword(mem);
|
||||||
|
|
||||||
|
mem += 4;
|
||||||
|
temp.lat = hal.storage->read_dword(mem);
|
||||||
|
|
||||||
|
mem += 4;
|
||||||
|
temp.lng = hal.storage->read_dword(mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_home_eeprom(struct Location temp)
|
||||||
|
{
|
||||||
|
uint16_t mem = WP_START_BYTE;
|
||||||
|
|
||||||
|
hal.storage->write_byte(mem, temp.id);
|
||||||
|
|
||||||
|
mem++;
|
||||||
|
hal.storage->write_byte(mem, temp.options);
|
||||||
|
|
||||||
|
mem++;
|
||||||
|
hal.storage->write_byte(mem, temp.p1);
|
||||||
|
|
||||||
|
mem++;
|
||||||
|
hal.storage->write_dword(mem, temp.alt);
|
||||||
|
|
||||||
|
mem += 4;
|
||||||
|
hal.storage->write_dword(mem, temp.lat);
|
||||||
|
|
||||||
|
mem += 4;
|
||||||
|
hal.storage->write_dword(mem, temp.lng);
|
||||||
|
|
||||||
|
// Now have a home location in EEPROM
|
||||||
|
g.command_total.set_and_save(1); // At most 1 entry for HOME
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_home(struct Location temp)
|
||||||
|
{
|
||||||
|
if (g.compass_enabled)
|
||||||
|
compass.set_initial_location(temp.lat, temp.lng);
|
||||||
|
set_home_eeprom(temp);
|
||||||
|
home_loc = temp;
|
||||||
|
}
|
||||||
|
|
|
@ -4,31 +4,149 @@
|
||||||
state of the vehicle we are tracking
|
state of the vehicle we are tracking
|
||||||
*/
|
*/
|
||||||
static struct {
|
static struct {
|
||||||
Location location;
|
Location location; // lat, long in degrees * 10^7; alt in meters * 100
|
||||||
uint32_t last_update_us;
|
uint32_t last_update_us;
|
||||||
float heading; // degrees
|
float heading; // degrees
|
||||||
float ground_speed; // m/s
|
float ground_speed; // m/s
|
||||||
} vehicle;
|
} vehicle;
|
||||||
|
|
||||||
static Location our_location;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
update the pitch servo. The aim is to drive the boards pitch to the
|
update the pitch (elevation) servo. The aim is to drive the boards ahrs pitch to the
|
||||||
requested pitch
|
requested pitch, so the board (and therefore the antenna) will be pointing at the target
|
||||||
*/
|
*/
|
||||||
static void update_pitch_servo(float pitch)
|
static void update_pitch_servo(float pitch)
|
||||||
{
|
{
|
||||||
channel_pitch.servo_out = g.pidPitch2Srv.get_pid_4500(degrees(ahrs.pitch) - pitch);
|
// degrees(ahrs.pitch) is -90 to 90, where 0 is horizontal
|
||||||
|
// pitch argument is -90 to 90, where 0 is horizontal
|
||||||
|
// servo_out is in 100ths of a degree
|
||||||
|
float ahrs_pitch = degrees(ahrs.pitch);
|
||||||
|
int32_t err = (ahrs_pitch - pitch) * 100.0;
|
||||||
|
// Need to configure your servo so that increasing servo_out causes increase in pitch/elevation (ie pointing higher into the sky,
|
||||||
|
// above the horizon. On my antenna tracker this requires the pitch/elevation servo to be reversed
|
||||||
|
// param set RC2_REV -1
|
||||||
|
//
|
||||||
|
// The pitch servo (RC channel 2) is configured for servo_out of -9000-0-9000 servo_out,
|
||||||
|
// which will drive the servo from RC2_MIN to RC2_MAX usec pulse width.
|
||||||
|
// Therefore, you must set RC2_MIN and RC2_MAX so that your servo drives the antenna altitude between -90 to 90 exactly
|
||||||
|
// To drive my HS-645MG servos through their full 180 degrees of rotational range, I have to set:
|
||||||
|
// param set RC2_MAX 2540
|
||||||
|
// param set RC2_MIN 640
|
||||||
|
//
|
||||||
|
// You will also need to tune the pitch PID to suit your antenna and servos. I use:
|
||||||
|
// PITCH2SRV_P 0.100000
|
||||||
|
// PITCH2SRV_I 0.020000
|
||||||
|
// PITCH2SRV_D 0.000000
|
||||||
|
// PITCH2SRV_IMAX 4000.000000
|
||||||
|
int32_t new_servo_out = channel_pitch.servo_out - g.pidPitch2Srv.get_pid(err);
|
||||||
|
channel_pitch.servo_out = constrain_float(new_servo_out, -9000, 9000);
|
||||||
channel_pitch.calc_pwm();
|
channel_pitch.calc_pwm();
|
||||||
channel_pitch.output();
|
channel_pitch.output();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
update the yaw servo
|
update the yaw (azimuth) servo. The aim is to drive the boards ahrs yaw to the
|
||||||
|
requested yaw, so the board (and therefore the antenna) will be pinting at the target
|
||||||
*/
|
*/
|
||||||
static void update_yaw_servo(float yaw)
|
static void update_yaw_servo(float yaw)
|
||||||
{
|
{
|
||||||
channel_yaw.servo_out = g.pidYaw2Srv.get_pid_4500(degrees(ahrs.yaw) - yaw);
|
// degrees(ahrs.yaw) is -180 to 180, where 0 is north
|
||||||
|
float ahrs_yaw = degrees(ahrs.yaw);
|
||||||
|
// yaw argument is 0 to 360 where 0 and 360 are north
|
||||||
|
// Make yaw -180-0-180 too
|
||||||
|
if (yaw > 180)
|
||||||
|
yaw = yaw - 360;
|
||||||
|
|
||||||
|
// Antenna as Ballerina. Use with antenna that do not have continuously rotating servos, ie at some point in rotation
|
||||||
|
// the servo limits are reached and the servo has to slew 360 degrees to the 'other side' to keep tracking.
|
||||||
|
//
|
||||||
|
// This algorithm accounts for the fact that the antenna mount may not be aligned with North
|
||||||
|
// (in fact, any alignment is permissable), and that the alignment may change (possibly rapidly) over time
|
||||||
|
// (as when the antenna is mounted on a moving, turning vehicle)
|
||||||
|
// When the servo is being forced beyond its limits, it rapidly slews to the 'other side' then normal tracking takes over.
|
||||||
|
//
|
||||||
|
// Caution: this whole system is compromised by the fact that the ahrs_yaw reported by the compass system lags
|
||||||
|
// the actual yaw by about 5 seconds, and also periodically realigns itself with about a 30 second period,
|
||||||
|
// which makes it very hard to be completely sure exactly where the antenna is _really_ pointing
|
||||||
|
// especially during the high speed slew. This can cause odd pointing artifacts from time to time. The best strategy is to
|
||||||
|
// position and point the mount so the aircraft does not 'go behind' the antenna (if possible)
|
||||||
|
//
|
||||||
|
// With my antenna mount, large pwm output drives the antenna anticlockise, so need:
|
||||||
|
// param set RC1_REV -1
|
||||||
|
// to reverse the servo. Yours may be different
|
||||||
|
//
|
||||||
|
// You MUST set RC1_MIN and RC1_MAX so that your servo drives the antenna azimuth from -180 to 180 relative
|
||||||
|
// to the mount.
|
||||||
|
// To drive my HS-645MG servos through their full 180 degrees of rotational range and therefore the
|
||||||
|
// antenna through a full 360 degrees, I have to set:
|
||||||
|
// param set RC1_MAX 2380
|
||||||
|
// param set RC1_MIN 680
|
||||||
|
// According to the specs at https://www.servocity.com/html/hs-645mg_ultra_torque.html,
|
||||||
|
// that should be 600 through 2400, but the azimuth gearing in my antenna pointer is not exactly 2:1
|
||||||
|
int32_t err = (ahrs_yaw - yaw) * 100.0;
|
||||||
|
static int32_t last_err = 0.0;
|
||||||
|
|
||||||
|
// Correct for wrapping yaw at +-180
|
||||||
|
// so we get the error to the _closest_ version of the target azimuth
|
||||||
|
// +ve error requires anticlockwise motion (ie towards more negative yaw)
|
||||||
|
if (err > 18000)
|
||||||
|
err -= 36000;
|
||||||
|
else if (err < -18000)
|
||||||
|
err += 36000;
|
||||||
|
|
||||||
|
static int32_t slew_to = 0;
|
||||||
|
|
||||||
|
int32_t servo_err = channel_yaw.servo_out - err; // Servo position we need to get to
|
||||||
|
if ( !slew_to
|
||||||
|
&& servo_err > 19000 // 10 degreee deadband
|
||||||
|
&& err < 0
|
||||||
|
&& last_err > err)
|
||||||
|
{
|
||||||
|
// We need to be beyond the servo limits and the error magnitude is increasing
|
||||||
|
// Slew most of the way to the other side at high speed...
|
||||||
|
slew_to = servo_err - 27000;
|
||||||
|
}
|
||||||
|
else if ( !slew_to
|
||||||
|
&& servo_err < -19000 // 10 degreee deadband
|
||||||
|
&& err > 0
|
||||||
|
&& last_err < err)
|
||||||
|
{
|
||||||
|
// We need to be beyond the servo limits and the error magnitude is increasing
|
||||||
|
// Slew most of the way to the other side at high speed...
|
||||||
|
slew_to = servo_err + 27000;
|
||||||
|
}
|
||||||
|
else if ( slew_to < 0
|
||||||
|
&& err > 0
|
||||||
|
&& last_err < err)
|
||||||
|
{
|
||||||
|
// ...then let normal tracking take over
|
||||||
|
slew_to = 0;
|
||||||
|
}
|
||||||
|
else if ( slew_to > 0
|
||||||
|
&& err < 0
|
||||||
|
&& last_err > err)
|
||||||
|
{
|
||||||
|
// ...then let normal tracking take over
|
||||||
|
slew_to = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slew_to)
|
||||||
|
{
|
||||||
|
channel_yaw.servo_out = slew_to;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Normal tracking
|
||||||
|
// You will need to tune the yaw PID to suit your antenna and servos
|
||||||
|
// For my servos, suitable PID settings are:
|
||||||
|
// param set YAW2SRV_P 0.1
|
||||||
|
// param set YAW2SRV_I 0.05
|
||||||
|
// param set YAW2SRV_D 0
|
||||||
|
// param set YAW2SRV_IMAX 4000
|
||||||
|
|
||||||
|
int32_t new_servo_out = channel_yaw.servo_out - g.pidYaw2Srv.get_pid(err);
|
||||||
|
channel_yaw.servo_out = constrain_float(new_servo_out, -18000, 18000);
|
||||||
|
}
|
||||||
|
last_err = err;
|
||||||
channel_yaw.calc_pwm();
|
channel_yaw.calc_pwm();
|
||||||
channel_yaw.output();
|
channel_yaw.output();
|
||||||
}
|
}
|
||||||
|
@ -46,16 +164,17 @@ static void update_tracking(void)
|
||||||
|
|
||||||
// update our position if we have at least a 2D fix
|
// update our position if we have at least a 2D fix
|
||||||
if (g_gps->status() >= GPS::GPS_OK_FIX_2D) {
|
if (g_gps->status() >= GPS::GPS_OK_FIX_2D) {
|
||||||
our_location.lat = g_gps->latitude;
|
current_loc.lat = g_gps->latitude;
|
||||||
our_location.lng = g_gps->longitude;
|
current_loc.lng = g_gps->longitude;
|
||||||
our_location.alt = 0; // assume ground level for now
|
current_loc.alt = 0; // assume ground level for now REVISIT: WHY?
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
current_loc = home_loc; // dont know any better
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate the bearing to the vehicle
|
// calculate the bearing to the vehicle
|
||||||
float bearing = get_bearing_cd(our_location, vehicle.location) * 0.01f;
|
float bearing = get_bearing_cd(current_loc, vehicle.location) * 0.01f;
|
||||||
float distance = get_distance(our_location, vehicle.location);
|
float distance = get_distance(current_loc, vehicle.location);
|
||||||
float pitch = degrees(atan2(vehicle.location.alt - our_location.alt, distance));
|
float pitch = degrees(atan2((vehicle.location.alt - current_loc.alt)/100, distance));
|
||||||
|
|
||||||
// update the servos
|
// update the servos
|
||||||
update_pitch_servo(pitch);
|
update_pitch_servo(pitch);
|
||||||
update_yaw_servo(bearing);
|
update_yaw_servo(bearing);
|
||||||
|
@ -79,3 +198,4 @@ static void tracking_update_position(const mavlink_global_position_int_t &msg)
|
||||||
vehicle.ground_speed = pythagorous2(msg.vx, msg.vy) * 0.01f;
|
vehicle.ground_speed = pythagorous2(msg.vx, msg.vy) * 0.01f;
|
||||||
vehicle.last_update_us = hal.scheduler->micros();
|
vehicle.last_update_us = hal.scheduler->micros();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue