紧急返航功能,策略不对,临时保存

This commit is contained in:
pxzleo 2024-01-17 22:37:25 +08:00
parent 2614dc2f59
commit 36875bcdc2
7 changed files with 3376 additions and 3140 deletions

View File

@ -163,7 +163,11 @@ namespace Plane.FormationCreator.Formation
get { return _ModifyingSingleCopterInfo; } get { return _ModifyingSingleCopterInfo; }
set { Set(nameof(ModifyingSingleCopterInfo), ref _ModifyingSingleCopterInfo, value); } set { Set(nameof(ModifyingSingleCopterInfo), ref _ModifyingSingleCopterInfo, value); }
} }
/// <summary>
/// 实际执行某一个任务--包含等待
/// </summary>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public async Task RunAsync() public async Task RunAsync()
{ {
switch (TaskType) switch (TaskType)
@ -172,8 +176,6 @@ namespace Plane.FormationCreator.Formation
await RunFlyToTaskAsync().ConfigureAwait(false); await RunFlyToTaskAsync().ConfigureAwait(false);
break; break;
case FlightTaskType.TakeOff: case FlightTaskType.TakeOff:
//多架同时起飞
//await MutilRunTakeOffTaskAsync().ConfigureAwait(false);
await NewMutilRunTakeOffTaskAsync().ConfigureAwait(false); await NewMutilRunTakeOffTaskAsync().ConfigureAwait(false);
break; break;
case FlightTaskType.Land: case FlightTaskType.Land:

View File

@ -22,6 +22,10 @@ using Plane.CommunicationManagement;
using Microsoft.Practices.ServiceLocation; using Microsoft.Practices.ServiceLocation;
using Plane.FormationCreator.ViewModels; using Plane.FormationCreator.ViewModels;
using MahApps.Metro.Controls; using MahApps.Metro.Controls;
using Newtonsoft.Json.Linq;
using GMap.NET.MapProviders;
using GMap.NET;
using static Plane.FormationCreator.CalculationLogLatDistance;
namespace Plane.FormationCreator.Formation namespace Plane.FormationCreator.Formation
{ {
@ -648,7 +652,21 @@ namespace Plane.FormationCreator.Formation
// SelectedTaskIndex = 0; // SelectedTaskIndex = 0;
} }
//模拟紧急返航
public async Task sim_DoMissionEmergencyRetAsync(PLLocation takeoffcentloc, PLLocation taskcentloc, float mindistance,int rettime, bool descending)
{
var copters = _copterManager.Copters;
if (TaskState == TasksStatus.Stop)
return;
IsEmergencyRet = true;
//设置所有模拟飞机的位置
for (int j = 0; j < copters.Count; j++)
{
var copter = copters[j];
var fc = copter as FakeCopter;
await fc.EmergencyRetAsync(takeoffcentloc, taskcentloc, mindistance, rettime, descending);
}
}
public async Task ForceNextTasks() public async Task ForceNextTasks()
{ {
@ -2199,6 +2217,15 @@ namespace Plane.FormationCreator.Formation
} }
return ret; return ret;
} }
CancellationTokenSource cts ;
//绕行取消用于3D绕行计算
public void cancel_ABypassBAsync()
{
if (cts!=null)
cts.Cancel(); //取消掉 异步执行的 绕行函数
}
//新开线程异步调用ABypassB并等待返回 //新开线程异步调用ABypassB并等待返回
public async Task<(List<List<FlightRouteV2.Vector3>>,bool)> ABypassBAsync(FlightRouteV2.Vector3[] aVecs, FlightRouteV2.Vector3[] bVecs) public async Task<(List<List<FlightRouteV2.Vector3>>,bool)> ABypassBAsync(FlightRouteV2.Vector3[] aVecs, FlightRouteV2.Vector3[] bVecs)
{ {
@ -2207,7 +2234,8 @@ namespace Plane.FormationCreator.Formation
var task = Task.Run(() => var task = Task.Run(() =>
{ {
ret = FlyVecFun.ABypassB(aVecs, bVecs, Routecallback, Cronograma, out isPasstmp); cts = new CancellationTokenSource();
ret = FlyVecFun.ABypassB(aVecs, bVecs, Routecallback, Cronograma, cts.Token, out isPasstmp);
}); });
try try
{ {
@ -2852,8 +2880,24 @@ namespace Plane.FormationCreator.Formation
Message.Show($"经纬方式计算用时:{stopWatch.Elapsed.TotalMilliseconds}ms,总飞行距离{sumlength}米,有{crosscount}个交叉"); Message.Show($"经纬方式计算用时:{stopWatch.Elapsed.TotalMilliseconds}ms,总飞行距离{sumlength}米,有{crosscount}个交叉");
} }
//计算一个图案的重心点 (三维的)
//计算中心点 (三维的) private PLLocation CenterGravityLatLng(List<PLLocation> points)
{
double aLatitude = 0;
double aLongitude = 0;
double aAlt = 0;
foreach (var item in points)
{
aLatitude += item.Latitude;
aLongitude += item.Longitude;
aAlt += item.Altitude;
}
aLatitude = aLatitude / points.Count;
aLongitude = aLongitude / points.Count;
aAlt = aAlt / points.Count;
return new PLLocation(aLatitude, aLongitude, (float)aAlt);
}
//计算两个图案的共同几何中心点 (三维的)
private PLLocation CenterLatLng(List<PLLocation> point1, List<PLLocation> point2) private PLLocation CenterLatLng(List<PLLocation> point1, List<PLLocation> point2)
{ {
PLLocation centerLatLng = new PLLocation(0,0,0); PLLocation centerLatLng = new PLLocation(0,0,0);
@ -3195,8 +3239,30 @@ namespace Plane.FormationCreator.Formation
} }
} }
private bool _IsEmergencyRet=false;
public bool IsEmergencyRet
{
get { return _IsEmergencyRet; }
private set
{
if (Set(nameof(IsEmergencyRet), ref _IsEmergencyRet, value))
{
if (_IsEmergencyRet)
{
MessageText = "任务紧急返航中!";
}
else
{
MessageText = "任务运行中";
}
}
}
}
TimeSpan timeSpan; TimeSpan timeSpan;
DateTime taskStartTime; public DateTime taskStartTime;
public async Task RunTaskAsync() public async Task RunTaskAsync()
{ {
if (Tasks.Count == 0) return; if (Tasks.Count == 0) return;
@ -3249,10 +3315,14 @@ namespace Plane.FormationCreator.Formation
} }
} }
/// <summary>
/// 开始运行模拟任务
/// </summary>
/// <returns></returns>
public async Task RunAsync() public async Task RunAsync()
{ {
IsPaused = false; IsPaused = false;
IsEmergencyRet = false;
for (int i = CurrentRunningTaskIndex; i < Tasks.Count; i++) for (int i = CurrentRunningTaskIndex; i < Tasks.Count; i++)
{ {
var task = Tasks[i]; var task = Tasks[i];
@ -3261,6 +3331,10 @@ namespace Plane.FormationCreator.Formation
} }
AppEx.Current.AppMode = AppMode.RunningTasks; AppEx.Current.AppMode = AppMode.RunningTasks;
StartAvoidingCrash(); //开始碰撞检测 StartAvoidingCrash(); //开始碰撞检测
//告诉所有飞机开始任务--模拟飞机不计算起飞延迟直接传0
foreach (var copter in _copterManager.Copters)
await copter.MissionStartAsync(0, 0, 0, 0, 0);
TaskState = TasksStatus.Running; TaskState = TasksStatus.Running;
for (int i = CurrentRunningTaskIndex; i < Tasks.Count; i++) for (int i = CurrentRunningTaskIndex; i < Tasks.Count; i++)
{ {
@ -3269,16 +3343,13 @@ namespace Plane.FormationCreator.Formation
task.Status = FlightTaskStatus.Running; task.Status = FlightTaskStatus.Running;
CurrentRunningTask = task; CurrentRunningTask = task;
CurrentRunningTaskIndex = i; CurrentRunningTaskIndex = i;
//显示提示信息
//////////////////显示提示信息
int starttime = 0; int starttime = 0;
for (int j = 0; j < task.TaskIndex; j++) for (int j = 0; j < task.TaskIndex; j++)
starttime += GetTaskTime(j); starttime += GetTaskTime(j);
TimeSpan ts = new TimeSpan(0, 0, Convert.ToInt32(starttime)); TimeSpan ts = new TimeSpan(0, 0, Convert.ToInt32(starttime));
Message.Show($"{ts}:任务{i+1} {task.TaskCnName } 开始执行,需{ GetTaskTime(task.TaskIndex)}秒"); Message.Show($"{ts}:任务{i+1} {task.TaskCnName } 开始执行,需{ GetTaskTime(task.TaskIndex)}秒");
///////////////////////// //开始执行任务
await task.RunAsync().ConfigureAwait(false); await task.RunAsync().ConfigureAwait(false);
// 1. 被暂停时,中断 RunAsync。继续运行时将把此时运行了一半的 CurrentRunningTask 重新运行一遍。 // 1. 被暂停时,中断 RunAsync。继续运行时将把此时运行了一半的 CurrentRunningTask 重新运行一遍。
if (IsPaused == true) if (IsPaused == true)
@ -3288,10 +3359,17 @@ namespace Plane.FormationCreator.Formation
Message.Show($"任务{i + 1} {task.TaskCnName } 暂停执行"); Message.Show($"任务{i + 1} {task.TaskCnName } 暂停执行");
return; return;
} }
//紧急返航中-跳出任务循环
if (IsEmergencyRet == true) break;
task.Status = FlightTaskStatus.Stop; task.Status = FlightTaskStatus.Stop;
} }
// 2. 正常结束时,重置 CurrentRunningTask、CurrentRunningTaskIndex 和 IsPaused。 //紧急返航中-等待返航结束
while (IsEmergencyRet) {
//延时10ms等待
await Task.Delay(10);
}
// 2. 正常结束时,重置 CurrentRunningTask、CurrentRunningTaskIndex 和 IsPaused。
TaskState = TasksStatus.Stop; TaskState = TasksStatus.Stop;
CurrentRunningTask = null; CurrentRunningTask = null;
CurrentRunningTaskIndex = 0; CurrentRunningTaskIndex = 0;
@ -3306,11 +3384,179 @@ namespace Plane.FormationCreator.Formation
#endregion Run and pause. #endregion Run and pause.
//计算飞行一段时间后的位置
private PLLocation TaskFlyLoc(PLLocation startloc, PLLocation tarloc,int currflytime,int flytime )
{
PLLocation flyLatLng;
if (currflytime >= flytime)
{
flyLatLng=new PLLocation(tarloc.Latitude, tarloc.Longitude, tarloc.Altitude);
return flyLatLng;
}
double _direction = startloc.CalcDirection2D(tarloc.Latitude, tarloc.Longitude);
double _Lng_delta = (float)(Math.Sin(_direction) * GeographyUtils.CalcMetersToLngSpan(tarloc.Latitude));
double _Lat_delta = (float)(Math.Cos(_direction) * GeographyUtils.METERS_TO_LAT_SPAN);
//计算xy和z方向距离
float _distance_xy = (float)startloc.CalcDistance2D(tarloc);
float _distance_z = tarloc.Altitude - startloc.Altitude;
float currdis_xy= _distance_xy/ flytime* currflytime;
float currdis_z = _distance_z / flytime * currflytime;
// 更新位置
float Altitude = startloc.Altitude + currdis_z;
double Longitude = startloc.Longitude + currdis_xy * _Lng_delta;
double Latitude = startloc.Latitude + currdis_xy * _Lat_delta;
flyLatLng = new PLLocation(Latitude, Longitude, Altitude);
return flyLatLng;
}
//计算紧急返航数据
//rettime :返航时间点--从起飞开始计算的秒数
//takeoffcentloc:起飞图案重心点
//taskcentloc:返航图案重心点
//mindistance:离起飞重心点最近飞机距离
//overlapping:两个图案是否有重叠--用来决定飞机是先降低高度还是先横着飞
//返回值:是否可以计算返航--起飞不能用这个函数,直接降落
public bool EmergencyRet(int rettime, out PLLocation takeoffcentloc, out PLLocation taskcentloc, out double mindistance, out bool overlapping)
{
mindistance = 0;
int starttime = 0;
int flyedtasktime = 0;
int rettaskindex = -1;
int taskflytime = 0;
taskcentloc = null;
overlapping = false;
double takeoffmaxlat=0;
double takeoffmaxlng = 0;
double takeoffminlat = double.MaxValue;
double takeoffminlng = double.MaxValue;
double taskmaxlat = 0;
double taskmaxlng = 0;
double taskminlat = double.MaxValue;
double taskminlng = double.MaxValue;
Dictionary<int, PLLocation> curTaskPoint = new Dictionary<int, PLLocation>();
//计算地面起飞矩阵的中心点
for (int i = 0; i < _copterManager.Copters.Count; i++)
{
//起飞任务
var curinfo = Tasks[0].SingleCopterInfos[i];
PLLocation curLoc = new PLLocation(curinfo.TargetLat, curinfo.TargetLng,0);
if (curinfo.TargetLat > takeoffmaxlat)
takeoffmaxlat = curinfo.TargetLat;
if (curinfo.TargetLng > takeoffmaxlng)
takeoffmaxlng = curinfo.TargetLng;
if (curinfo.TargetLat < takeoffminlat)
takeoffminlat = curinfo.TargetLat;
if (curinfo.TargetLng < takeoffminlng)
takeoffminlng = curinfo.TargetLng;
curTaskPoint.Add(i, curLoc);
}
takeoffcentloc = CenterGravityLatLng(curTaskPoint.Values.ToList());
curTaskPoint.Clear();
//计算返航时间正在飞行哪个航点,飞了多久
for (int i = 0; i < Tasks.Count; i++)
{
flyedtasktime= GetTaskTime(i);
if ((starttime+ flyedtasktime) > rettime)
{
rettaskindex = i;
taskflytime = rettime - starttime;
}
starttime += flyedtasktime;
}
//起飞不能用这个函数,直接降落
if (rettaskindex<1) return false;
mindistance = double.MaxValue;
//计算悬停图案的重心点
for (int i = 0; i < _copterManager.Copters.Count; i++)
{
var curinfo = Tasks[rettaskindex].SingleCopterInfos[i];
var prvcurinfo = Tasks[rettaskindex - 1].SingleCopterInfos[i];
PLLocation curLoc;
if (taskflytime < Tasks[rettaskindex].FlytoTime)
{
PLLocation coptercurLoc = new PLLocation(curinfo.TargetLat, curinfo.TargetLng, curinfo.TargetAlt);
PLLocation copterprvLoc = new PLLocation(prvcurinfo.TargetLat, prvcurinfo.TargetLng, prvcurinfo.TargetAlt);
//计算飞行一段时间后的位置
curLoc = TaskFlyLoc(copterprvLoc, coptercurLoc, taskflytime, Tasks[rettaskindex].FlytoTime);
}
else //正在悬停
curLoc = new PLLocation(curinfo.TargetLat, curinfo.TargetLng, 0);
curTaskPoint.Add(i, curLoc);
if (curinfo.TargetLat > taskmaxlat)
taskmaxlat = curinfo.TargetLat;
if (curinfo.TargetLng > taskmaxlng)
taskmaxlng = curinfo.TargetLng;
if (curinfo.TargetLat < taskminlat)
taskminlat = curinfo.TargetLat;
if (curinfo.TargetLng < taskminlng)
taskminlng = curinfo.TargetLng;
double taskdistance = takeoffcentloc.CalcDistance(curLoc);
if (taskdistance < mindistance)
mindistance = taskdistance;
}
taskcentloc = CenterGravityLatLng(curTaskPoint.Values.ToList());
curTaskPoint.Clear();
//判断两个图案是否有重叠
overlapping = DoRectanglesOverlap(takeoffminlat, takeoffminlng, takeoffmaxlat, takeoffmaxlng,
taskminlat, taskminlng, taskmaxlat, taskmaxlng);
return true;
}
/// <summary>
/// 判断两个矩形是否有重叠
/// </summary>
/// <param name="minLat1"></param>
/// <param name="minLng1"></param>
/// <param name="maxLat1"></param>
/// <param name="maxLng1"></param>
/// <param name="minLat2"></param>
/// <param name="minLng2"></param>
/// <param name="maxLat2"></param>
/// <param name="maxLng2"></param>
/// <returns></returns>
static bool DoRectanglesOverlap(double minLat1, double minLng1, double maxLat1, double maxLng1,
double minLat2, double minLng2, double maxLat2, double maxLng2)
{
// 判断第一个矩形在第二个矩形的左边或右边
if (minLng1 > maxLng2 || minLng2 > maxLng1)
{
return false;
}
// 判断第一个矩形在第二个矩形的上边或下边
if (minLat1 > maxLat2 || minLat2 > maxLat1)
{
return false;
}
return true;
}
Dictionary<int, string> AvoidCrashLog = new Dictionary<int, string >(); Dictionary<int, string> AvoidCrashLog = new Dictionary<int, string >();
private async void StartAvoidingCrash() private async void StartAvoidingCrash()
{ {

View File

@ -1,13 +1,13 @@
public enum FlightTaskStatus public enum FlightTaskStatus
{ {
Stop, Stop,
Running, Running,
Paused, Paused,
Selected Selected
} }
public enum TasksStatus public enum TasksStatus
{ {
Stop, Stop,
Running, Running,
Paused Paused
} }

View File

@ -1,262 +1,212 @@
using Plane.Copters; using Plane.Copters;
using Plane.Geography; using Plane.Geography;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Plane.Windows.Messages; using Plane.Windows.Messages;
namespace Plane.FormationCreator.Formation namespace Plane.FormationCreator.Formation
{ {
public partial class FlightTask public partial class FlightTask
{ {
private bool _StaggerRoutes = true; private bool _StaggerRoutes = true;
//是否有交错 //是否有交错
public bool StaggerRoutes public bool StaggerRoutes
{ {
get { return _StaggerRoutes; } get { return _StaggerRoutes; }
set { Set(nameof(StaggerRoutes), ref _StaggerRoutes, value); } set { Set(nameof(StaggerRoutes), ref _StaggerRoutes, value); }
} }
//同一个任务每一架飞机的FlytoTime和LoiterTime保持统一 //同一个任务每一架飞机的FlytoTime和LoiterTime保持统一
private int _FlytoTime = 10; private int _FlytoTime = 10;
public int FlytoTime public int FlytoTime
{ {
get { return _FlytoTime; } get { return _FlytoTime; }
set set
{ {
if (value > 4095) value = 4095; if (value > 4095) value = 4095;
if (value < 0) value = 0; if (value < 0) value = 0;
Set(nameof(FlytoTime), ref _FlytoTime, value); Set(nameof(FlytoTime), ref _FlytoTime, value);
} }
} }
private int _LoiterTime = 1; private int _LoiterTime = 1;
public int LoiterTime public int LoiterTime
{ {
get { return _LoiterTime; } get { return _LoiterTime; }
set set
{ {
if (value > 4095) value = 4095; if (value > 4095) value = 4095;
if (value < 0) value = 0; if (value < 0) value = 0;
Set(nameof(LoiterTime), ref _LoiterTime, value); Set(nameof(LoiterTime), ref _LoiterTime, value);
} }
} }
private bool _VerticalLift = false; private bool _VerticalLift = false;
public bool VerticalLift // 垂直升降标志位,后面需要加入即使拖动地图上的飞机,也不会变化经纬度. added by ZJF public bool VerticalLift // 垂直升降标志位,后面需要加入即使拖动地图上的飞机,也不会变化经纬度. added by ZJF
{ {
get { return _VerticalLift; } get { return _VerticalLift; }
set set
{ {
if (value) if (value)
{ {
int currentIndex = _flightTaskManager.SelectedTaskIndex; int currentIndex = _flightTaskManager.SelectedTaskIndex;
var currentCopterInfos = _flightTaskManager.SelectedTask.SingleCopterInfos; var currentCopterInfos = _flightTaskManager.SelectedTask.SingleCopterInfos;
var previousCopterInfos = _flightTaskManager.Tasks[currentIndex - 1].SingleCopterInfos; var previousCopterInfos = _flightTaskManager.Tasks[currentIndex - 1].SingleCopterInfos;
for (int i = 0; i < currentCopterInfos.Count; i++) for (int i = 0; i < currentCopterInfos.Count; i++)
{ {
currentCopterInfos[i].TargetLat = previousCopterInfos[i].TargetLat; currentCopterInfos[i].TargetLat = previousCopterInfos[i].TargetLat;
currentCopterInfos[i].TargetLng = previousCopterInfos[i].TargetLng; currentCopterInfos[i].TargetLng = previousCopterInfos[i].TargetLng;
currentCopterInfos[i].TargetAlt = previousCopterInfos[i].TargetAlt; currentCopterInfos[i].TargetAlt = previousCopterInfos[i].TargetAlt;
} }
} }
Set(nameof(VerticalLift), ref _VerticalLift, value); Set(nameof(VerticalLift), ref _VerticalLift, value);
} }
} }
public async Task RunFlyToTaskAsync() // 全部飞到指定航点 public async Task RunFlyToTaskAsync() // 全部飞到指定航点
{ {
//是否有交错 //是否有交错
if (StaggerRoutes) if (StaggerRoutes)
{ {
var infos = SingleCopterInfos; var infos = SingleCopterInfos;
var tasks = new Task[infos.Count]; var tasks = new Task[infos.Count];
for (int i = 0; i < infos.Count; i++) for (int i = 0; i < infos.Count; i++)
{ {
var info = infos[i]; var info = infos[i];
//为每架飞机创建一个航点任务
tasks[i] = await Task.Factory.StartNew(async () => tasks[i] = await Task.Factory.StartNew(async () =>
{ {
var internalInfo = info; var internalInfo = info;
//if (i1 > 0) await FlyToTaskFlySingleCopterAsync(internalInfo);
//{ });
// var prevCopter = infos[i1 - 1].Copter; }
// while (CheckCrossing(infos, i1) && await Task.WhenAll(tasks).ConfigureAwait(false);
// prevCopter.Altitude - copter.Altitude < 2)
// { }
// await Task.Delay(25).ConfigureAwait(false); else
// } {
//} await Task.WhenAll(
SingleCopterInfos.Select(info => FlyToTaskFlySingleCopterAsync(info))
await FlyToTaskFlySingleCopterAsync(internalInfo); ).ConfigureAwait(false);
}); }
} }
await Task.WhenAll(tasks).ConfigureAwait(false);
} // private int RuningTaskRemaining = 0;
else /// <summary>
{ /// 单独飞机执行飞行任务
await Task.WhenAll( /// </summary>
SingleCopterInfos.Select(info => FlyToTaskFlySingleCopterAsync(info)) /// <param name="info"></param>
).ConfigureAwait(false); /// <returns></returns>
} private async Task FlyToTaskFlySingleCopterAsync(FlightTaskSingleCopterInfo info)
} {
DateTime dtNow = DateTime.Now;
DateTime dtLastTime = DateTime.Now;
// private int RuningTaskRemaining = 0; TimeSpan ts = dtNow - dtLastTime;
private async Task FlyToTaskFlySingleCopterAsync(FlightTaskSingleCopterInfo info)
{ FlightTask task = _flightTaskManager.CurrentRunningTask;
DateTime dtNow = DateTime.Now; int flyToTime = task.FlytoTime * 1000;
DateTime dtLastTime = DateTime.Now; int loiterTime = task.LoiterTime * 1000;
TimeSpan ts = dtNow - dtLastTime; int taskIndex = _flightTaskManager.CurrentRunningTaskIndex;
int copterIndex = SingleCopterInfos.IndexOf(info);
FlightTask task = _flightTaskManager.CurrentRunningTask;
int flyToTime = task.FlytoTime * 1000; // 当该飞机被标记时,悬停并跳过飞行任务
int loiterTime = task.LoiterTime * 1000; if ((bool)_copterManager.CopterStatus[copterIndex])
int taskIndex = _flightTaskManager.CurrentRunningTaskIndex; {
int copterIndex = SingleCopterInfos.IndexOf(info); await info.Copter.HoverAsync();
return;
}
// 当该飞机被标记时,悬停并跳过飞行任务
if ((bool)_copterManager.CopterStatus[copterIndex]) await info.Copter.SetShowLEDAsync(info.FlytoShowLED);
{
await info.Copter.HoverAsync(); if (info.Copter.State != Plane.Copters.CopterState.CommandMode)
return; await info.Copter.GuidAsync();
}
await info.Copter.SetShowLEDAsync(info.FlytoShowLED); double targetLat = info.TargetLat;
double targetLng = info.TargetLng;
if (info.Copter.State != Plane.Copters.CopterState.CommandMode) if (info.IsLandWaypoint)
await info.Copter.GuidAsync(); {
targetLat = info.Copter.TakeOffPoint.Latitude;
targetLng = info.Copter.TakeOffPoint.Longitude;
double targetLat = info.TargetLat; }
double targetLng = info.TargetLng; int flytype = _flightTaskManager.getflytype(taskIndex);
if (info.IsLandWaypoint) //指定目标位置
{ await info.Copter.FlyToAsync(targetLat, targetLng, info.TargetAlt, task.FlytoTime, flytype);
targetLat = info.Copter.TakeOffPoint.Latitude; dtNow = DateTime.Now;
targetLng = info.Copter.TakeOffPoint.Longitude; ts = dtNow - dtLastTime;
} //等待时间到达,并执行灯光模拟--不移动飞机,移动飞机是飞机自己计算的
int flytype = _flightTaskManager.getflytype(taskIndex); while (ts.TotalMilliseconds < (flyToTime + loiterTime)) //按时间轴飞:当前任务时间到达后自动飞往下个航点
await info.Copter.FlyToAsync(targetLat, targetLng, info.TargetAlt, task.FlytoTime, flytype); {
// await Task.Delay(10).ConfigureAwait(false); if (_flightTaskManager.IsPaused == true)
{
dtNow = DateTime.Now; await info.Copter.HoverAsync();
ts = dtNow - dtLastTime; return;
}
// int sendFlyToTimes = 0; await Task.Delay(100).ConfigureAwait(false); //判断是否到达位置10hz
//执行灯光模拟
/* if (info.LEDInfos.Count > 0)
//第0个任务为takeoff {
if (taskIndex > 0) string LEDRGB = "";
{ List<LEDInfo> LedControl = info.LEDInfos.ToList();
FlightTask prevTask = _flightTaskManager.Tasks[taskIndex - 1]; double time = 0;
if (prevTask.TaskType == FlightTaskType.FlyTo && prevTask.LoiterTime == 0) for (int i = 0; i < LedControl.Count; i++)
flyToTime += prevTask.RuningTaskRemaining; {
}
*/ var led = LedControl[i];
time += led.Delay * 1000;
//while (!info.Copter.ArrivedTarget(info.TargetLat, info.TargetLng, info.TargetAlt)) //按航点飞 所有Copter到达目标点开始飞下个航点 if (ts.TotalMilliseconds >= time)
while (ts.TotalMilliseconds < (flyToTime + loiterTime)) //按时间轴飞:当前任务时间到达后自动飞往下个航点 LEDRGB = info.LEDInfos[i].LEDRGB;
{ else
/* break;
//悬停时间等于0为快速航点 到达之后立即出发下个航点 切时间累积 }
if (loiterTime == 0 && info.Copter.LEDColor = LEDRGB;
info.Copter.ArrivedTarget(info.TargetLat, info.TargetLng, info.TargetAlt)) }
{ // 当该飞机被标记时,悬停并跳过飞行任务
task.RuningTaskRemaining = flyToTime - (int)ts.TotalMilliseconds; if ((bool)_copterManager.CopterStatus[copterIndex])
break; {
} await info.Copter.HoverAsync();
*/ return;
if (_flightTaskManager.IsPaused == true) }
{ dtNow = DateTime.Now;
await info.Copter.HoverAsync(); ts = dtNow - dtLastTime;
return; }
} // await info.Copter.HoverAsync();
await Task.Delay(100).ConfigureAwait(false); //判断是否到达位置10hz if (taskIndex == _flightTaskManager.Tasks.Count() - 1)
{
await info.Copter.HoverAsync();
}
// if (info.LEDInfos.Count > 0) }
// {
// string LEDRGB = "";
// List<LEDInfo> LedControl = info.LEDInfos.OrderBy(i=>i.Delay).ToList(); private static bool CheckCrossing(List<FlightTaskSingleCopterInfo> infos, int currentIndex)
// for (int i = 0; i < LedControl.Count; i++) {
// { var info = infos[currentIndex];
// var led = LedControl[i]; for (int i = 0; i < currentIndex; i++)
// if (ts.TotalMilliseconds >= led.Delay * 1000) {
// LEDRGB = info.LEDInfos[i].LEDRGB; var nextInfo = infos[i];
// else if (GeographyUtils.CheckCrossing2D(info.Copter.Latitude, info.Copter.Longitude, info.TargetLat, info.TargetLng,
// break; nextInfo.Copter.Latitude, nextInfo.Copter.Longitude, nextInfo.TargetLat, nextInfo.TargetLng))
// } {
// info.Copter.LEDColor = LEDRGB; return true;
// }
// } }
return false;
if (info.LEDInfos.Count > 0) }
{ }
string LEDRGB = ""; }
List<LEDInfo> LedControl = info.LEDInfos.ToList();
double time = 0;
for (int i = 0; i < LedControl.Count; i++)
{
var led = LedControl[i];
time += led.Delay * 1000;
if (ts.TotalMilliseconds >= time)
LEDRGB = info.LEDInfos[i].LEDRGB;
else
break;
}
info.Copter.LEDColor = LEDRGB;
}
// 当该飞机被标记时,悬停并跳过飞行任务
if ((bool)_copterManager.CopterStatus[copterIndex])
{
await info.Copter.HoverAsync();
return;
}
dtNow = DateTime.Now;
ts = dtNow - dtLastTime;
}
// await info.Copter.HoverAsync();
if (taskIndex == _flightTaskManager.Tasks.Count() - 1)
{
await info.Copter.HoverAsync();
}
}
private static bool CheckCrossing(List<FlightTaskSingleCopterInfo> infos, int currentIndex)
{
var info = infos[currentIndex];
for (int i = 0; i < currentIndex; i++)
{
var nextInfo = infos[i];
if (GeographyUtils.CheckCrossing2D(info.Copter.Latitude, info.Copter.Longitude, info.TargetLat, info.TargetLng,
nextInfo.Copter.Latitude, nextInfo.Copter.Longitude, nextInfo.TargetLat, nextInfo.TargetLng))
{
return true;
}
}
return false;
}
}
}

View File

@ -1,487 +1,486 @@
using Plane.Copters; using Plane.Copters;
using Microsoft.Practices.ServiceLocation; using Microsoft.Practices.ServiceLocation;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Plane.Geography; using Plane.Geography;
namespace Plane.FormationCreator.Formation namespace Plane.FormationCreator.Formation
{ {
public partial class FlightTask public partial class FlightTask
{ {
//起飞到第一个航点高度的飞行时间 //起飞到第一个航点高度的飞行时间
private byte _TakeOffTime = 10; private byte _TakeOffTime = 10;
public byte TakeOffTime public byte TakeOffTime
{ {
get { return _TakeOffTime; } get { return _TakeOffTime; }
set { Set(nameof(TakeOffTime), ref _TakeOffTime, value); } set { Set(nameof(TakeOffTime), ref _TakeOffTime, value); }
} }
//一架架起飞--未使用 //一架架起飞--未使用
public async Task RunTakeOffTaskAsync() public async Task RunTakeOffTaskAsync()
{ {
// float takeOffAlt = 15; // float takeOffAlt = 15;
int TaskCount = _flightTaskManager.Tasks.Count(); int TaskCount = _flightTaskManager.Tasks.Count();
if (TaskCount > 1) if (TaskCount > 1)
{ {
var infos = SingleCopterInfos; var infos = SingleCopterInfos;
// var tasks = new Task[infos.Count]; // var tasks = new Task[infos.Count];
var tasksTmp = new Task[infos.Count]; var tasksTmp = new Task[infos.Count];
for (int i = 0; i < infos.Count; i++) for (int i = 0; i < infos.Count; i++)
{ {
var info = infos[i]; var info = infos[i];
if (info.takeOffStage == 0) // 第一阶段起飞到10m if (info.takeOffStage == 0) // 第一阶段起飞到10m
{ {
await TakeOffTaskFlySingleCopterAsync(info); await TakeOffTaskFlySingleCopterAsync(info);
//if (_flightTaskManager.IsPaused == false) //if (_flightTaskManager.IsPaused == false)
//{ //{
// info.takeOffStage++; // info.takeOffStage++;
//} //}
} }
tasksTmp[i] = TakeOffSecondTaskAsync(info); // 第二和第三阶段 tasksTmp[i] = TakeOffSecondTaskAsync(info); // 第二和第三阶段
} }
await Task.WhenAll(tasksTmp).ConfigureAwait(false); await Task.WhenAll(tasksTmp).ConfigureAwait(false);
if (_flightTaskManager.IsPaused == false) if (_flightTaskManager.IsPaused == false)
{ {
for (int i = 0; i < infos.Count; i++) for (int i = 0; i < infos.Count; i++)
{ {
var info = infos[i]; var info = infos[i];
info.takeOffStage = 0; info.takeOffStage = 0;
} }
} }
} }
} }
//新版的起飞方案 //新版的起飞方案
public async Task NewMutilRunTakeOffTaskAsync() public async Task NewMutilRunTakeOffTaskAsync()
{ {
var infos = SingleCopterInfos; var infos = SingleCopterInfos;
var tasksTakeOff = new Task[infos.Count]; var tasksTakeOff = new Task[infos.Count];
for (int i = 0; i < infos.Count; i++) for (int i = 0; i < infos.Count; i++)
{ {
//tasksTakeOff[i] = NewSingleRunTaskOffTaskAsunc(infos[i]); tasksTakeOff[i] = await Task.Factory.StartNew(async () =>
{
var internalInfo = infos[i];
tasksTakeOff[i] = await Task.Factory.StartNew(async () => await NewSingleRunTaskOffTaskAsunc(internalInfo);
{ });
var internalInfo = infos[i]; }
await Task.WhenAll(tasksTakeOff).ConfigureAwait(false);
await NewSingleRunTaskOffTaskAsunc(internalInfo); }
});
} /// <summary>
await Task.WhenAll(tasksTakeOff).ConfigureAwait(false); /// 单独飞机 执行起飞任务
//await Task.Delay(100); /// </summary>
} /// <param name="info"></param>
/// <returns></returns>
private async Task NewSingleRunTaskOffTaskAsunc(FlightTaskSingleCopterInfo info) private async Task NewSingleRunTaskOffTaskAsunc(FlightTaskSingleCopterInfo info)
{ {
DateTime dtNow = DateTime.Now; DateTime dtNow = DateTime.Now;
DateTime dtLastTime = DateTime.Now; DateTime dtLastTime = DateTime.Now;
TimeSpan ts = dtNow - dtLastTime; TimeSpan ts = dtNow - dtLastTime;
int copterIndex = SingleCopterInfos.IndexOf(info); int copterIndex = SingleCopterInfos.IndexOf(info);
var copter = info.Copter; var copter = info.Copter;
await copter.UnlockAsync(); await copter.UnlockAsync();
//等待起飞时间 //等待起飞时间
while ((int)ts.TotalMilliseconds < (int)info.TakeOffWaitTime * 1000) while ((int)ts.TotalMilliseconds < (int)info.TakeOffWaitTime * 1000)
{ {
if (_flightTaskManager.IsPaused == true) if (_flightTaskManager.IsPaused == true)
{ {
await copter.UnlockAsync(); await copter.UnlockAsync();
await info.Copter.HoverAsync(); await info.Copter.HoverAsync();
return; return;
} }
await Task.Delay(100); await Task.Delay(100);
dtNow = DateTime.Now; dtNow = DateTime.Now;
ts = dtNow - dtLastTime; ts = dtNow - dtLastTime;
} }
//虚拟飞机5秒后不起飞会自动上锁 //虚拟飞机5秒后不起飞会自动上锁
await copter.UnlockAsync(); await copter.UnlockAsync();
await copter.TakeOffAsync(); await copter.TakeOffAsync();
var copterNextTask = _flightTaskManager.Tasks[TaskIndex + 1].SingleCopterInfos[copterIndex]; var copterNextTask = _flightTaskManager.Tasks[TaskIndex + 1].SingleCopterInfos[copterIndex];
float takeOffAlt = copterNextTask.TargetAlt; float takeOffAlt = copterNextTask.TargetAlt;
info.TargetLat = info.Copter.Latitude; info.TargetLat = info.Copter.Latitude;
info.TargetLng = info.Copter.Longitude; info.TargetLng = info.Copter.Longitude;
//info.Copter.takeOffTargetAltitude = takeOffAlt; //info.Copter.takeOffTargetAltitude = takeOffAlt;
FlightTask task = _flightTaskManager.CurrentRunningTask; FlightTask task = _flightTaskManager.CurrentRunningTask;
float takeflytime = task.TakeOffTime - info.TakeOffWaitTime; float takeflytime = task.TakeOffTime - info.TakeOffWaitTime;
//开始往上飞 //飞行目标,开始往上飞
await info.Copter.FlyToAsync(info.TargetLat, info.TargetLng, takeOffAlt, takeflytime, 1); //秒 await info.Copter.FlyToAsync(info.TargetLat, info.TargetLng, takeOffAlt, takeflytime, 1); //秒
//解锁起飞用暗紫色 //解锁起飞用暗紫色
info.Copter.LEDColor = CopterManager.CopterTakeoffColor; info.Copter.LEDColor = CopterManager.CopterTakeoffColor;
dtNow = DateTime.Now; dtNow = DateTime.Now;
ts = dtNow - dtLastTime; ts = dtNow - dtLastTime;
//等待起飞时间完成,并模拟灯光--不移动飞机-飞机自己计算并移动位置
while (ts.TotalMilliseconds < task.TakeOffTime * 1000) while (ts.TotalMilliseconds < task.TakeOffTime * 1000)
{ {
if (_flightTaskManager.IsPaused == true) if (_flightTaskManager.IsPaused == true)
{ {
await info.Copter.HoverAsync(); await info.Copter.HoverAsync();
return; return;
} }
await Task.Delay(100).ConfigureAwait(false); await Task.Delay(100).ConfigureAwait(false);
dtNow = DateTime.Now; dtNow = DateTime.Now;
ts = dtNow - dtLastTime; ts = dtNow - dtLastTime;
//灯光控制 //灯光控制
if (info.LEDInfos.Count > 0) if (info.LEDInfos.Count > 0)
{ {
string LEDRGB = ""; string LEDRGB = "";
List<LEDInfo> LedControl = info.LEDInfos.ToList(); List<LEDInfo> LedControl = info.LEDInfos.ToList();
double time = 0; double time = 0;
for (int i = 0; i < LedControl.Count; i++) for (int i = 0; i < LedControl.Count; i++)
{ {
var led = LedControl[i]; var led = LedControl[i];
time += led.Delay * 1000; time += led.Delay * 1000;
if (ts.TotalMilliseconds >= time) if (ts.TotalMilliseconds >= time)
LEDRGB = info.LEDInfos[i].LEDRGB; LEDRGB = info.LEDInfos[i].LEDRGB;
else else
break; break;
} }
info.Copter.LEDColor = LEDRGB; info.Copter.LEDColor = LEDRGB;
///灯光控制结束 ///灯光控制结束
} }
} }
//起飞完成用默认颜色 //起飞完成用默认颜色
info.Copter.LEDColor = CopterManager.CopterFlyingColor; info.Copter.LEDColor = CopterManager.CopterFlyingColor;
}
}
//老方案 ----- 按起飞数量起飞
//老方案 ----- 按起飞数量起飞 // 几架飞机同时起飞参数为takeOffCount-----------------使用中
// 几架飞机同时起飞参数为takeOffCount-----------------使用中 //起飞分三个阶段:
//起飞分三个阶段: //1阶段分批起飞到15米(目前15米高度是飞控起飞航点决定)上一批起飞超过5米下一批开始起飞
//1阶段分批起飞到15米(目前15米高度是飞控起飞航点决定)上一批起飞超过5米下一批开始起飞 // 等待全部起飞完成后执行第二阶段,
// 等待全部起飞完成后执行第二阶段, //2阶段等待高度超过9米(可能已到达15米)然后平飞到第一个航点位置,高度为15米的位置
//2阶段等待高度超过9米(可能已到达15米)然后平飞到第一个航点位置,高度为15米的位置 //3阶段垂直上升到第一个航点指定高度
//3阶段垂直上升到第一个航点指定高度 //
// //修改方案:针对高度
//修改方案:针对高度 //1.上升到起飞高度(目前没有地面站设置高度,高度在飞控中)
//1.上升到起飞高度(目前没有地面站设置高度,高度在飞控中) //2.直接飞往第一个航点的高度
//2.直接飞往第一个航点的高度 public async Task MutilRunTakeOffTaskAsync()
public async Task MutilRunTakeOffTaskAsync() {
{
int TaskCount = _flightTaskManager.Tasks.Count();
int TaskCount = _flightTaskManager.Tasks.Count(); if (TaskCount > 1)
if (TaskCount > 1) {
{ var infos = SingleCopterInfos;
var infos = SingleCopterInfos;
//不再使用起飞数量 强制设置起飞总数等于所有飞机
//不再使用起飞数量 强制设置起飞总数等于所有飞机 int takeOffCount = _copterManager.Copters.Count();
int takeOffCount = _copterManager.Copters.Count(); int copterCount = infos.Count;
int copterCount = infos.Count; int integerPart = copterCount / takeOffCount;
int integerPart = copterCount / takeOffCount; int residualPart = copterCount % takeOffCount;
int residualPart = copterCount % takeOffCount;
// var tasks = new Task[infos.Count];
// var tasks = new Task[infos.Count]; var tasksTmp = new Task[infos.Count];
var tasksTmp = new Task[infos.Count]; for (int i = 0; i < integerPart; i++)
for (int i = 0; i < integerPart; i++) {
{ var tasksTakeOff = new Task[takeOffCount];
var tasksTakeOff = new Task[takeOffCount]; //执行n架同时起飞
//执行n架同时起飞 for (int j = takeOffCount * i; j < takeOffCount * (i + 1); j++)
for (int j = takeOffCount * i; j < takeOffCount * (i + 1); j++) {
{ var info = infos[j];
var info = infos[j];
int indexTmp = j - takeOffCount * i;
int indexTmp = j - takeOffCount * i; if (info.takeOffStage == 0) // 第一阶段起飞到15m
if (info.takeOffStage == 0) // 第一阶段起飞到15m {
{ tasksTakeOff[indexTmp] = TakeOffTaskFlySingleCopterAsync(info);
tasksTakeOff[indexTmp] = TakeOffTaskFlySingleCopterAsync(info); }
} else
else {
{ tasksTakeOff[indexTmp] = Task.Run(async () => { await Task.Delay(1).ConfigureAwait(false); });
tasksTakeOff[indexTmp] = Task.Run(async () => { await Task.Delay(1).ConfigureAwait(false); }); }
} }
} //等待多架起飞任务-起飞高度超过5米完成
//等待多架起飞任务-起飞高度超过5米完成 await Task.WhenAll(tasksTakeOff).ConfigureAwait(false);
await Task.WhenAll(tasksTakeOff).ConfigureAwait(false); //加入已起飞飞机的第二第三阶段起飞任务--并不执行
//加入已起飞飞机的第二第三阶段起飞任务--并不执行 for (int j = takeOffCount * i; j < takeOffCount * (i + 1); j++)
for (int j = takeOffCount * i; j < takeOffCount * (i + 1); j++) {
{ var info = infos[j];
var info = infos[j]; tasksTmp[j] = TakeOffSecondTaskAsync(info); // 第二和第三阶段
tasksTmp[j] = TakeOffSecondTaskAsync(info); // 第二和第三阶段 }
} }
}
// 余数架飞机同时起飞
// 余数架飞机同时起飞 if (residualPart > 0)
if (residualPart > 0) {
{ var tasksTakeOff = new Task[residualPart];
var tasksTakeOff = new Task[residualPart]; for (int j = integerPart * takeOffCount; j < takeOffCount * integerPart + residualPart; j++)
for (int j = integerPart * takeOffCount; j < takeOffCount * integerPart + residualPart; j++) {
{ var info = infos[j];
var info = infos[j];
int indexTmp = j - takeOffCount * integerPart;
int indexTmp = j - takeOffCount * integerPart; if (info.takeOffStage == 0) // 第一阶段起飞到15m
if (info.takeOffStage == 0) // 第一阶段起飞到15m {
{ tasksTakeOff[indexTmp] = TakeOffTaskFlySingleCopterAsync(info);
tasksTakeOff[indexTmp] = TakeOffTaskFlySingleCopterAsync(info); }
} else
else {
{ tasksTakeOff[indexTmp] = Task.Run(async () => { await Task.Delay(1).ConfigureAwait(false); });
tasksTakeOff[indexTmp] = Task.Run(async () => { await Task.Delay(1).ConfigureAwait(false); }); }
} }
} //等待起飞超过5米
//等待起飞超过5米 await Task.WhenAll(tasksTakeOff).ConfigureAwait(false);
await Task.WhenAll(tasksTakeOff).ConfigureAwait(false);
for (int j = integerPart * takeOffCount; j < takeOffCount * integerPart + residualPart; j++)
for (int j = integerPart * takeOffCount; j < takeOffCount * integerPart + residualPart; j++) {
{ var info = infos[j];
var info = infos[j]; tasksTmp[j] = TakeOffSecondTaskAsync(info); // 加入第二和第三阶段
tasksTmp[j] = TakeOffSecondTaskAsync(info); // 加入第二和第三阶段 }
} }
} //执行并等待所有的第二第三阶段起飞任务完成
//执行并等待所有的第二第三阶段起飞任务完成 await Task.WhenAll(tasksTmp).ConfigureAwait(false);
await Task.WhenAll(tasksTmp).ConfigureAwait(false); if (_flightTaskManager.IsPaused == false)
if (_flightTaskManager.IsPaused == false) {
{ for (int i = 0; i < infos.Count; i++)
for (int i = 0; i < infos.Count; i++) {
{ var info = infos[i];
var info = infos[i]; info.takeOffStage = 0;
info.takeOffStage = 0; }
} }
}
}
} }
}
private CopterManager _copterManager = ServiceLocator.Current.GetInstance<CopterManager>();
private CopterManager _copterManager = ServiceLocator.Current.GetInstance<CopterManager>();
//执行第一阶段解锁起飞任务---使用中
//执行第一阶段解锁起飞任务---使用中 private async Task TakeOffTaskFlySingleCopterAsync(FlightTaskSingleCopterInfo info)
private async Task TakeOffTaskFlySingleCopterAsync(FlightTaskSingleCopterInfo info) {
{ DateTime dtNow = DateTime.Now;
DateTime dtNow = DateTime.Now; DateTime dtLastTime = DateTime.Now;
DateTime dtLastTime = DateTime.Now; TimeSpan ts = dtNow - dtLastTime;
TimeSpan ts = dtNow - dtLastTime;
int copterIndex = SingleCopterInfos.IndexOf(info);
int copterIndex = SingleCopterInfos.IndexOf(info); var copter = info.Copter;
var copter = info.Copter; var copterNextTask = _flightTaskManager.Tasks[1].SingleCopterInfos[copterIndex];
var copterNextTask = _flightTaskManager.Tasks[1].SingleCopterInfos[copterIndex];
if ((bool)_copterManager.CopterStatus[copterIndex])
if ((bool)_copterManager.CopterStatus[copterIndex]) return;
return;
if (_flightTaskManager.IsPaused == true)
if (_flightTaskManager.IsPaused == true) {
{ return;
return; }
}
//设置灯光
//设置灯光 await copter.SetShowLEDAsync(true);
await copter.SetShowLEDAsync(true);
//开始解锁
//开始解锁 await copter.UnlockAsync();
await copter.UnlockAsync(); for (int i = 0; !copter.IsUnlocked; i++)
for (int i = 0; !copter.IsUnlocked; i++) {
{ //if (_flightTaskManager.IsPaused == true)
//if (_flightTaskManager.IsPaused == true) //{
//{ // return;
// return; //}
//} //8秒内每1000毫秒尝试解锁一次
//8秒内每1000毫秒尝试解锁一次 //解锁间隔一定要超过1s否则导致飞控以后无法解锁
//解锁间隔一定要超过1s否则导致飞控以后无法解锁
if (i > 320)
if (i > 320) return; //无法解锁后面不用执行了
return; //无法解锁后面不用执行了 if (i % (1000 / 25) == 1000 / 25 - 1)
if (i % (1000 / 25) == 1000 / 25 - 1) {
{ await copter.UnlockAsync(); // 每 1000 毫秒重试一次。
await copter.UnlockAsync(); // 每 1000 毫秒重试一次。 }
}
await Task.Delay(25).ConfigureAwait(false);
await Task.Delay(25).ConfigureAwait(false); }
} //////解锁完成
//////解锁完成
// 为了返航,记录家的位置, 应该放在起飞命令
// 为了返航,记录家的位置, 应该放在起飞命令 info.TargetLat = info.Copter.Latitude;
info.TargetLat = info.Copter.Latitude; info.TargetLng = info.Copter.Longitude;
info.TargetLng = info.Copter.Longitude;
//等待起飞时间
//等待起飞时间 while (ts.TotalMilliseconds < info.TakeOffWaitTime * 1000 )
while (ts.TotalMilliseconds < info.TakeOffWaitTime * 1000 ) {
{ await Task.Delay(100);
await Task.Delay(100); dtNow = DateTime.Now;
dtNow = DateTime.Now; ts = dtNow - dtLastTime;
ts = dtNow - dtLastTime; }
}
//开始起飞
//开始起飞 for (int i = 0; i < 5; i++) // added by ZJF
for (int i = 0; i < 5; i++) // added by ZJF {
{ await copter.TakeOffAsync();
await copter.TakeOffAsync(); await Task.Delay(50).ConfigureAwait(false);
await Task.Delay(50).ConfigureAwait(false); }
}
// while (copter.Altitude < 4 || copter.State == Copters.CopterState.TakingOff)
// while (copter.Altitude < 4 || copter.State == Copters.CopterState.TakingOff) //低于5米任务一直等待
//低于5米任务一直等待 while (copter.Altitude < 5) // 修改起飞逻辑当高度达到5米时下一架开始起飞
while (copter.Altitude < 5) // 修改起飞逻辑当高度达到5米时下一架开始起飞 {
{ if (_flightTaskManager.IsPaused == true)
if (_flightTaskManager.IsPaused == true) {
{ await info.Copter.HoverAsync();
await info.Copter.HoverAsync(); return;
return; }
} await Task.Delay(100).ConfigureAwait(false);
await Task.Delay(100).ConfigureAwait(false); }
}
/* //先不要这个控制看能否正常工作
/* //先不要这个控制看能否正常工作 if (copter.Altitude > 8)
if (copter.Altitude > 8) {
{ await info.Copter.GuidAsync();
await info.Copter.GuidAsync(); return;
return; }
} */
*/ }
}
//执行第二第三阶段起飞任务-------------使用中
//执行第二第三阶段起飞任务-------------使用中 private async Task TakeOffSecondTaskAsync(FlightTaskSingleCopterInfo info)
private async Task TakeOffSecondTaskAsync(FlightTaskSingleCopterInfo info) {
{
int copterIndex = SingleCopterInfos.IndexOf(info);
int copterIndex = SingleCopterInfos.IndexOf(info); var copterNextTask = _flightTaskManager.Tasks[1].SingleCopterInfos[copterIndex];
var copterNextTask = _flightTaskManager.Tasks[1].SingleCopterInfos[copterIndex]; float takeOffAlt = copterNextTask.TargetAlt;// 15; 起飞高度到下个任务的高度
float takeOffAlt = copterNextTask.TargetAlt;// 15; 起飞高度到下个任务的高度 // 当该飞机被标记时,悬停并跳过飞行任务
// 当该飞机被标记时,悬停并跳过飞行任务 if ((bool)_copterManager.CopterStatus[copterIndex])
if ((bool)_copterManager.CopterStatus[copterIndex]) {
{ await info.Copter.HoverAsync();
await info.Copter.HoverAsync(); return;
return; } // await Task.Run(async () =>
} // await Task.Run(async () => // {
// { // 小于9米时等待----按起飞高度算此时可能已到达15米起飞高度
// 小于9米时等待----按起飞高度算此时可能已到达15米起飞高度 if (info.takeOffStage == 0)
if (info.takeOffStage == 0) {
{ while (info.Copter.Altitude < 9)
while (info.Copter.Altitude < 9) {
{ if (_flightTaskManager.IsPaused == true)
if (_flightTaskManager.IsPaused == true) {
{ await info.Copter.HoverAsync();
await info.Copter.HoverAsync(); return;
return; }
} await Task.Delay(100).ConfigureAwait(false);
await Task.Delay(100).ConfigureAwait(false); // 当该飞机被标记时,悬停并跳过飞行任务
// 当该飞机被标记时,悬停并跳过飞行任务 if ((bool)_copterManager.CopterStatus[copterIndex])
if ((bool)_copterManager.CopterStatus[copterIndex]) {
{ await info.Copter.HoverAsync();
await info.Copter.HoverAsync(); return;
return; }
} }
} if (_flightTaskManager.IsPaused == false)
if (_flightTaskManager.IsPaused == false) {
{ info.takeOffStage++;
info.takeOffStage++; }
} }
}
DateTime dtNow = DateTime.Now;
DateTime dtNow = DateTime.Now; DateTime dtLastTime = DateTime.Now;
DateTime dtLastTime = DateTime.Now; TimeSpan ts = dtNow - dtLastTime;
TimeSpan ts = dtNow - dtLastTime;
#region
#region
// 第二阶段超过9米开始水平飞行
// 第二阶段超过9米开始水平飞行 if (info.takeOffStage == 1)
if (info.takeOffStage == 1) {
{ //切换到guided模式
//切换到guided模式 await info.Copter.GuidAsync();
await info.Copter.GuidAsync(); //设置灯光为航点要求的灯光
//设置灯光为航点要求的灯光 await info.Copter.SetShowLEDAsync(copterNextTask.FlytoShowLED );
await info.Copter.SetShowLEDAsync(copterNextTask.FlytoShowLED ); //异步执行飞到第一个航点高度固定为15米的任务
//异步执行飞到第一个航点高度固定为15米的任务 for (int j = 0; j < 3; j++)
for (int j = 0; j < 3; j++) {
{ await info.Copter.FlyToAsync(info.TargetLat, info.TargetLng, takeOffAlt);
await info.Copter.FlyToAsync(info.TargetLat, info.TargetLng, takeOffAlt); await Task.Delay(10).ConfigureAwait(false);
await Task.Delay(10).ConfigureAwait(false); }
} //直到到达第一个航点并高度15米
//直到到达第一个航点并高度15米 while (!info.Copter.ArrivedTarget(info.TargetLat, info.TargetLng, takeOffAlt))
while (!info.Copter.ArrivedTarget(info.TargetLat, info.TargetLng, takeOffAlt)) {
{ if (_flightTaskManager.IsPaused == true)
if (_flightTaskManager.IsPaused == true) {
{ await info.Copter.HoverAsync();
await info.Copter.HoverAsync(); return;
return; }
} await Task.Delay(25).ConfigureAwait(false);
await Task.Delay(25).ConfigureAwait(false);
dtNow = DateTime.Now;
dtNow = DateTime.Now; ts = dtNow - dtLastTime;
ts = dtNow - dtLastTime; //每2秒再异步执行一次到航点高度15米的任务
//每2秒再异步执行一次到航点高度15米的任务 if (ts.TotalMilliseconds > 2000)
if (ts.TotalMilliseconds > 2000) {
{ for (int j = 0; j < 2; j++)
for (int j = 0; j < 2; j++) {
{ await info.Copter.FlyToAsync(info.TargetLat, info.TargetLng, takeOffAlt);
await info.Copter.FlyToAsync(info.TargetLat, info.TargetLng, takeOffAlt); await Task.Delay(10).ConfigureAwait(false);
await Task.Delay(10).ConfigureAwait(false); }
} dtLastTime = dtNow;
dtLastTime = dtNow; }
} // 当该飞机被标记时,悬停并跳过飞行任务
// 当该飞机被标记时,悬停并跳过飞行任务 if ((bool)_copterManager.CopterStatus[copterIndex])
if ((bool)_copterManager.CopterStatus[copterIndex]) {
{ await info.Copter.HoverAsync();
await info.Copter.HoverAsync(); return;
return; }
} }
} if (_flightTaskManager.IsPaused == false)
if (_flightTaskManager.IsPaused == false) {
{ info.takeOffStage++; //当前变为2
info.takeOffStage++; //当前变为2 }
} }
}
dtNow = DateTime.Now;
dtNow = DateTime.Now; dtLastTime = DateTime.Now;
dtLastTime = DateTime.Now; ts = dtNow - dtLastTime;
ts = dtNow - dtLastTime;
#endregion
#endregion
info.takeOffStage++;
info.takeOffStage++;
// 第三阶段从第一个航点位置15米垂直飞行
// 第三阶段从第一个航点位置15米垂直飞行 if (info.takeOffStage == 2)
if (info.takeOffStage == 2) {
{ //执行飞到第一个航点高度为设定目标高度
//执行飞到第一个航点高度为设定目标高度 for (int j = 0; j < 3; j++)
for (int j = 0; j < 3; j++) {
{ await info.Copter.FlyToAsync(copterNextTask.TargetLat, copterNextTask.TargetLng, copterNextTask.TargetAlt);
await info.Copter.FlyToAsync(copterNextTask.TargetLat, copterNextTask.TargetLng, copterNextTask.TargetAlt); await Task.Delay(10).ConfigureAwait(false);
await Task.Delay(10).ConfigureAwait(false); }
} //直到到达第一个航点
//直到到达第一个航点 while (!info.Copter.ArrivedTarget(copterNextTask.TargetLat, copterNextTask.TargetLng, copterNextTask.TargetAlt))
while (!info.Copter.ArrivedTarget(copterNextTask.TargetLat, copterNextTask.TargetLng, copterNextTask.TargetAlt)) {
{ if (_flightTaskManager.IsPaused == true)
if (_flightTaskManager.IsPaused == true) {
{ await info.Copter.HoverAsync();
await info.Copter.HoverAsync(); return;
return; }
} await Task.Delay(25).ConfigureAwait(false);
await Task.Delay(25).ConfigureAwait(false);
dtNow = DateTime.Now;
dtNow = DateTime.Now; ts = dtNow - dtLastTime;
ts = dtNow - dtLastTime; //每2秒发一次第一个航点飞行任务
//每2秒发一次第一个航点飞行任务 if (ts.TotalMilliseconds > 2000)
if (ts.TotalMilliseconds > 2000) {
{ for (int j = 0; j < 2; j++)
for (int j = 0; j < 2; j++) {
{ await info.Copter.FlyToAsync(copterNextTask.TargetLat, copterNextTask.TargetLng, copterNextTask.TargetAlt);
await info.Copter.FlyToAsync(copterNextTask.TargetLat, copterNextTask.TargetLng, copterNextTask.TargetAlt); await Task.Delay(10).ConfigureAwait(false);
await Task.Delay(10).ConfigureAwait(false); }
} dtLastTime = dtNow;
dtLastTime = dtNow; }
} // 当该飞机被标记时,悬停并跳过飞行任务
// 当该飞机被标记时,悬停并跳过飞行任务 if ((bool)_copterManager.CopterStatus[copterIndex])
if ((bool)_copterManager.CopterStatus[copterIndex]) {
{ await info.Copter.HoverAsync();
await info.Copter.HoverAsync(); return;
return; }
} }
} }
}
// });
// }); }
}
}
} }
}

File diff suppressed because it is too large Load Diff

View File

@ -1,235 +1,238 @@
<UserControl x:Class="Plane.FormationCreator.Views.ControlPanelView" <UserControl x:Class="Plane.FormationCreator.Views.ControlPanelView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Plane.FormationCreator.Views" xmlns:local="clr-namespace:Plane.FormationCreator.Views"
xmlns:fc="clr-namespace:Plane.FormationCreator" xmlns:fc="clr-namespace:Plane.FormationCreator"
xmlns:ec="clr-namespace:Plane.Copters;assembly=PlaneGcsSdk_Private_NET46" xmlns:ec="clr-namespace:Plane.Copters;assembly=PlaneGcsSdk_Private_NET46"
xmlns:vm="clr-namespace:Plane.FormationCreator.ViewModels" xmlns:vm="clr-namespace:Plane.FormationCreator.ViewModels"
xmlns:m="clr-namespace:Plane.FormationCreator.Formation" xmlns:m="clr-namespace:Plane.FormationCreator.Formation"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="300" d:DesignHeight="300"
d:DesignWidth="300"> d:DesignWidth="300">
<StackPanel Margin="0,0,-8,0"> <StackPanel Margin="0,0,-8,0">
<StackPanel.Resources> <StackPanel.Resources>
<Style TargetType="Button" <Style TargetType="Button"
BasedOn="{StaticResource {x:Type Button}}"> BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Margin" <Setter Property="Margin"
Value="0,0,3,5" /> Value="0,0,3,5" />
</Style> </Style>
</StackPanel.Resources> </StackPanel.Resources>
<!--<TextBlock Text="连接" /> <!--<TextBlock Text="连接" />
<WrapPanel> <WrapPanel>
<Button Content="连接" <Button Content="连接"
Command="{Binding ConnectCommand}" /> Command="{Binding ConnectCommand}" />
<Button Content="断开" <Button Content="断开"
Command="{Binding DisconnectCommand}" /> Command="{Binding DisconnectCommand}" />
</WrapPanel>--> </WrapPanel>-->
<TabControl Margin="0,0,13,0"> <TabControl Margin="0,0,13,0">
<TabItem Header="飞行前准备"> <TabItem Header="飞行前准备">
<StackPanel Orientation="Vertical" Margin="0,5,0,0"> <StackPanel Orientation="Vertical" Margin="0,5,0,0">
<WrapPanel> <WrapPanel>
<Button Content="电压检测" <Button Content="电压检测"
Command="{Binding DetectionVoltage}" /> Command="{Binding DetectionVoltage}" />
<Button Content="版本检测" <Button Content="版本检测"
Command="{Binding GetVersionsCommand}" /> Command="{Binding GetVersionsCommand}" />
<Button Content="通讯版本" Command="{Binding DetectionCommModuleVersion}" /> <Button Content="通讯版本" Command="{Binding DetectionCommModuleVersion}" />
<Button Content="统计返回" <Button Content="统计返回"
Command="{Binding DetectionReturnData}" /> Command="{Binding DetectionReturnData}" />
<Button Content="通讯统计" <Button Content="通讯统计"
Command="{Binding GetCommsumCommand}" /> Command="{Binding GetCommsumCommand}" />
<TextBlock <TextBlock
Margin="5,5,5,5" Foreground ="Red" VerticalAlignment="Center" Margin="5,5,5,5" Foreground ="Red" VerticalAlignment="Center"
Text="{Binding RTKState}" Text="{Binding RTKState}"
/> />
</WrapPanel> </WrapPanel>
<WrapPanel> <WrapPanel>
<Button Content="参数设置" <Button Content="参数设置"
Command="{Binding ParamModify}" /> Command="{Binding ParamModify}" />
<Button Content="读入参数" <Button Content="读入参数"
Command="{Binding LoadParamfile}" /> Command="{Binding LoadParamfile}" />
<Button Content="状态统计" Command="{Binding ReportGPSTypeCommand}"/> <Button Content="状态统计" Command="{Binding ReportGPSTypeCommand}"/>
<Button Content="飞机校准" <Button Content="飞机校准"
Command="{Binding CalibrationSingleCommand}" /> Command="{Binding CalibrationSingleCommand}" />
<Button Content="正式参数" Command="{Binding TurnOffTestLightsCommand}" Visibility="Collapsed" /> <Button Content="正式参数" Command="{Binding TurnOffTestLightsCommand}" Visibility="Collapsed" />
<Button Content="电机" Visibility="Collapsed" <Button Content="电机" Visibility="Collapsed"
Command="{Binding MotorTestCommand}" /> Command="{Binding MotorTestCommand}" />
<Button Content="删除飞机" <Button Content="删除飞机"
Command="{Binding DelCommand}" /> Command="{Binding DelCommand}" />
<Label Visibility="Collapsed" Content="Lat"/> <Label Visibility="Collapsed" Content="Lat"/>
<TextBox Visibility="Collapsed" Text="{Binding LatOffset}" Width="50"/> <TextBox Visibility="Collapsed" Text="{Binding LatOffset}" Width="50"/>
<Label Visibility="Collapsed" Content="Lng"/> <Label Visibility="Collapsed" Content="Lng"/>
<TextBox Visibility="Collapsed" Text="{Binding LngOffset}" Width="50"/> <TextBox Visibility="Collapsed" Text="{Binding LngOffset}" Width="50"/>
<Button Visibility="Collapsed" Content="设置返航点" Command="{Binding RLTOffsetCommand}" /> <Button Visibility="Collapsed" Content="设置返航点" Command="{Binding RLTOffsetCommand}" />
</WrapPanel> </WrapPanel>
<WrapPanel> <WrapPanel>
<Button Content="写入航点" <Button Content="写入航点"
Command="{Binding WriteMissionCommand}" /> Command="{Binding WriteMissionCommand}" />
<Button Content="航点续写" <Button Content="航点续写"
Command="{Binding WriteMissionFailedCommand}" /> Command="{Binding WriteMissionFailedCommand}" />
<Button Content="选写航点" Command="{Binding WriteMissionSingleCommand}" /> <Button Content="选写航点" Command="{Binding WriteMissionSingleCommand}" />
<Button Content="统计航点" <Button Content="统计航点"
Command="{Binding DetectionMissionData}" /> Command="{Binding DetectionMissionData}" />
<TextBox <TextBox
Grid.Column="1" Grid.Column="1"
Width="55" Width="55"
Margin="5, 5, 5, 5" Margin="5, 5, 5, 5"
HorizontalContentAlignment="Right" HorizontalContentAlignment="Right"
Text="{Binding RTKcomvalue, UpdateSourceTrigger=PropertyChanged}" Visibility="Collapsed" Text="{Binding RTKcomvalue, UpdateSourceTrigger=PropertyChanged}" Visibility="Collapsed"
/> />
<Button Content="{Binding RTKbtntxt}" <Button Content="{Binding RTKbtntxt}"
Command="{Binding SendRTKCommand}" Visibility="Collapsed" /> Command="{Binding SendRTKCommand}" Visibility="Collapsed" />
<Button Content="{Binding NTRIPbtntxt}" <Button Content="{Binding NTRIPbtntxt}"
Command="{Binding SendRTCMCommand}" Visibility="Collapsed"/> Command="{Binding SendRTCMCommand}" Visibility="Collapsed"/>
<Button Content="RTK 控制" Command="{Binding OpenRtcmManageCommand}" /> <Button Content="RTK 控制" Command="{Binding OpenRtcmManageCommand}" />
</WrapPanel> </WrapPanel>
</StackPanel> </StackPanel>
</TabItem> </TabItem>
<TabItem Header="飞行控制"> <TabItem Header="飞行控制">
<StackPanel Orientation="Vertical" Margin="0,5,0,0"> <StackPanel Orientation="Vertical" Margin="0,5,0,0">
<WrapPanel > <WrapPanel >
<Button Content="解锁" <Button Content="解锁"
Command="{Binding UnlockCommand}" /> Command="{Binding UnlockCommand}" />
<Button Content="加锁" <Button Content="加锁"
Command="{Binding LockCommand}" /> Command="{Binding LockCommand}" />
<Button Content="单独任务" <Button Content="单独任务"
Command="{Binding TakeOffCommand}" /> Command="{Binding TakeOffCommand}" />
<Button Content="抛物" <Button Content="抛物"
Command="{Binding ThrowoutCommand}" /> Command="{Binding ThrowoutCommand}" />
</WrapPanel> </WrapPanel>
<WrapPanel> <WrapPanel>
<Button Content="起飞" <Button Content="起飞"
Command="{Binding GuidAsyncCommand}" /> Command="{Binding GuidAsyncCommand}" />
<Button Content="悬停" <Button Content="悬停"
Command="{Binding HoverCommand}" /> Command="{Binding HoverCommand}" />
<Button Content="手动" <Button Content="手动"
Command="{Binding FloatCommand}" /> Command="{Binding FloatCommand}" />
<Button Content="返航" <Button Content="返航"
Command="{Binding ReturnToLaunchCommand}" /> Command="{Binding ReturnToLaunchCommand}" />
<Button Content="降落" <Button Content="降落"
Command="{Binding LandCommand}" /> Command="{Binding LandCommand}" />
<Button Content="跳过" Visibility="Collapsed" <Button Content="跳过" Visibility="Collapsed"
Command="{Binding FlagCommand}" /> Command="{Binding FlagCommand}" />
<TextBox Width="50" <TextBox Width="50"
Visibility="Collapsed" Visibility="Collapsed"
Text="{Binding AltP, UpdateSourceTrigger=PropertyChanged}" /> Text="{Binding AltP, UpdateSourceTrigger=PropertyChanged}" />
</WrapPanel> </WrapPanel>
<WrapPanel> <WrapPanel>
<Button Content="闪灯" <Button Content="闪灯"
Command="{Binding LEDFlickerCommand}" /> Command="{Binding LEDFlickerCommand}" />
<Button Content="测试" Visibility="Collapsed" <Button Content="测试" Visibility="Collapsed"
Command="{Binding TestCommand}" /> Command="{Binding TestCommand}" />
<Button Content="开灯" <Button Content="开灯"
Command="{Binding LEDOnOffCommand}" Command="{Binding LEDOnOffCommand}"
CommandParameter="0"/> CommandParameter="0"/>
<Button Content="关灯" <Button Content="关灯"
Command="{Binding LEDOnOffCommand}" Command="{Binding LEDOnOffCommand}"
CommandParameter="1"/> CommandParameter="1"/>
<TextBlock Margin="8,-3,5,0" Text="起飞高度" VerticalAlignment="Center"/> <TextBlock Margin="8,-3,5,0" Text="起飞高度" VerticalAlignment="Center"/>
<TextBox VerticalContentAlignment="Center" Margin="0,0,0,5" Width="30" Height="25" Text="{Binding TaskOffAlt}" /> <TextBox VerticalContentAlignment="Center" Margin="0,0,0,5" Width="30" Height="25" Text="{Binding TaskOffAlt}" />
<TextBlock Margin="5,-3,5,0" Text="米" VerticalAlignment="Center"/> <TextBlock Margin="5,-3,5,0" Text="米" VerticalAlignment="Center"/>
</WrapPanel> </WrapPanel>
</StackPanel> </StackPanel>
</TabItem> </TabItem>
<TabItem Header="任务控制"> <TabItem Header="任务控制">
<StackPanel Orientation="Vertical" Margin="0,5,0,0"> <StackPanel Orientation="Vertical" Margin="0,5,0,0">
<WrapPanel> <WrapPanel>
<Button Content="全部解锁" <Button Content="全部解锁"
Command="{Binding UnlockAllCommand}" Command="{Binding UnlockAllCommand}"
IsEnabled="{Binding AllowMissionStart, UpdateSourceTrigger=PropertyChanged}" /> IsEnabled="{Binding AllowMissionStart, UpdateSourceTrigger=PropertyChanged}" />
<Button Content="全部加锁" <Button Content="全部加锁"
Command="{Binding LockAllCommand}" /> Command="{Binding LockAllCommand}" />
</WrapPanel> </WrapPanel>
<WrapPanel> <WrapPanel>
<Button Content="开始任务" <Button Content="开始任务"
Command="{Binding MissionStartCommand}" Command="{Binding MissionStartCommand}"
IsEnabled="{Binding AllowMissionStart, UpdateSourceTrigger=PropertyChanged}"/> IsEnabled="{Binding AllowMissionStart, UpdateSourceTrigger=PropertyChanged}"/>
<Button Content="暂停任务" <Button Content="暂停任务"
Command="{Binding MissionPauseCommand}" /> Command="{Binding MissionPauseCommand}" />
<Button Content="继续任务" <Button Content="继续任务"
Command="{Binding MissionResumeCommand}" /> Command="{Binding MissionResumeCommand}" />
</WrapPanel> </WrapPanel>
<WrapPanel> <WrapPanel>
<Button Content="全部降落" <Button Content="全部降落"
Command="{Binding AllLandCommand}" /> Command="{Binding AllLandCommand}" />
<Button Content="紧急返航"
</WrapPanel> Command="{Binding EmergencyRetCommand}" />
</StackPanel>
</TabItem> </WrapPanel>
</StackPanel>
</TabItem>
<TabItem Header="飞行报告" Visibility="Collapsed">
<StackPanel Orientation="Vertical" Margin="0,5,0,0">
<TabItem Header="飞行报告" Visibility="Collapsed">
<WrapPanel>
<StackPanel Orientation="Vertical" Margin="0,5,0,0">
<Button Content="添加报告"
Command="{Binding UnlockAllCommand}" <WrapPanel>
IsEnabled="{Binding AllowMissionStart, UpdateSourceTrigger=PropertyChanged}" />
<Button Content="查看报告" <Button Content="添加报告"
Command="{Binding LockAllCommand}" /> Command="{Binding UnlockAllCommand}"
</WrapPanel> IsEnabled="{Binding AllowMissionStart, UpdateSourceTrigger=PropertyChanged}" />
<Button Content="查看报告"
Command="{Binding LockAllCommand}" />
</WrapPanel>
</StackPanel>
</TabItem>
</StackPanel>
</TabItem>
</TabControl>
</StackPanel>
</UserControl>
</TabControl>
</StackPanel>
</UserControl>