支持紧急返航

支持返回飞机错误
飞机有预解锁错误回显示黄色
支持新版低电电压参数
支持重启飞控
支持陀螺仪校准
This commit is contained in:
pxzleo 2024-03-26 22:06:52 +08:00
parent 36875bcdc2
commit af9a86dffd
16 changed files with 1889 additions and 1648 deletions

View File

@ -75,9 +75,16 @@
<lcnv:HeartbeatCountToBrushConverter x:Key="HeartbeatCountToBrushConverter" />
<lcnv:AppModeToVisibilityConverter x:Key="AppModeToVisibilityConverter" />
<lcnv:FlightTaskStatusToFillConverter x:Key="FlightTaskStatusToFillConverter" />
<lcnv:ErrorCodeToColorConverter x:Key="ErrorCodeToColorConverter" />
<lcnv:PrecheckToColorConverter x:Key="PrecheckToColorConverter" />
<lcnv:FlightTaskStatusAndTransitionToFillConverter x:Key="FlightTaskStatusAndTransitionToFillConverter" />
<lcnv:FlightTaskIsSelectedToEffectConverter x:Key="FlightTaskIsSelectedToEffectConverter" />
</Application.Resources>
</Application>

View File

@ -15,25 +15,68 @@ namespace Plane.FormationCreator.Converters
public class HeartbeatCountToBrushConverter : IMultiValueConverter
{
private static SolidColorBrush _zeroBrush = new SolidColorBrush(Color.FromArgb(125, 125, 125, 125));
private static SolidColorBrush _zeroBrush_fault = new SolidColorBrush(Color.FromRgb(160, 140, 0));
private static SolidColorBrush _oneBrush = Copter.DefaultBrush;
private static SolidColorBrush _FakeCopterBrush = Copter.DefaultFakeBrush;
private static SolidColorBrush _PreCheckNopassBrush = Copter.YellowBrush;
private static SolidColorBrush _NoconnectedBrush = Copter.RedBrush;
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values[0] == DependencyProperty.UnsetValue) return _zeroBrush;
var heartbeatCount = (ulong)values[0];
if (heartbeatCount % 2 == 0) return _zeroBrush;
/* //绑定的是心跳,所以连接断开时不会调用这个转换器
//如果是真飞机,并且断开了,直接显示红色
if (values[1] is PLCopter)
{
var plcopter = values[1] as PLCopter;
if (!plcopter.CommModuleConnected)
return _NoconnectedBrush;
}
*/
//用于显示收到心跳的闪烁
if (heartbeatCount % 2 == 0)
{
//真飞机如果异常显示暗淡黄色
if (values[1] is PLCopter)
{
var plcopter = values[1] as PLCopter;
if (plcopter.CopterPreCheckPass)
return _zeroBrush;
else return _zeroBrush_fault;
}
else
return _zeroBrush;
}
if (values[1] is FakeCopter)
{
var fkcopter = values[1] as FakeCopter;
if (fkcopter.CopterPreCheckPass)
return _FakeCopterBrush;
else return _PreCheckNopassBrush;
}
if (values[1] is PLCopter)
{
var plcopter = values[1] as PLCopter;
if (plcopter.CopterPreCheckPass)
return _oneBrush;
else return _PreCheckNopassBrush;
}
var copter = values[1] as Copter;
return copter == null ? _oneBrush : copter.Brush;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)

View File

@ -62,7 +62,13 @@ namespace Plane.FormationCreator.Formation
private SolidColorBrush _Brush;
public SolidColorBrush Brush
{
get { return _Brush ?? DefaultBrush; }
get {
if (CopterPreCheckPass)
return _Brush ?? DefaultBrush;
else
return _Brush ?? YellowBrush;
}
set { Set(nameof(Brush), ref _Brush, value); }
}
}

View File

@ -26,6 +26,7 @@ using Newtonsoft.Json.Linq;
using GMap.NET.MapProviders;
using GMap.NET;
using static Plane.FormationCreator.CalculationLogLatDistance;
using Plane.CopterManagement;
namespace Plane.FormationCreator.Formation
{
@ -412,6 +413,13 @@ namespace Plane.FormationCreator.Formation
get { return _TaskState; }
private set { Set(nameof(TaskState), ref _TaskState, value); }
}
//真实飞行任务状态
private TasksStatus _TaskState_real = TasksStatus.Stop;
public TasksStatus TaskState_real
{
get { return _TaskState_real; }
private set { Set(nameof(TaskState_real), ref _TaskState_real, value);}
}
public event EventHandler<FlightTaskAddedEventArgs> TaskAdded;
public event EventHandler<FlightTaskDeledEventArgs> TaskDeled;
@ -601,6 +609,7 @@ namespace Plane.FormationCreator.Formation
/// <summary>
/// 起始点作为参考,设置起始点后飞行写入的数据将为相对坐标
/// </summary>
@ -796,7 +805,7 @@ namespace Plane.FormationCreator.Formation
Pause();
//等待暂停或2s超时(80*25ms)
int k = 0;
while ((TaskState != TasksStatus.Paused) || (k > 80))
while ((TaskState != TasksStatus.Paused) && (k < 80))
{
await Task.Delay(25).ConfigureAwait(false);
k++;
@ -2227,7 +2236,7 @@ namespace Plane.FormationCreator.Formation
}
//新开线程异步调用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, List<int> mappingId = null)
{
List<List<FlightRouteV2.Vector3>> ret = null;
bool isPasstmp = false;
@ -2235,7 +2244,7 @@ namespace Plane.FormationCreator.Formation
var task = Task.Run(() =>
{
cts = new CancellationTokenSource();
ret = FlyVecFun.ABypassB(aVecs, bVecs, Routecallback, Cronograma, cts.Token, out isPasstmp);
ret = FlyVecFun.ABypassB(aVecs, bVecs, Routecallback, Cronograma, cts.Token, out isPasstmp, mappingId);
});
try
{
@ -2277,7 +2286,7 @@ namespace Plane.FormationCreator.Formation
var task = Task.Run(() =>
{
ret = FlyVecFun.CollisionLayer(aVecs, bVecs, taskname_a, taskname_b, Routecallback);
ret = FlyVecFun.CollisionLayer(aVecs, bVecs, Routecallback);
});
try
{
@ -2408,7 +2417,7 @@ namespace Plane.FormationCreator.Formation
/// <summary>
/// 自动生成航线2D和3D都用这个-------V2版使用新的碰撞检测和绕行用flybase.cs库只用于新版固件--------------
/// </summary>
/// <param name="Is3d">3D计算</param>
/// <param name="Is3d">2D/3D计算</param>
/// <param name="Ischange">是否改变线路的结束点顺序--返回起飞点航线不能交换</param>
/// <param name="Is3dstagger">3D是否自动插入拉开层用于2D画面回起飞矩阵拉开2D画面</param>
public async Task OptimizeRouteMeterV2(bool Is3d = false, bool Ischange = true,bool Is3dstagger=false)
@ -2417,6 +2426,10 @@ namespace Plane.FormationCreator.Formation
Dictionary<int, Point3D> prevTaskPoint = new Dictionary<int, Point3D>();
var stopWatch = new Stopwatch();
stopWatch.Start();
//ID映射列表
List<int> mappingId = new List<int>();
//设置随机数种子
FlyVecFun.RandomSeed = (int)DateTime.Now.Ticks;
@ -2435,6 +2448,8 @@ namespace Plane.FormationCreator.Formation
var prevInfo = Tasks[SelectedTaskIndex - 1].SingleCopterInfos[i];
Point3D prevLoc = new Point3D(prevInfo.X * 100, prevInfo.TargetAlt * 100, prevInfo.Y * 100);
prevTaskPoint.Add(i, prevLoc);
//3D计算需要ID映射
mappingId.Add(int.Parse(_copterManager.Copters[i].Id));
}
string taskname_a = SelectedTaskIndex.ToString() + Tasks[SelectedTaskIndex - 1].TaskCnName;
string taskname_b = (SelectedTaskIndex+1).ToString()+SelectedTask.TaskCnName;
@ -2473,7 +2488,9 @@ namespace Plane.FormationCreator.Formation
if (Is3d)
{
bool isPass = false;
var result= await ABypassBAsync(aVecs, bVecs);
var result= await ABypassBAsync(aVecs, bVecs, mappingId);
List<List<FlightRouteV2.Vector3>> flyret = result.Item1;
isPass= result.Item2;
if ((flyret.Count == 0)&&(!isPass))
@ -2483,6 +2500,12 @@ namespace Plane.FormationCreator.Formation
{
Message.Show($"任务{SelectedTaskIndex + 1}无法直接生成3D航线尝试拉开画面");
cVecs = await NormalPullsync(aVecs, bVecs);
if (cVecs == null)
{
Message.Show($"任务不满足拉开条件,退出");
return;
}
Message.Show($"任务{SelectedTaskIndex + 1}后插入拉开层...");
//插入错层航点
SelectTask(SelectedTaskIndex - 1);
@ -2498,7 +2521,7 @@ namespace Plane.FormationCreator.Formation
SetTaskFlytime(SelectedTaskIndex);
//选到最后一个航点
SelectTask(SelectedTaskIndex + 1);
var result1= await ABypassBAsync(cVecs, bVecs);
var result1= await ABypassBAsync(cVecs, bVecs, mappingId);
flyret = result1.Item1;
isPass = result1.Item2;
}
@ -3260,9 +3283,64 @@ namespace Plane.FormationCreator.Formation
}
}
//任务飞行时长ms
private TimeSpan _taskflyTime ;
public TimeSpan taskflyTime
{
get { return _taskflyTime; }
set { Set(nameof(taskflyTime), ref _taskflyTime, value); }
}
//真实任务飞行时长ms
private TimeSpan _taskflyTime_real;
public TimeSpan taskflyTime_real
{
get { return _taskflyTime_real; }
set { Set(nameof(taskflyTime_real), ref _taskflyTime_real, value); }
}
private DateTime _taskStartTime;
private DateTime _taskStartTime_real;
public DateTime TaskStartTime_real
{
get { return _taskStartTime_real; }
}
public bool RealRunTask(DateTime taskStartTime)
{
if (TaskState_real == TasksStatus.Stop)
//根据传入时间设置真实起飞时间
{
_taskStartTime_real = taskStartTime;
TaskState_real = TasksStatus.Running;
Message.Show($"{taskStartTime.ToString("HH:mm:ss")}:真实任务开始");
return true;
}else
Message.Show($"任务已经开始");
return false;
}
public void RealResetTask()
{
TaskState_real = TasksStatus.Stop;
}
public bool SimRunTask(DateTime taskStartTime)
{
if (TaskState== TasksStatus.Stop)
//根据传入时间设置真实起飞时间
{
_taskStartTime = taskStartTime;
Message.Show($"{taskStartTime.ToString("HH:mm:ss")}:默认任务开始");
return true;
} else
Message.Show($"任务已经开始");
return false;
}
TimeSpan timeSpan;
public DateTime taskStartTime;
public async Task RunTaskAsync()
{
if (Tasks.Count == 0) return;
@ -3290,7 +3368,12 @@ namespace Plane.FormationCreator.Formation
if (CurrentRunningTaskIndex == 0)
{
taskStartTime = DateTime.Now;
if (!SimRunTask(DateTime.Now))
{
Alert.Show($"模拟任务已经开始,请先停止任务!");
return;
}
Message.Show($"{DateTime.Now.ToString("HH:mm:ss")}:任务开始");
}
@ -3307,13 +3390,16 @@ namespace Plane.FormationCreator.Formation
await RunAsync();
taskflyTime = DateTime.Now - _taskStartTime;
if ((IsPaused ?? false) == false)
{
timeSpan = DateTime.Now - taskStartTime;
Message.Show($"{DateTime.Now.ToString("HH:mm:ss")}:任务结束");
Message.Show($"总时长 = {timeSpan.Minutes}分{timeSpan.Seconds}秒");
Message.Show($"总时长 = {taskflyTime.Minutes}分{taskflyTime.Seconds}秒");
}
else
Message.Show($"任务暂停,总时长 = {taskflyTime.TotalSeconds}秒");
}
/// <summary>
/// 开始运行模拟任务
@ -3330,12 +3416,13 @@ namespace Plane.FormationCreator.Formation
task.Status = FlightTaskStatus.Stop;
}
AppEx.Current.AppMode = AppMode.RunningTasks;
StartAvoidingCrash(); //开始碰撞检测
//告诉所有飞机开始任务--模拟飞机不计算起飞延迟直接传0
foreach (var copter in _copterManager.Copters)
await copter.MissionStartAsync(0, 0, 0, 0, 0);
TaskState = TasksStatus.Running;
StartAvoidingCrash(); //开始碰撞检测
for (int i = CurrentRunningTaskIndex; i < Tasks.Count; i++)
{
var task = Tasks[i];
@ -3474,6 +3561,7 @@ namespace Plane.FormationCreator.Formation
{
rettaskindex = i;
taskflytime = rettime - starttime;
break;
}
starttime += flyedtasktime;
}
@ -3495,7 +3583,7 @@ namespace Plane.FormationCreator.Formation
curLoc = TaskFlyLoc(copterprvLoc, coptercurLoc, taskflytime, Tasks[rettaskindex].FlytoTime);
}
else //正在悬停
curLoc = new PLLocation(curinfo.TargetLat, curinfo.TargetLng, 0);
curLoc = new PLLocation(curinfo.TargetLat, curinfo.TargetLng, curinfo.TargetAlt);
curTaskPoint.Add(i, curLoc);
if (curinfo.TargetLat > taskmaxlat)
@ -3557,15 +3645,22 @@ namespace Plane.FormationCreator.Formation
/// <summary>
/// 开始碰撞检测
/// </summary>
private async void StartAvoidingCrash()
{
await Task.Factory.StartNew(AvoidCrashtoshow);
await Task.Factory.StartNew(LoopToAvoidCrash);
}
/// <summary>
/// 将碰撞显示到UI
/// </summary>
private async void AvoidCrashtoshow()
{
while (IsPaused == false)
Message.Show("开始碰撞检测");
while (TaskState != TasksStatus.Stop) //IsPaused == false
{
try
{
@ -3585,10 +3680,14 @@ namespace Plane.FormationCreator.Formation
await Task.Delay(100).ConfigureAwait(false);
}
}
Message.Show("开始碰撞检测停止");
}
/// <summary>
/// 循环检测碰撞
/// </summary>
private async void LoopToAvoidCrash()
{
while (IsPaused == false)
while (TaskState != TasksStatus.Stop)
{
try
{

View File

@ -183,6 +183,10 @@ namespace Plane.FormationCreator.Formation
await info.Copter.HoverAsync();
return;
}
if (_flightTaskManager.IsEmergencyRet == true)
{
return;
}
dtNow = DateTime.Now;
ts = dtNow - dtLastTime;
}

View File

@ -112,6 +112,8 @@ namespace Plane.FormationCreator.Formation
info.TargetLng = info.Copter.Longitude;
//info.Copter.takeOffTargetAltitude = takeOffAlt;
FlightTask task = _flightTaskManager.CurrentRunningTask;
if (task==null)
return;
float takeflytime = task.TakeOffTime - info.TakeOffWaitTime;
//飞行目标,开始往上飞
await info.Copter.FlyToAsync(info.TargetLat, info.TargetLng, takeOffAlt, takeflytime, 1); //秒

View File

@ -1,4 +1,5 @@
using Plane.FormationCreator.Util;
using Microsoft.Practices.ServiceLocation;
using Plane.FormationCreator.Util;
using System;
using System.Collections.Generic;
using System.Linq;
@ -43,7 +44,15 @@ namespace Plane.FormationCreator
private void Modify_Select(object sender, RoutedEventArgs e)
{
textParamName.Text = ((Button)sender).Tag.ToString();
Formation.CopterManager _copterManager = ServiceLocator.Current.GetInstance<Formation.CopterManager>();
String strParamName = ((Button)sender).Tag.ToString();
if (strParamName == "FS_BATT_VOLTAGE")
{
if (_copterManager.FC_VER_NO >= 3)
strParamName = "BATT_LOW_VOLT";
}
textParamName.Text = strParamName;
textParamName_cn.Text = ((Button)sender).Content.ToString();
}

View File

@ -166,6 +166,8 @@
<Compile Include="AppEx.cs" />
<Compile Include="AppConfig.cs" />
<Compile Include="Converters\AppModeToVisibilityConverter.cs" />
<Compile Include="Converters\PrecheckToColorConverter.cs" />
<Compile Include="Converters\ErrorCodeToColorConverter.cs" />
<Compile Include="Converters\FlightTaskIsSelectedToEffectConverter.cs" />
<Compile Include="Converters\FlightTaskStatusAndTransitionToFillConverter.cs" />
<Compile Include="Converters\FlightTaskStatusToFillConverter.cs" />

View File

@ -139,6 +139,47 @@ namespace Plane.FormationCreator.ViewModels
}
public bool IsCalibration { get; set; }
/// <summary>
/// 重启飞控
/// </summary>
private ICommand _RestartFCCommand;
public ICommand RestartFCCommand
{
get
{
return _RestartFCCommand ?? (_RestartFCCommand = new RelayCommand(async () =>
{
if (_copterManager.SelectedCopters.Count() == 0) return;
Message.Show("重启飞控");
await commModule.DoRestartFCAsync(_copterManager.SelectedCopters);
await Task.Delay(50).ConfigureAwait(false);
}));
}
}
/// <summary>
/// 陀螺仪校准
/// </summary>
private ICommand _CalibrationPreflightCommand;
public ICommand CalibrationPreflightCommand
{
get
{
return _CalibrationPreflightCommand ?? (_CalibrationPreflightCommand = new RelayCommand(async () =>
{
if (_copterManager.SelectedCopters.Count() == 0) return;
Message.Show("开始校准陀螺仪");
await commModule.DoCalibrationPreflightAsync(_copterManager.SelectedCopters);
await Task.Delay(50).ConfigureAwait(false);
}));
}
}
/// <summary>
/// 校准指南针
/// </summary>

View File

@ -395,6 +395,20 @@ namespace Plane.FormationCreator.ViewModels
}
}
private ICommand _ResetRealMissionCommand;
public ICommand ResetRealMissionCommand
{
get
{
return _ResetRealMissionCommand ?? (_ResetRealMissionCommand = new RelayCommand(async () =>
{
FlightTaskManager _flightTaskManager = ServiceLocator.Current.GetInstance<FlightTaskManager>();
_flightTaskManager.RealResetTask();
AllowMissionStart = true;
}));
}
}
private ICommand _EmergencyRetCommand;
public ICommand EmergencyRetCommand
{
@ -402,23 +416,45 @@ namespace Plane.FormationCreator.ViewModels
{
return _EmergencyRetCommand ?? (_EmergencyRetCommand = new RelayCommand(async () =>
{
if (Alert.Show("您确定要紧急返航吗?紧急返航可能导致飞行器碰撞!!!!", "警告", MessageBoxButton.OKCancel, MessageBoxImage.Warning)
!= MessageBoxResult.OK)
return; //计算当前图案中心点,起飞图案中心点,图案距离起飞图案中心点最近距离
FlightTaskManager _flightTaskManager = ServiceLocator.Current.GetInstance<FlightTaskManager>();
if (_flightTaskManager.Tasks.Count==0)
{
Alert.Show("没有航点无法紧急返航!", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
if ((_flightTaskManager.TaskState_real == TasksStatus.Stop)
&&((_flightTaskManager.IsPaused ?? false) == false))
{
Alert.Show("先暂停任务!", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
//if (Alert.Show("您确定要紧急返航吗?紧急返航可能导致飞行器碰撞!!!!", "警告", MessageBoxButton.OKCancel, MessageBoxImage.Warning)
// != MessageBoxResult.OK)
// return;
//计算当前图案中心点,起飞图案中心点,图案距离起飞图案中心点最近距离
//计算无人机返航方向和最近的飞机距离
PLLocation takeoffcentloc;
PLLocation taskcentloc;
double mindistance; //单位米
bool overlapping; //图案否重叠
int rettime= (int)(DateTime.Now - _flightTaskManager.taskStartTime).TotalSeconds;
int rettime=0;
if (_flightTaskManager.TaskState_real!= TasksStatus.Stop)
//计算实际飞行时间
rettime = (int)(DateTime.UtcNow - _flightTaskManager.TaskStartTime_real).TotalSeconds;
else
if (_flightTaskManager.TaskState!= TasksStatus.Stop)
//计算模拟飞行时间
rettime = (int)_flightTaskManager.taskflyTime.TotalSeconds;
if (!_flightTaskManager.EmergencyRet(rettime,out takeoffcentloc,out taskcentloc, out mindistance,out overlapping))
{
Alert.Show("紧急返航数据计算失败!", "提示");
return;
}
rettime += 5; //加5秒延迟用于通讯重复有些飞机通讯不成功多次发送才收到比别的飞机慢
//模拟测试
if (_flightTaskManager.TaskState != TasksStatus.Stop)
await _flightTaskManager.sim_DoMissionEmergencyRetAsync(takeoffcentloc, taskcentloc, (float)mindistance, rettime, overlapping);
@ -544,7 +580,8 @@ namespace Plane.FormationCreator.ViewModels
await Task.Delay(1000).ConfigureAwait(false);
}
await Task.Delay(100);
AllowMissionStart = true;
FlightTaskManager _flightTaskManager = ServiceLocator.Current.GetInstance<FlightTaskManager>();
AllowMissionStart = (_flightTaskManager.TaskState_real == TasksStatus.Stop);
/*
await Task.WhenAll(_copterManager.Copters.Select(async c => {
@ -1440,9 +1477,22 @@ namespace Plane.FormationCreator.ViewModels
Alert.Show("作为参照的原点未设置,无法开始任务!", "提示");
return;
}
if (_flightTaskManager.Tasks.Count == 0 )
{
if (Alert.Show("没有导入任务,紧急返航功能不能使用,继续吗?", "警告", MessageBoxButton.OKCancel, MessageBoxImage.Warning)
!= MessageBoxResult.OK)
return;
}
//飞机用UTC时间日志用本地时间记录
DateTime MissionTime = DateTime.UtcNow.AddSeconds(5);
DateTime MissionTime_log = DateTime.Now.AddSeconds(5);
if (!_flightTaskManager.RealRunTask(MissionTime))
{
Alert.Show("任务已经开始,请先重设任务!", "提示");
return;
}
AllowMissionStart = false;
Message.Show("任务开始:" + MissionTime_log.ToString());
//循环3次 发送起飞命令 避免通信问题
for (int i = 0; i < 20; i++) //20

View File

@ -959,8 +959,8 @@ namespace Plane.FormationCreator.ViewModels
return _OptimizeRouteCommandRet ?? (_OptimizeRouteCommandRet = new RelayCommand<int>(async =>
{
if (_copterManager.FC_VER_NO >= 3)
//3D计算不改变ID可以错层
_flightTaskManager.OptimizeRouteMeter(false, false, true); //采用米计算逻辑用3D生成不改变ID可拉开层(2D回起飞矩阵专用)
//2D计算不改变ID不用错层
_flightTaskManager.OptimizeRouteMeter(false, false, false); //采用米计算逻辑用3D生成不改变ID可拉开层(2D回起飞矩阵专用)
else
_flightTaskManager.OptimizeRouteMeter(false, false); //采用米计算逻辑用2D生成不改变ID不拉开层
@ -978,7 +978,7 @@ namespace Plane.FormationCreator.ViewModels
{
if (_copterManager.FC_VER_NO >= 3)
//3D计算不改变ID可以错层
_flightTaskManager.OptimizeRouteMeter(true, false, false); //采用米计算逻辑用3D生成不改变ID拉开层(3D回起飞矩阵专用)
_flightTaskManager.OptimizeRouteMeter(true, false, true); //采用米计算逻辑用3D生成不改变ID拉开层(3D回起飞矩阵专用,结束必须是矩阵)
else
_flightTaskManager.OptimizeRouteMeter(false, false); //采用米计算逻辑用2D生成不改变ID不拉开层

View File

@ -6,8 +6,8 @@
xmlns:local="clr-namespace:Plane.FormationCreator.Views"
mc:Ignorable="d"
WindowStartupLocation="CenterScreen"
Title="校准" Height="320" Width="450">
<Grid>
Title="校准" Height="329" Width="455">
<Grid Margin="0,0,0,7">
<Grid.RowDefinitions>
<RowDefinition Height="70*"/>
<RowDefinition Height="30*"/>
@ -25,12 +25,16 @@
</StackPanel>
<StackPanel Grid.Row="1" Margin="10,0,10,10">
<Label Content="指南针" Margin="0,0,0,10" FontWeight="Bold" FontSize="14"/>
<Label Content="其他" Margin="0,0,0,10" FontWeight="Bold" FontSize="14"/>
<WrapPanel HorizontalAlignment="Center">
<Button Content="开始校准" Width="100" Margin="10, 0"
Command="{Binding CalibrationCompassCommand}"/>
<Button Content="放弃校准" Width="100" Margin="10, 0"
Command="{Binding CancelCalibrationCompassCommand}" Visibility="Collapsed"/>
<Button Content="校准指南针" Width="120"
Command="{Binding CalibrationCompassCommand}"/>
<Button Content="校准陀螺仪" Width="120" Margin="20, 0"
Command="{Binding CalibrationPreflightCommand}"/>
<Button Content="重启飞控" Width="100" Margin="10, 0"
Command="{Binding RestartFCCommand}"/>
</WrapPanel>
<ProgressBar Margin="0,20" Height="18" Width="220" Value="{Binding CompassPercent, UpdateSourceTrigger=PropertyChanged}"/>

View File

@ -203,6 +203,8 @@
<Button Content="紧急返航"
Command="{Binding EmergencyRetCommand}" />
<Button Content="重设任务"
Command="{Binding ResetRealMissionCommand}" />
</WrapPanel>
</StackPanel>

View File

@ -12,9 +12,12 @@
d:DataContext="{d:DesignInstance Type=ec:FakeCopter, IsDesignTimeCreatable=True}">
<UserControl.Resources>
<Style TargetType="TextBlock">
<Setter Property="FontSize" Value="14" />
</Style>
@ -177,6 +180,7 @@
<StackPanel>
<TextBlock Text="飞行信息" />
<Grid>
<Grid.Resources>
<Style x:Key="CopterInfo_ComboBox"
TargetType="ComboBox"
@ -200,7 +204,7 @@
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Vertical" >
<StackPanel.Resources>
<Style TargetType="ComboBox"
BasedOn="{StaticResource CopterInfo_ComboBox}" />
@ -250,36 +254,19 @@
<TextBlock Text="高度:" />
<TextBlock Text="{Binding Altitude, StringFormat=0.##}" />
</StackPanel>
<StackPanel>
<TextBlock Text="距离:" />
<TextBlock Text="{Binding FlightDistance, StringFormat=0.##}" />
</StackPanel>
<StackPanel>
<TextBlock Text="锁定类型:" />
<TextBlock Text="{Binding GpsFixType}" />
</StackPanel>
<StackPanel>
<TextBlock Text="返回数据:" />
<StackPanel ToolTip="{Binding RetainInt}">
<TextBlock Text="{Binding Retain[3]}" />
<TextBlock Text="." />
<TextBlock Text="{Binding Retain[2]}" />
<TextBlock Text="." />
<TextBlock Text="{Binding Retain[1]}" />
<TextBlock Text="." />
<TextBlock Text="{Binding Retain[0]}" />
<TextBlock Text="预检查状态:" />
<TextBlock Text="{Binding CopterPreCheckPassStr}"
Foreground="{Binding CopterPreCheckPass, Converter={StaticResource PrecheckToColorConverter}}" />
</StackPanel>
</StackPanel>
</StackPanel>
<!--
<StackPanel>
<TextBlock Text="固件版本:" />
<TextBlock Text="{Binding FirmwareVersionText}" />
</StackPanel>-->
</StackPanel>
<StackPanel Grid.Row="1"
Grid.Column="1"
Orientation="Vertical">
@ -289,27 +276,11 @@
<Style TargetType="StackPanel"
BasedOn="{StaticResource CopterInfo_StackPanel}" />
</StackPanel.Resources>
<StackPanel>
<TextBlock Text="电压:" />
<Slider x:Name="sldChannel3"
Width="75"
Minimum="1100"
Maximum="1900"
Value="{Binding Channel3, Mode=OneWay}"
ValueChanged="sldChannel3_ValueChanged">
<Slider.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.Blue.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Lime.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Slider.Resources>
</Slider>
<StackPanel Visibility="Hidden">
<TextBlock Text="电压值:" />
<TextBlock Text="{Binding Path=Voltage}" />
</StackPanel>
<StackPanel>
<TextBlock Text="电压值:" />
<TextBlock Text="{Binding Path=Voltage}" />
@ -331,29 +302,30 @@
<TextBlock Text="经度:" />
<TextBlock Text="{Binding Longitude}" />
</StackPanel>
<StackPanel>
<TextBlock Text="通道3" />
<TextBlock Text="{Binding Channel3}" />
</StackPanel>
<StackPanel>
<TextBlock Text="通道4" />
<TextBlock Text="{Binding Channel4}" />
</StackPanel>
<StackPanel>
<TextBlock Text="定位精度:" />
<TextBlock Text="{Binding GpsHdop, StringFormat=0.##}" />
</StackPanel>
<StackPanel>
<TextBlock Text="通信模块版本:" />
<TextBlock Text="{Binding CommModuleVersion}" />
</StackPanel>
<StackPanel>
<TextBlock Text="返回数据:" />
<StackPanel Margin="0,0,0,0" Height="14" ToolTip="{Binding RetainInt}">
<TextBlock Margin="0,-1,0,0" Text="{Binding Retain[3]}" />
<TextBlock Margin="0,-1,0,0" Text="." />
<TextBlock Margin="0,-1,0,0" Text="{Binding Retain[2]}" />
<TextBlock Margin="0,-1,0,0" Text="." />
<TextBlock Margin="0,-1,0,0" Text="{Binding Retain[1]}" />
<TextBlock Margin="0,-1,0,0" Text="." />
<TextBlock Margin="0,-1,0,0" Text="{Binding Retain[0]}" />
</StackPanel>
</StackPanel>
<StackPanel >
<TextBlock Text="最后异常:" />
<TextBlock Text="{Binding CopterErrorString}"/>
</StackPanel>
</StackPanel>
</Grid>
</StackPanel>
</UserControl>

View File

@ -74,9 +74,9 @@
/>
<Button Margin="0,5,5,0" Content="3D航线" Width="82" Command="{Binding OptimizeRouteCommand3D}"
/>
<Button Margin="0,5,5,0" Content="2D返航" Width="82" Command="{Binding OptimizeRouteCommandRet}"
<Button Margin="0,5,5,0" Content="2D对应" Width="82" Command="{Binding OptimizeRouteCommandRet}"
/>
<Button Margin="0,5,5,0" Content="3D返航" Width="82" Command="{Binding OptimizeRouteCommandRet3D}"
<Button Margin="0,5,5,0" Content="3D对应" Width="82" Command="{Binding OptimizeRouteCommandRet3D}"
/>