关键词:OSDK waypoint v2,actions触发,航点任务
一、概述
前面大致介绍了下OSDK waypoint mission(waypoint v1)功能,但是OSDK提供waypoint v2后,M300机型已经没有兼容v1版本了,估计后面的机型都会使用v2。
v2的差别还是挺大的,所以再随笔写写v2的sample跟读。文档链接和github链接与waypoint v1一样,功能基本一致,代码再同一文件夹下:
文档:
https://developer.dji.com/cn/document/d625d3fc-ad52-4db4-9409-6406cea669b4
github 链接:
https://www.github.com/dji-sdk/Onboard-SDK/tree/4.1/sample/platform/linux/missions
二、代码:
主main代码:waypoint_v2_main.cpp,main中很简单,主要启动一个WaypointV2MissionSample示例,即我们主要要跟的示例代码在:
waypoint_v2_sample.cpp中,先找到执行代码贴出来如下:
ErrorCode::ErrorCodeType WaypointV2MissionSample::runWaypointV2Mission()
{
if (!vehiclePtr->isM300()) {
DSTATUS("This sample only supports M300!"); /*当前waypoint v2 仅支持M300机型*/
return false;
}
int timeout = 1;
GetRemainRamAck actionMemory = {0};
ErrorCode::ErrorCodeType ret;
if (!setUpSubscription(timeout))
{
DERROR("Failed to set up subscription!");
return -1;
}
else
{
DSTATUS("Set up subscription successfully!");
}
/*! wait for subscription data come*/
sleep(timeout);
/*! init mission */ /* 初始化mission任务 */
ret = initMissionSetting(timeout);
if(ret != ErrorCode::SysCommonErr::Success)
return ret;
sleep(timeout);
/*! upload mission */
/*! upload mission's timeout need to be longer than 2s*/
int uploadMissionTimeOut = 3;
ret = uploadWaypointMission(uploadMissionTimeOut); /* 上传任务,注意注释部分,这里的超时需要设置为3s, 设置为1时,可能因为上传任务过多,报index错误*/
if(ret != ErrorCode::SysCommonErr::Success)
return ret;
sleep(timeout);
/*! download mission */ /* 下载任务,可以查看对比上传的任务 debug的时候可以用来对比排查问题 */
std::vector<WaypointV2> mission;
ret = downloadWaypointMission(mission, timeout);
if(ret != ErrorCode::SysCommonErr::Success)
return ret;
sleep(timeout);
/*! upload actions */ /* 上传actions:*/
/*! check action memory */
ret = getActionRemainMemory(actionMemory, timeout); //上传action前先检查action容量,避免上传的任务过多导致action被挤掉了,执行动作可能不完整。最大貌似为65535 byte
if (actionMemory.remainMemory <= 0)
{
DSTATUS("action memory is not enough.Can not upload more action!");
return ErrorCode::SysCommonErr::UndefinedError;
}
ret = uploadWapointActions(timeout);
if(ret != ErrorCode::SysCommonErr::Success)
return ret;
ret = getActionRemainMemory(actionMemory, timeout);
sleep(timeout);
/*! start mission */
ret = startWaypointMission(timeout); //开始执行
if(ret != ErrorCode::SysCommonErr::Success)
return ret;
sleep(20);
/*! set global cruise speed */
setGlobalCruiseSpeed(1.5, timeout); //设置巡航速度,巡航速度为全程航线的巡航速度,不是通过单点航点任务来设置的。可以在单点航点中更改,间接实现不同的航点以不同的速度运行。
sleep(timeout);
/*! get global cruise speed */
getGlobalCruiseSpeed(timeout);
sleep(timeout);
/*! pause the mission*/
ret = pauseWaypointMission(timeout);
if(ret != ErrorCode::SysCommonErr::Success)
return ret;
sleep(5);
printf("kyle test: pauseWaypointMission and resumeWaypointMission\n");
/*! resume the mission*/
ret = resumeWaypointMission(timeout); //暂停及回复航线指令
if(ret != ErrorCode::SysCommonErr::Success)
return ret;
sleep(50);
/*! Set up telemetry subscription*/
if(!teardownSubscription(DEFAULT_PACKAGE_INDEX, timeout))
{
std::cout << "Failed to tear down Subscription!" << std::endl;
return ErrorCode::SysCommonErr::UndefinedError;
}
return ErrorCode::SysCommonErr::Success;
}
从功能上与waypoint v1基本一致,事先规划航点航线,以及任务action,上传并下发指令启动执行。初始化功能有变更,
WayPointV2InitSettings
typedef struct WayPointV2InitSettings{
/**
* The Mission ID. Use to distinguish different mission
*/
uint32_t missionID;
/**
* The Mission waypoint total length, could not exceed 65535
*/
uint16_t missTotalLen;
/**
* Mission execution can be repeated more than once. A value of 0 means the mission
* only executes once, and does not repeat. A value of 1 means the mission will
* execute a total of two times.
*/
uint8_t repeatTimes;
/**
* Action the aircraft will take when the waypoint mission is complete.
*/
DJIWaypointV2MissionFinishedAction finishedAction;
/**
* While the aircraft is travelling between waypoints, you can offset its speed by
* using the throttle joystick on the remote controller. `maxFlightSpeed` is this
* offset when the joystick is pushed to maximum deflection. For example, If
* maxFlightSpeed is 10 m/s, then pushing the throttle joystick all the way up
* will add 10 m/s to the aircraft speed, while pushing down will subtract 10 m/s
* from the aircraft speed. If the remote controller stick is not at maximum
* deflection, then the offset speed will be interpolated between [0,
* `maxFlightSpeed`] with a resolution of 1000 steps. If the offset speed is
* negative, then the aircraft will fly backwards to previous waypoints. When it
* reaches the first waypoint, it will then hover in place until a positive speed
* is applied. `maxFlightSpeed` has a range of [2,15] m/s.
* unit: m/s
*/
float32_t maxFlightSpeed;
/**
* The base automatic speed of the aircraft as it moves between waypoints with
* range [-15, 15] m/s. The aircraft's actual speed is a combination of the base
* automatic speed, and the speed control given by the throttle joystick on the
* remote controller. If `autoFlightSpeed` >0: Actual speed is `autoFlightSpeed` +
* Joystick Speed (with combined max of `maxFlightSpeed`) If `autoFlightSpeed` =0:
* Actual speed is controlled only by the remote controller joystick. If
* `autoFlightSpeed` <0 and the aircraft is at the first waypoint, the aircraft
* will hover in place until the speed is made positive by the remote controller
* joystick.
* unit: m/s
*/
float32_t autoFlightSpeed;
/**
* Determines whether the mission should stop when connection between the aircraft
* and remote controller is lost. Default is `NO`.
*/
uint8_t exitMissionOnRCSignalLost;
/**
* Defines how the aircraft will go to the first waypoint from its current
* position. Default is ``DJIWaypointV2MissionV2_DJIWaypointV2MissionGotoWaypointMode_Safely``.
*/
DJIWaypointV2MissionGotoFirstWaypointMode gotoFirstWaypointMode;
std::vector<WaypointV2> mission;
}WayPointV2InitSettings;
说明一下
1、其中的速度参数:maxFlightSpeed和autoFlightSpeed,非航点中设置的巡航速度,参考注释说明,与joystick控制有关,即航点任务执行过程中支持
摇杆控制,其中autoFlightSpeed为base速度,结合摇杆打杆量来产生最终的实际运行速度,最终运行速度受maxFlightSpeed限制。
2、航点任务即最终通过此参数上传给飞控的坐标依旧是弧度值,如果传角度值会报错坐标超出范围。
指令性的API不多介绍了,主要说说action的上传,相比v1中的两个参数上传航点任务,这个还是要复杂很多,不过依旧还是只能上传已经定义好的action,不支持自定义。
先通过sample了解一下实现:
std::vector<DJIWaypointV2Action> WaypointV2MissionSample::generateWaypointActions(uint16_t actionNum)
{
std::vector<DJIWaypointV2Action> actionVector;
for(uint16_t i = 0; i < actionNum; i++)
{
DJIWaypointV2SampleReachPointTriggerParam sampleReachPointTriggerParam;
sampleReachPointTriggerParam.waypointIndex = i;
sampleReachPointTriggerParam.terminateNum = 0;
auto trigger = DJIWaypointV2Trigger(DJIWaypointV2ActionTriggerTypeSampleReachPoint,&sampleReachPointTriggerParam);
auto cameraActuatorParam = DJIWaypointV2CameraActuatorParam(DJIWaypointV2ActionActuatorCameraOperationTypeTakePhoto, nullptr);
auto actuator = DJIWaypointV2Actuator(DJIWaypointV2ActionActuatorTypeCamera, 0, &cameraActuatorParam);
auto action = DJIWaypointV2Action(i, trigger,actuator);
actionVector.push_back(action);
}
return actionVector;
}
1、总的来说,还是创建action vector,即将所有需要上传的动作打包一起上传给飞控。
2、创建action的步骤:
a) 创建触发器,即该动作什么时候触发,例sample为到达航点时触发:
auto trigger = DJIWaypointV2Trigger(DJIWaypointV2ActionTriggerTypeSampleReachPoint,&sampleReachPointTriggerParam);
顺便再看看其他触发方式:
enum DJIWaypointV2ActionTriggerType:uint8_t {
/**
* The action will be triggered when action associated executes.
* The parameters should be defined by ``DJIWaypointV2Action_DJIWaypointV2AssociateTriggerParam``.
*/
//关联触发,即将此动作关联到其他的工作上,此动作的触发将会与被关联的动作绑定,具体可以设置同时触发,也可以设置为被关联动作触发完成后再触发。
DJIWaypointV2ActionTriggerTypeActionAssociated = 2,
/**
* The action will be triggered when the aircraft flies from one waypoint to the next.
* The parameters should be defined by ``DJIWaypointV2Action_DJIWaypointV2TrajectoryTriggerParam``.
*/
//航点轨道中触发,由参数指定第几个航点到下一个航点飞行时触发。
DJIWaypointV2ActionTriggerTypeTrajectory,
/**
* The action will be triggered when the aircraft flies between two waypoints
* The parameters should be defined by ``DJIWaypointV2Action_DJIWaypointV2IntervalTriggerParam``.
*/
//类似上一个轨道触发,但是这个类型是间隔时间/距离多次触发,时间/距离由参数指定。
DJIWaypointV2ActionTriggerTypeInterval,
/**
* The action will be trigger when the aircraft reach the waypoint point.
* The parameters should be setting by ``DJIWaypointV2SampleReachPointTriggerParam``.
*/
//sample示例使用的到达航点触发。
DJIWaypointV2ActionTriggerTypeSampleReachPoint,
/**
* Unknown
*/
DJIWaypointV2ActionTriggerTypeUnknown = 0xFF
}
b)生成具体的动作,sample生成相机执行器,其中具体动作为拍照。
auto cameraActuatorParam = DJIWaypointV2CameraActuatorParam(DJIWaypointV2ActionActuatorCameraOperationTypeTakePhoto, nullptr);
auto actuator = DJIWaypointV2Actuator(DJIWaypointV2ActionActuatorTypeCamera, 0, &cameraActuatorParam);
先看DJIWaypointV2Actuator:三个枚举值,分别为相机、云台和飞机控制。
enum DJIWaypointV2ActionActuatorType:uint8_t {
/**
* The action will be executed by the camera.
* The parameters should be defined by ``DJIWaypointV2Action_DJIWaypointV2CameraActuatorParam``.
*/
DJIWaypointV2ActionActuatorTypeCamera = 1,
/**
* The action will be executed by the gimbal.
* The parameters should be defined by ``DJIWaypointV2Action_DJIWaypointV2GimbalActuatorParam``.
*/
DJIWaypointV2ActionActuatorTypeGimbal = 2,
/**
* The action will executes by control aircraft.
* The parameters should be setting by ``DJIWaypointV2Action_DJIWaypointV2CameraActuatorParam``.
*/
DJIWaypointV2ActionActuatorTypeAircraftControl = 4,
/**
* Unknown actuator type.
*/
DJIWaypointV2ActionActuatorTypeUnknown = 0xFF
};
cameraActuatorParam便为对应actuator中的操作和参数生成,比如拍照,就没有参数,如果为云台角度控制,就需要设置参数。
rotation.x = 0;
rotation.y = 20 * 10;
rotation.z = 0;
rotation.pitchCmdIgnore = 0;
rotation.yawCmdIgnore = 1;
rotation.duationTime = 50;
gimbalActuatorParam = new DJIWaypointV2GimbalActuatorParam(DJIWaypointV2ActionActuatorGimbalOperationTypeRotateGimbal, &rotation);
actuator = new DJIWaypointV2Actuator(DJIWaypointV2ActionActuatorTypeGimbal, 0, gimbalActuatorParam);
c)根据前面创建触发器和具体动作,生成action并保存至vector中等待上传
s = new DJIWaypointV2Action(action_id, *trigger,*actuator);
actionVector.push_back(*s);
sample给我们的信息就查看完了,sample就是引导我们了解SDK实现原理,此sample实现的动作与实际应用可能不匹配,咱们开发者们就可以通过原理来实现我们需要的
功能(当然功能也不是想啥都能实现,还是要基于SDK提供的功能基础上来实现)。为便于理解和应用,后面提供一个action生成的部分代码(节选自开发者代码,此代码直观简洁易懂,若有侵权,麻烦联系删除),有兴趣可以替换进demo中编译
看看啥效果。
std::vector<DJIWaypointV2Action> WaypointV2MissionSample::generateWaypointActions(uint16_t actionNum)
{
std::vector<DJIWaypointV2Action> actionVector;
#if 0
for(uint16_t i = 0; i < actionNum; i++)
{
DJIWaypointV2SampleReachPointTriggerParam sampleReachPointTriggerParam;
sampleReachPointTriggerParam.waypointIndex = i;
sampleReachPointTriggerParam.terminateNum = 0;
auto *trigger = new DJIWaypointV2Trigger(DJIWaypointV2ActionTriggerTypeSampleReachPoint,&sampleReachPointTriggerParam);
auto *cameraActuatorParam = new DJIWaypointV2CameraActuatorParam(DJIWaypointV2ActionActuatorCameraOperationTypeTakePhoto, nullptr);
auto *actuator = new DJIWaypointV2Actuator(DJIWaypointV2ActionActuatorTypeCamera, 0, cameraActuatorParam);
auto *action = new DJIWaypointV2Action(i, *trigger,*actuator);
actionVector.push_back(*action);
}
#endif
// pause when reach waypoint[1]
sampleReachPointTriggerParam.waypointIndex = 1;
sampleReachPointTriggerParam.terminateNum = 0;
trigger = new DJIWaypointV2Trigger(DJIWaypointV2ActionTriggerTypeSampleReachPoint,&sampleReachPointTriggerParam);
flyControlParam.isStartFlying = 0;
aircraftActuatorParam = new DJIWaypointV2AircraftControlParam(DJIWaypointV2ActionActuatorAircraftControlOperationTypeFlyingControl, &flyControlParam);
actuator = new DJIWaypointV2Actuator(DJIWaypointV2ActionActuatorTypeAircraftControl, 0, aircraftActuatorParam);
s = new DJIWaypointV2Action(action_id, *trigger,*actuator);
actionVector.push_back(*s);
action_id++;
delete trigger;
delete aircraftActuatorParam;
delete actuator;
delete s;
// Gimbal Yaw rotate at waypoint[1]
associateTriggerParam.actionAssociatedType = DJIWaypointV2TriggerAssociatedTimingTypeAfterFinised;
associateTriggerParam.waitingTime = 0;
associateTriggerParam.actionIdAssociated = action_id - 1;
trigger = new DJIWaypointV2Trigger(DJIWaypointV2ActionTriggerTypeActionAssociated,&associateTriggerParam);
rotation.x = 0;
rotation.y = 0;
rotation.z = -90 * 10;
rotation.pitchCmdIgnore = 1;
rotation.yawCmdIgnore = 0;
rotation.duationTime = 50;
rotation.absYawModeRef = 1;
gimbalActuatorParam = new DJIWaypointV2GimbalActuatorParam(DJIWaypointV2ActionActuatorGimbalOperationTypeRotateGimbal, &rotation);
actuator = new DJIWaypointV2Actuator(DJIWaypointV2ActionActuatorTypeGimbal, 0, gimbalActuatorParam);
s = new DJIWaypointV2Action(action_id, *trigger,*actuator);
actionVector.push_back(*s);
action_id++;
delete trigger;
delete gimbalActuatorParam;
delete actuator;
delete s;
// Gimbal Pitch rotate at waypoint[1]
associateTriggerParam.actionAssociatedType = DJIWaypointV2TriggerAssociatedTimingTypeAfterFinised;
associateTriggerParam.waitingTime = 0;
associateTriggerParam.actionIdAssociated = action_id - 1;
trigger = new DJIWaypointV2Trigger(DJIWaypointV2ActionTriggerTypeActionAssociated,&associateTriggerParam);
rotation.x = 0;
rotation.y = 20 * 10;
rotation.z = 0;
rotation.pitchCmdIgnore = 0;
rotation.yawCmdIgnore = 1;
rotation.duationTime = 50;
gimbalActuatorParam = new DJIWaypointV2GimbalActuatorParam(DJIWaypointV2ActionActuatorGimbalOperationTypeRotateGimbal, &rotation);
actuator = new DJIWaypointV2Actuator(DJIWaypointV2ActionActuatorTypeGimbal, 0, gimbalActuatorParam);
s = new DJIWaypointV2Action(action_id, *trigger,*actuator);
actionVector.push_back(*s);
action_id++;
delete trigger;
delete gimbalActuatorParam;
delete actuator;
delete s;
// take photo at waypoint[1]
associateTriggerParam.actionAssociatedType = DJIWaypointV2TriggerAssociatedTimingTypeAfterFinised;
associateTriggerParam.waitingTime = 0;
associateTriggerParam.actionIdAssociated = action_id - 1;
trigger = new DJIWaypointV2Trigger(DJIWaypointV2ActionTriggerTypeActionAssociated,&associateTriggerParam);
cameraActuatorParam = new DJIWaypointV2CameraActuatorParam(DJIWaypointV2ActionActuatorCameraOperationTypeTakePhoto, nullptr);
actuator = new DJIWaypointV2Actuator(DJIWaypointV2ActionActuatorTypeCamera, 0, cameraActuatorParam);
s = new DJIWaypointV2Action(action_id, *trigger,*actuator);
actionVector.push_back(*s);
action_id++;
delete trigger;
delete cameraActuatorParam;
delete actuator;
delete s;
// Gimbal reset at waypoint[1]
associateTriggerParam.actionAssociatedType = DJIWaypointV2TriggerAssociatedTimingTypeAfterFinised;
associateTriggerParam.waitingTime = 0;
associateTriggerParam.actionIdAssociated = action_id - 1;
trigger = new DJIWaypointV2Trigger(DJIWaypointV2ActionTriggerTypeActionAssociated,&associateTriggerParam);
rotation.x = 0;
rotation.y = 0;
rotation.z = 0;
rotation.duationTime = 100;
rotation.absYawModeRef = 0;
rotation.pitchCmdIgnore = 0;
rotation.rollCmdIgnore = 0;
rotation.yawCmdIgnore = 0;
gimbalActuatorParam = new DJIWaypointV2GimbalActuatorParam(DJIWaypointV2ActionActuatorGimbalOperationTypeRotateGimbal, &rotation);
actuator = new DJIWaypointV2Actuator(DJIWaypointV2ActionActuatorTypeGimbal, 0, gimbalActuatorParam);
s = new DJIWaypointV2Action(action_id, *trigger,*actuator);
actionVector.push_back(*s);
action_id++;
delete trigger;
delete gimbalActuatorParam;
delete actuator;
delete s;
// resume after actions at waypoint[1]
associateTriggerParam.actionAssociatedType = DJIWaypointV2TriggerAssociatedTimingTypeAfterFinised;
associateTriggerParam.waitingTime = 0;
associateTriggerParam.actionIdAssociated = action_id - 1;
trigger = new DJIWaypointV2Trigger(DJIWaypointV2ActionTriggerTypeActionAssociated,&associateTriggerParam);
flyControlParam.isStartFlying = 1;
aircraftActuatorParam = new DJIWaypointV2AircraftControlParam(DJIWaypointV2ActionActuatorAircraftControlOperationTypeFlyingControl, &flyControlParam);
actuator = new DJIWaypointV2Actuator(DJIWaypointV2ActionActuatorTypeAircraftControl, 0, aircraftActuatorParam);
s = new DJIWaypointV2Action(action_id, *trigger,*actuator);
actionVector.push_back(*s);
action_id++;
delete trigger;
delete aircraftActuatorParam;
delete actuator;
delete s;
return actionVector;
}
评论
0 条评论
请登录写评论。