mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2024-12-12 20:08:48 +01:00
405 lines
12 KiB
C++
405 lines
12 KiB
C++
/**
|
|
******************************************************************************
|
|
*
|
|
* @file pathcompiler.h
|
|
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
|
* @addtogroup GCSPlugins GCS Plugins
|
|
* @{
|
|
* @addtogroup OPMapPlugin OpenPilot Map Plugin
|
|
* @{
|
|
* @brief The OpenPilot Map plugin
|
|
*****************************************************************************/
|
|
/*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
#include <pathcompiler.h>
|
|
#include <extensionsystem/pluginmanager.h>
|
|
#include <utils/coordinateconversions.h>
|
|
#include <uavobjectmanager.h>
|
|
#include <waypoint.h>
|
|
#include <homelocation.h>
|
|
|
|
#include <QDebug>
|
|
|
|
PathCompiler::PathCompiler(QObject *parent) :
|
|
QObject(parent)
|
|
{
|
|
HomeLocation *homeLocation = NULL;
|
|
|
|
/* To catch new waypoint UAVOs */
|
|
connect(getObjectManager(), SIGNAL(newInstance(UAVObject *)), this, SLOT(doNewInstance(UAVObject *)));
|
|
|
|
/* Connect the object updates */
|
|
int numWaypoints = getObjectManager()->getNumInstances(Waypoint::OBJID);
|
|
for (int i = 0; i < numWaypoints; i++) {
|
|
Waypoint *waypoint = Waypoint::GetInstance(getObjectManager(), i);
|
|
Q_ASSERT(waypoint);
|
|
if (waypoint) {
|
|
connect(waypoint, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(doUpdateFromUAV(UAVObject *)));
|
|
}
|
|
}
|
|
|
|
homeLocation = HomeLocation::GetInstance(getObjectManager());
|
|
Q_ASSERT(homeLocation);
|
|
if (homeLocation) {
|
|
connect(homeLocation, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(doUpdateFromUAV(UAVObject *)));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helper method to get the uavobjectamanger
|
|
*/
|
|
UAVObjectManager *PathCompiler::getObjectManager()
|
|
{
|
|
ExtensionSystem::PluginManager *pm = NULL;
|
|
UAVObjectManager *objMngr = NULL;
|
|
|
|
pm = ExtensionSystem::PluginManager::instance();
|
|
Q_ASSERT(pm);
|
|
if (pm) {
|
|
objMngr = pm->getObject<UAVObjectManager>();
|
|
}
|
|
Q_ASSERT(objMngr);
|
|
|
|
return objMngr;
|
|
}
|
|
|
|
/**
|
|
* This method opens a dialog (if filename is null) and saves the path
|
|
* @param filename The file to save the path to
|
|
* @returns -1 for failure, 0 for success
|
|
*/
|
|
int PathCompiler::savePath(QString filename)
|
|
{
|
|
Q_UNUSED(filename);
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* This method opens a dialog (if filename is null) and loads the path
|
|
* @param filename The file to load from
|
|
* @returns -1 for failure, 0 for success
|
|
*/
|
|
int PathCompiler::loadPath(QString filename)
|
|
{
|
|
Q_UNUSED(filename);
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* Called whenever a new object instance is created so we can check
|
|
* if it's a waypoint and if so connect to it
|
|
* @param [in] obj The point to the object being created
|
|
*/
|
|
void PathCompiler::doNewInstance(UAVObject *obj)
|
|
{
|
|
Q_ASSERT(obj);
|
|
if (!obj) {
|
|
return;
|
|
}
|
|
|
|
if (obj->getObjID() == Waypoint::OBJID) {
|
|
connect(obj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(doUpdateFromUAV(UAVObject *)));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* add a waypoint
|
|
* @param waypoint the new waypoint to add
|
|
* @param position which position to insert it to, defaults to end
|
|
*/
|
|
void PathCompiler::doAddWaypoint(waypoint newWaypointInternal, int /*position*/)
|
|
{
|
|
/* TODO: If a waypoint is inserted not at the end shift them all by one and */
|
|
/* add the data there */
|
|
|
|
UAVObjectManager *objManager = getObjectManager();
|
|
|
|
// Format the data from the map into a UAVO
|
|
Waypoint::DataFields newWaypoint = InternalToUavo(newWaypointInternal);
|
|
|
|
// Search for any waypoints set to stop, because if they exist we
|
|
// should add the waypoint immediately after that one
|
|
int numWaypoints = objManager->getNumInstances(Waypoint::OBJID);
|
|
int i;
|
|
|
|
for (i = 0; i < numWaypoints; i++) {
|
|
Waypoint *waypoint = Waypoint::GetInstance(objManager, i);
|
|
Q_ASSERT(waypoint);
|
|
if (waypoint == NULL) {
|
|
return;
|
|
}
|
|
|
|
Waypoint::DataFields waypointData = waypoint->getData();
|
|
if (waypointData.Action == Waypoint::ACTION_STOP) {
|
|
waypointData.Action = Waypoint::ACTION_PATHTONEXT;
|
|
waypoint->setData(waypointData);
|
|
waypoint->updated();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i >= numWaypoints - 1) {
|
|
// We reached end of list so new waypoint needs to be registered
|
|
|
|
Waypoint *waypoint = new Waypoint();
|
|
Q_ASSERT(waypoint);
|
|
if (waypoint) {
|
|
// Register a new waypoint instance
|
|
quint32 newInstId = objManager->getNumInstances(waypoint->getObjID());
|
|
waypoint->initialize(newInstId, waypoint->getMetaObject());
|
|
objManager->registerObject(waypoint);
|
|
|
|
// Set the data in the new object
|
|
waypoint->setData(newWaypoint);
|
|
waypoint->updated();
|
|
}
|
|
} else {
|
|
Waypoint *waypoint = Waypoint::GetInstance(objManager, i + 1);
|
|
Q_ASSERT(waypoint);
|
|
if (waypoint) {
|
|
waypoint->setData(newWaypoint);
|
|
waypoint->updated();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update waypoint
|
|
*/
|
|
void PathCompiler::doUpdateWaypoints(PathCompiler::waypoint changedWaypoint, int position)
|
|
{
|
|
int numWaypoints = getObjectManager()->getNumInstances(Waypoint::OBJID);
|
|
|
|
Q_ASSERT(position < numWaypoints);
|
|
if (position >= numWaypoints) {
|
|
return;
|
|
}
|
|
|
|
Waypoint *waypointInst = Waypoint::GetInstance(getObjectManager(), position);
|
|
Q_ASSERT(waypointInst);
|
|
|
|
// Mirror over the updated position. We don't just use the changedWaypoint
|
|
// because things like action might need to be preserved
|
|
Waypoint::DataFields changedWaypointUAVO = InternalToUavo(changedWaypoint);
|
|
Waypoint::DataFields oldWaypointUAVO = waypointInst->getData();
|
|
oldWaypointUAVO.Position[0] = changedWaypointUAVO.Position[0];
|
|
oldWaypointUAVO.Position[1] = changedWaypointUAVO.Position[1];
|
|
// Don't take the altitude from the map for now
|
|
|
|
waypointInst->setData(oldWaypointUAVO);
|
|
waypointInst->updated();
|
|
}
|
|
|
|
/**
|
|
* Delete a waypoint
|
|
* @param index which waypoint to delete
|
|
*/
|
|
void PathCompiler::doDelWaypoint(int index)
|
|
{
|
|
// This method is awkward because there is no support
|
|
// on the FC for actually deleting a waypoint. We need
|
|
// to shift them all by one and set the new "last" waypoint
|
|
// to a stop action
|
|
|
|
UAVObjectManager *objManager = getObjectManager();
|
|
Waypoint *waypoint = Waypoint::GetInstance(objManager);
|
|
|
|
Q_ASSERT(waypoint);
|
|
if (!waypoint) {
|
|
return;
|
|
}
|
|
|
|
int numWaypoints = objManager->getNumInstances(waypoint->getObjID());
|
|
for (int i = index; i < numWaypoints - 1; i++) {
|
|
Waypoint *waypointDest = Waypoint::GetInstance(objManager, i);
|
|
Q_ASSERT(waypointDest);
|
|
|
|
Waypoint *waypointSrc = Waypoint::GetInstance(objManager, i + 1);
|
|
Q_ASSERT(waypointSrc);
|
|
|
|
if (!waypointDest || !waypointSrc) {
|
|
return;
|
|
}
|
|
|
|
// Copy the data down an index
|
|
Waypoint::DataFields waypoint = waypointSrc->getData();
|
|
waypointDest->setData(waypoint);
|
|
waypointDest->updated();
|
|
}
|
|
|
|
// Set the second to last waypoint to stop (and last for safety)
|
|
// the functional equivalent to deleting
|
|
for (int i = numWaypoints - 2; i < numWaypoints; i++) {
|
|
waypoint = Waypoint::GetInstance(objManager, i);
|
|
Q_ASSERT(waypoint);
|
|
if (waypoint) {
|
|
Waypoint::DataFields waypointData = waypoint->getData();
|
|
waypointData.Action = Waypoint::ACTION_STOP;
|
|
waypoint->setData(waypointData);
|
|
waypoint->updated();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete all the waypoints
|
|
*/
|
|
void PathCompiler::doDelAllWaypoints()
|
|
{
|
|
Waypoint *waypointObj = Waypoint::GetInstance(getObjectManager(), 0);
|
|
|
|
Q_ASSERT(waypointObj);
|
|
if (waypointObj == NULL) {
|
|
return;
|
|
}
|
|
|
|
int numWaypoints = getObjectManager()->getNumInstances(waypointObj->getObjID());
|
|
for (int i = 0; i < numWaypoints; i++) {
|
|
Waypoint *waypoint = Waypoint::GetInstance(getObjectManager(), i);
|
|
Q_ASSERT(waypoint);
|
|
if (waypoint) {
|
|
Waypoint::DataFields waypointData = waypoint->getData();
|
|
waypointData.Action = Waypoint::ACTION_STOP;
|
|
waypoint->setData(waypointData);
|
|
}
|
|
}
|
|
|
|
waypointObj->updated();
|
|
}
|
|
|
|
/**
|
|
* When the UAV waypoints change trigger the pathcompiler to
|
|
* get the latest version and then update the visualization
|
|
*/
|
|
void PathCompiler::doUpdateFromUAV(UAVObject *obj)
|
|
{
|
|
UAVObjectManager *objManager = getObjectManager();
|
|
|
|
if (!objManager) {
|
|
return;
|
|
}
|
|
|
|
Waypoint *waypointObj = Waypoint::GetInstance(getObjectManager());
|
|
Q_ASSERT(waypointObj);
|
|
if (waypointObj == NULL) {
|
|
return;
|
|
}
|
|
|
|
/* Get all the waypoints from the UAVO and create a representation for the visualization */
|
|
QList <waypoint> waypoints;
|
|
waypoints.clear();
|
|
int numWaypoints = objManager->getNumInstances(waypointObj->getObjID());
|
|
bool stopped = false;
|
|
for (int i = 0; i < numWaypoints && !stopped; i++) {
|
|
Waypoint *waypoint = Waypoint::GetInstance(objManager, i);
|
|
Q_ASSERT(waypoint);
|
|
if (waypoint == NULL) {
|
|
return;
|
|
}
|
|
|
|
Waypoint::DataFields waypointData = waypoint->getData();
|
|
waypoints.append(UavoToInternal(waypointData));
|
|
stopped = waypointData.Action == Waypoint::ACTION_STOP;
|
|
}
|
|
|
|
if (previousWaypoints != waypoints) {
|
|
/* Because the waypoints have to update periodically (or we miss new ones on the FC */
|
|
/* side - needs telem fix) we want to filter updates to map that are simply periodic */
|
|
previousWaypoints = waypoints;
|
|
|
|
/* Inform visualization */
|
|
emit visualizationChanged(waypoints);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Convert a UAVO waypoint to the local structure
|
|
* @param uavo The UAVO data representation
|
|
* @return The waypoint structure for visualization
|
|
*/
|
|
struct PathCompiler::waypoint PathCompiler::UavoToInternal(Waypoint::DataFields uavo)
|
|
{
|
|
double homeLLA[3];
|
|
double LLA[3];
|
|
double NED[3];
|
|
waypoint internalWaypoint;
|
|
|
|
HomeLocation *homeLocation = HomeLocation::GetInstance(getObjectManager());
|
|
|
|
Q_ASSERT(homeLocation);
|
|
if (homeLocation == NULL) {
|
|
return internalWaypoint;
|
|
}
|
|
HomeLocation::DataFields homeLocationData = homeLocation->getData();
|
|
homeLLA[0] = homeLocationData.Latitude / 10e6;
|
|
homeLLA[1] = homeLocationData.Longitude / 10e6;
|
|
homeLLA[2] = homeLocationData.Altitude;
|
|
|
|
NED[0] = uavo.Position[Waypoint::POSITION_NORTH];
|
|
NED[1] = uavo.Position[Waypoint::POSITION_EAST];
|
|
NED[2] = uavo.Position[Waypoint::POSITION_DOWN];
|
|
Utils::CoordinateConversions().GetLLA(homeLLA, NED, LLA);
|
|
|
|
internalWaypoint.latitude = LLA[0];
|
|
internalWaypoint.longitude = LLA[1];
|
|
internalWaypoint.altitude = LLA[2];
|
|
return internalWaypoint;
|
|
}
|
|
|
|
/**
|
|
* Convert a UAVO waypoint to the local structure
|
|
* @param internal The internal structure type
|
|
* @returns The waypoint UAVO data structure
|
|
*/
|
|
Waypoint::DataFields PathCompiler::InternalToUavo(waypoint internal)
|
|
{
|
|
Waypoint::DataFields uavo;
|
|
|
|
double homeLLA[3];
|
|
double LLA[3];
|
|
double NED[3];
|
|
|
|
HomeLocation *homeLocation = HomeLocation::GetInstance(getObjectManager());
|
|
|
|
Q_ASSERT(homeLocation);
|
|
if (homeLocation == NULL) {
|
|
return uavo;
|
|
}
|
|
HomeLocation::DataFields homeLocationData = homeLocation->getData();
|
|
homeLLA[0] = homeLocationData.Latitude / 10e6;
|
|
homeLLA[1] = homeLocationData.Longitude / 10e6;
|
|
homeLLA[2] = homeLocationData.Altitude;
|
|
|
|
// TODO: Give the point a concept of altitude
|
|
LLA[0] = internal.latitude;
|
|
LLA[1] = internal.longitude;
|
|
LLA[2] = internal.altitude;
|
|
|
|
Utils::CoordinateConversions().GetNED(homeLLA, LLA, NED);
|
|
|
|
uavo.Position[Waypoint::POSITION_NORTH] = NED[0];
|
|
uavo.Position[Waypoint::POSITION_EAST] = NED[1];
|
|
uavo.Position[Waypoint::POSITION_DOWN] = NED[2];
|
|
|
|
uavo.Action = Waypoint::ACTION_PATHTONEXT;
|
|
|
|
uavo.Velocity[Waypoint::VELOCITY_NORTH] = 5;
|
|
uavo.Velocity[Waypoint::VELOCITY_EAST] = 0;
|
|
uavo.Velocity[Waypoint::VELOCITY_DOWN] = 0;
|
|
|
|
return uavo;
|
|
}
|