aboutsummaryrefslogblamecommitdiff
path: root/src/modules/navigator/abs_follow.cpp
blob: cce2b712a7d092d9017c59d18b47d1c653e75859 (plain) (tree)
































































































































































































































































                                                                                                                                                                                                  
/****************************************************************************
 *
 *   Copyright (c) 2013-2014 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/
/**
 * @file abs_follow.cpp
 *
 * @author Julian Oes <julian@oes.ch>
 * @author Anton Babushkin <anton.babushkin@me.com>
 * @author Martins Frolovs <martins.f@airdog.com>
 */

#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
#include <fcntl.h>

#include <mavlink/mavlink_log.h>
#include <systemlib/err.h>

#include <uORB/uORB.h>
#include <uORB/topics/position_setpoint_triplet.h>

#include "navigator.h"
#include "abs_follow.h"

AbsFollow::AbsFollow(Navigator *navigator, const char *name) :
	MissionBlock(navigator, name)
{
    updateParameters();
}

AbsFollow::~AbsFollow()
{
}

void
AbsFollow::on_inactive()
{
}

void
AbsFollow::on_activation()
{
	updateParameters();

	_afollow_offset.zero();
	global_pos = _navigator->get_global_position();
	target_pos = _navigator->get_target_position();
	home_pos = _navigator->get_home_position();
	pos_sp_triplet = _navigator->get_position_setpoint_triplet();

	_init_alt = global_pos->alt;

	float target_alt = target_pos->alt;

	get_vector_to_next_waypoint_fast(target_pos->lat, target_pos->lon, global_pos->lat, global_pos->lon, &_afollow_offset.data[0], &_afollow_offset.data[1]);
	_afollow_offset.data[2] = -(global_pos->alt - target_alt);

	mavlink_log_info(_navigator->get_mavlink_fd(), "[abs_fol] Reset abs_follow offset: %.2f, %.2f, %.2f", (double)_afollow_offset(0), (double)_afollow_offset(1), (double)_afollow_offset(2));

	point_camera_to_target(&(pos_sp_triplet->current));
	_navigator->set_position_setpoint_triplet_updated();
}

void
AbsFollow::on_active()
{

	/* Update position data pointer */
	global_pos = _navigator->get_global_position();
	home_pos = _navigator->get_home_position();
	target_pos = _navigator->get_target_position();
	pos_sp_triplet = _navigator->get_position_setpoint_triplet();

	// Execute command if received
	if ( update_vehicle_command() )
			execute_vehicle_command();

	_target_lat = target_pos->lat;
	_target_lon = target_pos->lon;

	double lat_new;
	double lon_new;

	/* add offset to target position */
	add_vector_to_global_position(
			_target_lat, _target_lon,
			_afollow_offset(0), _afollow_offset(1),
			&lat_new, &lon_new
	);

	pos_sp_triplet->current.valid = true;
	pos_sp_triplet->current.type = SETPOINT_TYPE_MOVING;

	pos_sp_triplet->current.lat = lat_new;
	pos_sp_triplet->current.lon = lon_new;

	if (_parameters.afol_rep_target_alt)
		pos_sp_triplet->current.alt = target_pos->alt - _afollow_offset(2);
	else
		pos_sp_triplet->current.alt = _init_alt;


	/* calculate direction to target */
	pos_sp_triplet->current.yaw = get_bearing_to_next_waypoint(global_pos->lat, global_pos->lon, target_pos->lat, target_pos->lon);
	pos_sp_triplet->current.pitch_min = 0.0f;

	_navigator->set_position_setpoint_triplet_updated();

}

void
AbsFollow::execute_vehicle_command() {

    // Update _parameter values with the latest navigator_mode parameters
    memcpy(&_parameters, &(NavigatorMode::_parameters), sizeof(_parameters));

	vehicle_command_s cmd = _vcommand;

	if (cmd.command == VEHICLE_CMD_NAV_REMOTE_CMD) {

		REMOTE_CMD remote_cmd = (REMOTE_CMD)cmd.param1;

		math::Vector<3> offset =_afollow_offset;

		switch(remote_cmd){
			case REMOTE_CMD_PLAY_PAUSE: {
				commander_request_s *commander_request = _navigator->get_commander_request();
				commander_request->request_type = V_MAIN_STATE_CHANGE;
				commander_request->main_state = MAIN_STATE_AUTO_LOITER;
				_navigator->set_commander_request_updated();
				break;
			}

			case REMOTE_CMD_UP: {

				_afollow_offset.data[2] -= _parameters.loi_step_len;
				break;
			}
			case REMOTE_CMD_DOWN: {

				_afollow_offset.data[2] += _parameters.loi_step_len;
				break;
			}
			case REMOTE_CMD_LEFT: {

				math::Matrix<3, 3> R_phi;

				double radius = sqrt(offset(0) * offset(0) + offset(1) * offset(1));

				// derived from formula: ( step / ( sqrt(x^2 + y^2)*2PI ) ) *  2PI
				// radius: (sqrt(x^2 + y^2)
				// circumference C: (radius * 2* PI)
				// step length fraction of C: step/C
				// angle of step fraction in radians: step/C * 2PI
				double alpha = (double)_parameters.loi_step_len / radius;

				// vector yaw rotation +alpha or -alpha depending on left or right
				R_phi.from_euler(0.0f, 0.0f, alpha);
				math::Vector<3> offset_new  = R_phi * offset;

				_afollow_offset = offset_new;

				break;
			}
			case REMOTE_CMD_RIGHT: {

				math::Matrix<3, 3> R_phi;

				double radius = sqrt(offset(0) * offset(0) + offset(1) * offset(1));

				// derived from formula: ( step / ( sqrt(x^2 + y^2)*2PI ) ) *  2PI
				// radius: (sqrt(x^2 + y^2)
				// circumference C: (radius * 2* PI)
				// step length fraction of C: step/C
				// angle of step fraction in radians: step/C * 2PI
				double alpha = (double)_parameters.loi_step_len / radius;

				// vector yaw rotation +alpha or -alpha depending on left or right
				R_phi.from_euler(0.0f, 0.0f, -alpha);
				math::Vector<3> offset_new  = R_phi * offset;

				_afollow_offset = offset_new;

				break;
			}
			case REMOTE_CMD_CLOSER: {

				// Calculate vector angle from target to device with atan2(y, x)
				float alpha = atan2f(offset(1), offset(0));

				// Create vector in the same direction, with loiter_step length
				math::Vector<3> offset_delta(
						cosf(alpha) * _parameters.loi_step_len,
						sinf(alpha) * _parameters.loi_step_len,
						0);

				math::Vector<3> offset_new = offset - offset_delta;

				_afollow_offset = offset_new;

				break;

			}

			case REMOTE_CMD_FURTHER: {

				// Calculate vector angle from target to device with atan2(y, x)
				float alpha = atan2(offset(1), offset(0));

				// Create vector in the same direction, with loiter_step length
				math::Vector<3> offset_delta(
						cosf(alpha) * _parameters.loi_step_len,
						sinf(alpha) * _parameters.loi_step_len,
						0);

				math::Vector<3> offset_new = offset + offset_delta;

				_afollow_offset = offset_new;

				break;
			}

		}
	}

}