using Plane.Communication; using Plane.Geography; using System; using System.Diagnostics; using System.Drawing; using System.Threading; using System.Threading.Tasks; using static Plane.Copters.Constants; using System.Windows.Media; using Plane.CopterControllers; namespace Plane.Copters { /// /// 虚拟的 实现。 /// [DebuggerDisplay("Name={Name}")] public partial class FakeCopter : CopterImplSharedPart, IFakeCopter { /// /// 心跳间隔,单位为毫秒。 /// private const int HEARTBEAT_INTERVAL = 200; /// /// 更新虚拟飞行器状态的时间间隔,单位为毫秒。 /// static private int UPDATE_INTERVAL = 100; //默认100, i7电脑 150可以跑1000架 100可以跑500架 50可以200-300架 static private int UPDATE_INTERVAL_TEMP = 50; /// /// 在一个更新间隔中的最大移动距离。 /// private float MAX_MOVE_IN_INTERVAL = MAX_VEL * UPDATE_INTERVAL_TEMP / 1000; /// /// 高速模式下,在一个更新间隔中的最大移动距离。 /// private float MAX_MOVE_IN_INTERVAL_FAST = MAX_VEL * UPDATE_INTERVAL_TEMP / 1000 * 4; //MAX_MOVE_IN_INTERVAL*4 // private int _UPDATE_INTERVAL = 50; /// /// 对飞行器的模拟是否正在运行。 /// private bool _isRunning = false; /// /// 上次计算速度时的位置。 /// private ILocation _lastCalcSpeedPoint; /// /// 上次计算速度的时间。 /// private DateTime _lastCalcSpeedTime; /// /// 高速模式下,按比例缩放过的在一个更新间隔中的最大移动距离。 /// private float _scaledFastMaxMoveInInterval = MAX_VEL * UPDATE_INTERVAL_TEMP / 1000 * 4; //MAX_MOVE_IN_INTERVAL_FAST /// /// 按比例缩放过的在一个更新间隔中的最大移动距离。 /// private float _scaledMaxMoveInInterval = MAX_VEL * UPDATE_INTERVAL_TEMP / 1000; //MAX_MOVE_IN_INTERVAL /// /// 速度缩放比例。 /// private float _speedScale = 1; /// /// 自动起飞的目标高度。 /// private int _takeOffTargetAltitude; /// /// FlyTo 的目标高度。 /// private float _targetAlt; //航点开始高度 private float _startAlt; private float _Lng_delta; private float _Lat_delta; private float _flytime; private DateTime _startTicks; private float _distance_xy; private float _distance_z; private float _xy_speed; private float _z_speed; private int _flytype; private float currflytime; // 根据飞行时间计算飞行距离。 private float currdis_xy; private float currdis_z; // 目标点相对于开始位置的方向。 private double _direction; /// /// FlyTo 的目标纬度。 /// private double _targetLat; /// /// FlyTo 的目标经度。 /// private double _targetLng; /// /// FlyTo 的目标纬度。 /// private double _startLat; /// /// FlyTo 的目标经度。 /// private double _startLng; /// /// FlyTo 的目标经度。 /// private bool _ShowLED; private System.Drawing.ColorConverter rgbconverter; private PLLocation _takeoffcentloc; private PLLocation _taskcentloc; private float _mindistance; private int _rettime; private bool _descending; int Emergency_Retstatus = 0; //返航路径第一个航点 PLLocation Emergency_firstloc; /// /// 使用 创建 实例。 /// public FakeCopter() : this(SynchronizationContext.Current) { } new public int sim_update_int { get { return UPDATE_INTERVAL; } set { //最大移动距离 MAX_MOVE_IN_INTERVAL = MAX_VEL * value / 1000; //快速模式最大移动距离 MAX_MOVE_IN_INTERVAL_FAST = MAX_MOVE_IN_INTERVAL * 4; //速度缩放后快速速度距离 _scaledFastMaxMoveInInterval = MAX_MOVE_IN_INTERVAL_FAST * _speedScale; //速度缩放后速度距离 _scaledMaxMoveInInterval = MAX_MOVE_IN_INTERVAL * _speedScale; Set(nameof(sim_update_int), ref UPDATE_INTERVAL, value); } } public Task DoCommandAckAsync(ushort command, byte result) { return TaskUtils.CompletedTask; } /// /// 创建 实例。 /// /// UI 线程的同步上下文。 /// 自动起飞时的目标高度。 /// 速度缩放比例。 public FakeCopter(SynchronizationContext uiSyncContext, int takeOffTargetAltitude = 10, float speedScale = 1, IConnection connection = null) : base(uiSyncContext) { Latitude = 23.155382266268134; Longitude = 113.45038586296141; Elevation = 20; this.PropertyChanged += (sender, e) => { switch (e.PropertyName) { case nameof(Altitude): Elevation = Altitude + 20; break; case nameof(IsUnlocked): if (IsUnlocked) { // 王海, 20151029, 在解锁时上次计算速度点、上次计算速度时刻。 _lastCalcSpeedPoint = new PLLocation { Latitude = Latitude, Longitude = Longitude, Altitude = Altitude }; _lastCalcSpeedTime = DateTime.Now; } break; } }; _takeOffTargetAltitude = takeOffTargetAltitude; _speedScale = speedScale; _scaledMaxMoveInInterval = MAX_MOVE_IN_INTERVAL * _speedScale; _scaledFastMaxMoveInInterval = MAX_MOVE_IN_INTERVAL_FAST * _speedScale; this.Connection = connection ?? EmptyConnection.Instance; _isRunning = true; // 持续计算并更新虚拟飞行器的状态。 // Task.Run(async () => Task.Factory.StartNew(async () => { while (_isRunning) { Update(); await TaskUtils.Delay(UPDATE_INTERVAL).ConfigureAwait(false); } } , TaskCreationOptions.LongRunning ); ++HeartbeatCount; GpsFixType = GpsFixType.Fix3D; GpsHdop = 1; IsGpsAccurate = true; HasSwitchedToGpsMode = true; GC_xy = new GuidController(); GC_z = new GuidController(); /* // 持续假装收到飞行器发来的心跳。 Task.Run(async () => { while (true) { if (_isRunning) { ++HeartbeatCount; IsCheckingConnection = false; if (HeartbeatCount >= 10) { // 收到若干个心跳之后,设置一下 GPS 相关属性。 GpsFixType = GpsFixType.Fix3D; GpsHdop = 1; IsGpsAccurate = true; HasSwitchedToGpsMode = true; } _uiSyncContext.Post(() => RaiseHeartbeatReceived(new HeartbeatReceivedEventArgs(HeartbeatCount))); } await TaskUtils.Delay(HEARTBEAT_INTERVAL).ConfigureAwait(false); } }); */ } public IConnection Connection { get; set; } public string Id { get; set; } private int ReturnToLaunchAltitude { get { return _takeOffTargetAltitude; } } private GuidController GC_xy; private GuidController GC_z; public Task ConnectAsync() { IsConnected = true; _isRunning = true; IsCheckingConnection = true; return TaskUtils.CompletedTask; } public Task DisconnectAsync() { IsConnected = false; _isRunning = false; IsCheckingConnection = false; return TaskUtils.CompletedTask; } private void BuildPath() { float taralt; //返航高度参数 float retalt = 15; if (_descending) { if (Altitude <= retalt) taralt = Altitude; else { float maxalt = Altitude - retalt; //降低一个随机高度,随机高度介于0和maxalt之间,也就是目标高度不要低于retalt, 防止飞机在同一高度飞行 taralt = (float)(Altitude - (new Random().NextDouble() * maxalt)); } Emergency_firstloc = new PLLocation(this.Latitude,this.Longitude, taralt); } else { //计算当前位置和起飞点的距离 float dis = (float)this.CalcDistance(TakeOffPoint.Latitude, TakeOffPoint.Longitude,Altitude); //随机水平飞行距离 float maxdis = (float)new Random().NextDouble() * dis; } } public Task EmergencyRetAsync(PLLocation takeoffcentloc, PLLocation taskcentloc, float mindistance, int rettime, bool descending) { _takeoffcentloc = takeoffcentloc; _taskcentloc = taskcentloc; _mindistance = mindistance; _rettime = rettime; _descending = descending; Emergency_Retstatus = 0; //计算返航路径 BuildPath(); Mode = FlightMode.EMERG_RTL; return TaskUtils.CompletedTask; } protected override Task FlyToCoreAsync(double lat, double lng, float alt, float flytime = 0, int flytype = 0) { if (!IsEmergencyHoverActive) { _targetLat = lat; _targetLng = lng; _targetAlt = alt; _startLat = Latitude; _startLng = Longitude ; _startAlt = Altitude; _direction = this.CalcDirection2D(lat, lng); _flytime = flytime*1000; //ms _startTicks = DateTime.Now; //ms _Lng_delta = (float)( Math.Sin(_direction) * GeographyUtils.CalcMetersToLngSpan(Latitude)); _Lat_delta =(float)( Math.Cos(_direction) * GeographyUtils.METERS_TO_LAT_SPAN); //计算xy和x方向距离 _distance_xy = (float)this.CalcDistance(lat, lng, Altitude); _distance_z = alt - Altitude; Console.WriteLine($"{this.Id}d:{_distance_xy},lat{this.Latitude},lng{this.Longitude },tlat:{lat}tlng:{lng}"); _flytype = flytype; // _xy_speed = _distance_xy / _flytime; // _z_speed = _distance_z / _flytime; GC_xy.initgetspeeddist(_flytype, _flytime / 1000, _distance_xy, acc_xy, maxspeed_xy); if (_targetAlt>Altitude ) GC_z.initgetspeeddist(_flytype, _flytime / 1000, _distance_z, acc_z, maxspeed_up); else GC_z.initgetspeeddist(_flytype, _flytime / 1000, _distance_z, acc_z, maxspeed_down); Mode = FlightMode.GUIDED; } return TaskUtils.CompletedTask; } public Task GetCopterDataAsync() { return TaskUtils.CompletedTask; } public Task GetParamAsync(string paramName, int millisecondsTimeout = Timeout.Infinite) { // TODO: 王海, 20150806, 实现仿真的 GetParamAsync。 return Task.FromResult(0f); } public Task LockAsync() { if (IsUnlocked) { IsUnlocked = false; } return TaskUtils.CompletedTask; } public Task LEDAsync() { return TaskUtils.CompletedTask; } public Task MotorTestAsync(int motor) { return TaskUtils.CompletedTask; } public override Task SetChannelsAsync() { Channel1 = DesiredChannel1 ?? Channel1; Channel2 = DesiredChannel2 ?? Channel2; Channel3 = DesiredChannel3 ?? Channel3; Channel4 = DesiredChannel4 ?? Channel4; Channel5 = DesiredChannel5 ?? Channel5; Channel6 = DesiredChannel6 ?? Channel6; Channel7 = DesiredChannel7 ?? Channel7; Channel8 = DesiredChannel8 ?? Channel8; return TaskUtils.CompletedTask; } public override Task SetMobileControlAsync() { Channel1 = DesiredChannel1 ?? Channel1; Channel2 = DesiredChannel2 ?? Channel2; Channel3 = DesiredChannel3 ?? Channel3; Channel4 = DesiredChannel4 ?? Channel4; Channel5 = DesiredChannel5 ?? Channel5; Channel6 = DesiredChannel6 ?? Channel6; Channel7 = DesiredChannel7 ?? Channel7; Channel8 = DesiredChannel8 ?? Channel8; Yaw = DesiredYaw ?? Yaw; Heading = (short)Yaw; return TaskUtils.CompletedTask; } //得到收到的总数据量 public void GetCommunicationNumber(out int recnumber, out int sendnumber) { recnumber = 0; sendnumber = 0; } //重设数据量 public void ResetCommunicationNumber() { } public async Task DoCommandAsync(int actionid, float p1, float p2, float p3, float p4, float p5, float p6, float p7) { await Task.Delay(50).ConfigureAwait(false); } public Task SetParamAsync(string paramName, float value, int millisecondsTimeout = Timeout.Infinite) { // TODO: 王海, 20150807, 实现仿真的 SetParamAsync。 return TaskUtils.CompletedTask; } public bool GetShowLEDAsync() { return _ShowLED; } public Task SetShowLEDAsync(bool Ledon) { _ShowLED = Ledon; RaiseLocationChanged(); return TaskUtils.CompletedTask; } public Task SetShowRGBLEDAsync(int RedValue, int GreenValue, int BlueValue) { return TaskUtils.CompletedTask; } public Task SetShowLEDFlashAsync(int Flashtype, int millisecondsTime) { bool Ledison; Ledison = GetShowLEDAsync(); if (!Ledison) { SetShowLEDAsync(true); Task.Delay(millisecondsTime).ConfigureAwait(false); SetShowLEDAsync(false); } else { SetShowLEDAsync(false); Task.Delay(millisecondsTime).ConfigureAwait(false); SetShowLEDAsync(true); } return TaskUtils.CompletedTask; } public void SetProperties( string id = null, //"Junqing's Drone", double? latitude = null, //23.14973333, double? longitude = null, //113.40974166, float? altitude = null, //0, string name = null, //"王海的飞行器", byte? batteryPer = null, //10, short? heading = null, //33, bool? isConnected = null, //true, float? pitch = null, //-70, float? roll = null, //28, byte? satCount = null, //6, float? airSpeed = null, //3.333, double? flightDistance = null, //100.388, double? flightDistance2D = null, // 100.88, TimeSpan? flightTimeSpan = null) { if (id != null) Id = id; if (name != null) Name = name; if (latitude != null) Latitude = latitude.Value; if (longitude != null) Longitude = longitude.Value; if (altitude != null) Altitude = altitude.Value; if (batteryPer != null) BatteryPer = batteryPer.Value; if (heading != null) Heading = heading.Value; if (isConnected != null) IsConnected = isConnected.Value; if (pitch != null) Pitch = pitch.Value; if (roll != null) Roll = roll.Value; if (satCount != null) SatCount = satCount.Value; if (airSpeed != null) AirSpeed = airSpeed.Value; if (flightDistance != null) FlightDistance = flightDistance.Value; if (flightDistance2D != null) FlightDistance2D = flightDistance2D.Value; if (flightTimeSpan != null) FlightTimeSpan = flightTimeSpan.Value; } public Task StartPairingAsync() { RaisePairingCompleted(new PairingCompletedEventArgs(true, 0, 0)); return TaskUtils.CompletedTask; } public Task StopPairingAsync() { return TaskUtils.CompletedTask; } public async Task TakeOffAsync(float alt) { await UnlockAsync().ConfigureAwait(false); _takeOffTargetAltitude = (int)alt; await TakeOffAsync().ConfigureAwait(false); } DateTime MissionStartTime; public Task MissionStartAsync(int hour_utc, int minute_utc, int second_utc, double Missionlng, double Missionlat) { MissionStartTime = DateTime.Now; TakeOffPoint = new PLLocation(Missionlat, Missionlng, 0); return TaskUtils.CompletedTask; } public async Task UnlockAsync() { if (!IsUnlocked) { await SetChannelsAsync( ch1: 1500, ch2: 1500, ch3: 1100, ch4: 1500 ).ConfigureAwait(false); if (await SetModeAsync(FlightMode.ALT_HOLD).ConfigureAwait(false)) { IsUnlocked = true; } } } /// /// 无论在不在紧急悬停状态下都可用的切换模式方法。 /// /// 模式。 /// 超时。 /// 成功与否。 internal override Task SetModeCoreAsync(FlightMode mode, int millisecondsTimeout = 5000) { Mode = mode; return Task.FromResult(true); } protected override void UpdateFlightDataIfNeeded() { //计算飞机距离,没必要 /* if (!TakeOffPoint.IsNullOrEmpty()) { FlightDistance = TakeOffPoint.CalcDistance(this); FlightDistance2D = TakeOffPoint.CalcDistance2D(this); } if (FlightTimeSpan.TotalSeconds > 0) { if (_lastCalcSpeedPoint.IsNullOrEmpty()) { if (!this.IsNullOrEmpty()) { _lastCalcSpeedPoint = new PLLocation(this); _lastCalcSpeedTime = DateTime.Now; } } else { var movedDistance = _lastCalcSpeedPoint.CalcDistance(this); var movedTime = DateTime.Now - _lastCalcSpeedTime; if (movedDistance >= 3 || movedTime.TotalSeconds >= 3) { var airSpeed = movedDistance / movedTime.TotalSeconds; if (airSpeed < 100) // 王海, 20151023, 速度过大时不正常,经纬度可能有错误。 { AirSpeed = (float)airSpeed; } //Windows.Messages.Message.Show(AirSpeed.ToString()); GroundSpeed = AirSpeed; _lastCalcSpeedPoint = new PLLocation(this); _lastCalcSpeedTime = DateTime.Now; } } } */ } private void MoveToPointImmediately(double lat, double lng, float alt) { Latitude = lat; Longitude = lng; Altitude = alt; Roll = 0; Pitch = 0; } public Task InjectGpsDataAsync(byte[] data, ushort length) { return TaskUtils.CompletedTask; } public static System.Drawing.Color GetRandomColor() { Random rand = new Random(); return System.Drawing.Color.FromArgb(rand.Next(256), rand.Next(256), rand.Next(256)); } private DateTime led_laston; private System.Drawing.Color Led_color; //更新显示颜色,根据设置的led参数 private void UpdateShowColor() { // 使用实例化的对象调用ConvertFromString //LEDShowColor = (System.Drawing.Color)converter.ConvertFromString("#" + LEDColor); // 创建ColorConverter实例用于颜色转换 if ( rgbconverter==null) rgbconverter=new System.Drawing.ColorConverter(); //简化版的颜色模拟 switch (LEDMode) { case 0: if (LEDColor != null) LEDShowColor = (System.Drawing.Color)rgbconverter.ConvertFromString("#" + LEDColor); else LEDShowColor = (System.Drawing.Color)rgbconverter.ConvertFromString("#FFFFFF"); break; //闪烁 case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: if (DateTime.Now.AddMilliseconds(-(LEDInterval*1000)) >= led_laston) { led_laston = DateTime.Now; if (LEDShowColor != System.Drawing.Color.Black) { LEDShowColor = System.Drawing.Color.Black; } else { if ((LEDMode == 1) || (LEDMode == 4) || (LEDMode == 5) || (LEDMode == 6) || (LEDMode == 7) || (LEDMode == 9) || (LEDMode == 11) || (LEDMode == 13)) LEDShowColor = (System.Drawing.Color)rgbconverter.ConvertFromString("#" + LEDColor); if ((LEDMode == 2)||(LEDMode == 3) || (LEDMode == 8) || (LEDMode == 10) || (LEDMode == 12) || (LEDMode == 14)) LEDShowColor = GetRandomColor(); } } break; } } private bool ReachedDestination(double destLat, double destLng, float destAlt) => this.CalcDistance(destLat, destLng, destAlt) < 0.1; /// /// 计算并更新虚拟飞行器状态。 /// private void Update() { if (IsUnlocked) { // 飞行器接触地面(只判断 Altitude <= 0)后,如果处于 LAND 模式或者保持 Channel3 < MIN_HOVER_CHANNEL,在一段时间后自动锁定。 if ((Mode == FlightMode.LAND || Channel3 < MIN_HOVER_CHANNEL) && Altitude <= 0) { Task.Run(async () => { for (int i = 0; i < 4000 / 20; i++) { await TaskUtils.Delay(20).ConfigureAwait(false); if ((Mode != FlightMode.LAND && Channel3 >= MIN_HOVER_CHANNEL) || !IsUnlocked) { return; } } IsUnlocked = false; }); } else { switch (Mode) { case FlightMode.ACRO: break; case FlightMode.AUTO: /* // 暂时只管起飞。以最大速度上升,直到达到目标高度。 if (Altitude < _takeOffTargetAltitude) { Altitude += _scaledMaxMoveInInterval; } else { Mode = FlightMode.LOITER; } */ break; case FlightMode.GUIDED: // 王海, 20160317, 指点时也能体感控制若干通道。 //考虑不更新这个,好像没必要-xu //UpdateWithChannels(); //UpdateWithDestination(_targetLat, _targetLng, _targetAlt); if (FlightControlMode==1) UpdateWithDestination_v2(_targetLat, _targetLng, _targetAlt); else UpdateWithDestination(_targetLat, _targetLng, _targetAlt); break; case FlightMode.STABILIZE: case FlightMode.ALT_HOLD: case FlightMode.LOITER: UpdateWithChannels(); break; case FlightMode.RTL: if (Altitude < ReturnToLaunchAltitude && !ReachedDestination(Latitude, Longitude, ReturnToLaunchAltitude)) { UpdateWithDestination(Latitude, Longitude, ReturnToLaunchAltitude); } else if (Altitude > ReturnToLaunchAltitude && !ReachedDestination(TakeOffPoint.Latitude, TakeOffPoint.Longitude, Altitude)) { UpdateWithDestination(TakeOffPoint.Latitude, TakeOffPoint.Longitude, Altitude); } else { UpdateWithDestination(TakeOffPoint.Latitude, TakeOffPoint.Longitude, ReturnToLaunchAltitude); } break; case FlightMode.CIRCLE: break; case FlightMode.POSITION: break; case FlightMode.LAND: // 王海, 20160317, 降落时也能体感控制若干通道。 UpdateWithChannels(); // 以最大速度降落,直到高度为 0。 if (Altitude > 0) { if (Altitude > _scaledMaxMoveInInterval) { Altitude -= _scaledMaxMoveInInterval; } else { Altitude = 0; } Roll = 0; Pitch = 0; } break; case FlightMode.OF_LOITER: break; case FlightMode.TOY: break; //紧急返航 case FlightMode.EMERG_RTL: switch(Emergency_Retstatus) { case 0: //等待返航 if ((DateTime.Now- MissionStartTime).TotalSeconds > _rettime) { Emergency_Retstatus = 1; //平飞或降落随机距离 FlyToCoreAsync(Emergency_firstloc.Latitude, Emergency_firstloc.Longitude, Emergency_firstloc.Altitude); //FlyToCoreAsync里面把模式改成了GUIDED,这里改回来 Mode = FlightMode.EMERG_RTL; } break; case 1: //返航阶段一:等待平飞或降落随机距离并到达,然后飞到起飞点上空 UpdateWithDestination(Emergency_firstloc.Latitude, Emergency_firstloc.Longitude, Emergency_firstloc.Altitude); if (ReachedDestination(Emergency_firstloc.Latitude, Emergency_firstloc.Longitude, Emergency_firstloc.Altitude)) { FlyToCoreAsync(TakeOffPoint.Latitude, TakeOffPoint.Longitude, Emergency_firstloc.Altitude); //FlyToCoreAsync里面把模式改成了GUIDED,这里改回来 Mode = FlightMode.EMERG_RTL; Emergency_Retstatus = 2; } break; case 2: //返航阶段二:等待到达起飞点上空,然后降落 UpdateWithDestination(TakeOffPoint.Latitude, TakeOffPoint.Longitude, Emergency_firstloc.Altitude); if (ReachedDestination(TakeOffPoint.Latitude, TakeOffPoint.Longitude, Emergency_firstloc.Altitude)) { FlyToCoreAsync(TakeOffPoint.Latitude, TakeOffPoint.Longitude, Emergency_firstloc.Altitude); //FlyToCoreAsync里面把模式改成了GUIDED,这里改回来 Mode = FlightMode.LAND; Emergency_Retstatus = 3; } break; case 3: //降落 break; } break; default: break; } //UpdateFlightDataIfNeeded(); } } else { // TODO: 王海, 20151228, 模拟空中锁定。 // 锁定时直接把速度设为 0。 AirSpeed = 0; } // UpdateShowColor(); _uiSyncContext.Post(() => { //位置变化需要在UI刷新 RaiseLocationChangedIfNeeded(); //高度变化需要在UI刷新 // RaiseAltitudeChangedIfNeeded(); //GPS数据用于显示 // RaiseDataStreamReceived(PDataStreamType.GPS_RAW_INT); //不考虑姿态 // RaiseAttitudeChanged(); }); } /// /// 根据各个通道值来更新位置、姿态等状态。 /// private void UpdateWithChannels() { var maxMove = Mode == FlightMode.LOITER ? _scaledMaxMoveInInterval : _scaledFastMaxMoveInInterval; var ch3Delta = Channel3 > MAX_HOVER_CHANNEL ? Channel3 - MAX_HOVER_CHANNEL : Channel3 < MIN_HOVER_CHANNEL ? Channel3 - MIN_HOVER_CHANNEL : 0; if (ch3Delta != 0) { // 更新相对高度。 Altitude = Math.Max(0, Altitude + maxMove * ch3Delta / MAX_CHANNEL_DELTA); } var yawRad = Yaw.DegToRad(); var metersToLocalLng = GeographyUtils.CalcMetersToLngSpan(Latitude); var ch1Delta = Channel1 > MAX_HOVER_CHANNEL ? Channel1 - MAX_HOVER_CHANNEL : Channel1 < MIN_HOVER_CHANNEL ? Channel1 - MIN_HOVER_CHANNEL : 0; var xDistance = maxMove * ch1Delta / MAX_CHANNEL_DELTA; if (ch1Delta != 0) { // 更新横滚方向的纬度和经度。 Latitude -= xDistance * Math.Sin(yawRad) * GeographyUtils.METERS_TO_LAT_SPAN; Longitude += xDistance * Math.Cos(yawRad) * metersToLocalLng; // 更新横滚姿态。 Roll = MAX_TILT_IN_FLIGHT * ch1Delta / MAX_CHANNEL_DELTA; } else { Roll = 0; } var ch2Delta = Channel2 > MAX_HOVER_CHANNEL ? Channel2 - MAX_HOVER_CHANNEL : Channel2 < MIN_HOVER_CHANNEL ? Channel2 - MIN_HOVER_CHANNEL : 0; var yDistance = maxMove * ch2Delta / MAX_CHANNEL_DELTA; if (ch2Delta != 0) { // 更新俯仰方向的纬度和经度。 Latitude -= yDistance * Math.Cos(yawRad) * GeographyUtils.METERS_TO_LAT_SPAN; Longitude -= yDistance * Math.Sin(yawRad) * metersToLocalLng; // 更新俯仰姿态。 Pitch = MAX_TILT_IN_FLIGHT * ch2Delta / MAX_CHANNEL_DELTA; } else { Pitch = 0; } } /// /// 根据目的地来更新位置、姿态等状态。 /// private void UpdateWithDestination(ILocation loc) { UpdateWithDestination(loc.Latitude, loc.Longitude, loc.Altitude); } /// /// 根据目的地来更新位置、姿态等状态。 /// private void UpdateWithDestination(double lat, double lng, float alt) { // 与目标点之间的距离。 var distance = this.CalcDistance(lat, lng, alt); // 距离已经很近,直接移动到目标点。 if (distance < _scaledMaxMoveInInterval) { MoveToPointImmediately(lat, lng, alt); return; } // 在空间中的移动距离。 var move = _scaledMaxMoveInInterval; // 竖直方向的移动距离。 var altDelta = (float)(move * (alt - Altitude) / distance); // 更新高度。 Altitude += altDelta; // 目标点相对于当前位置的方向。 // var direction = this.CalcDirection2D(lat, lng); // 水平面上的移动距离。 var moveInHorizontalPlane = Math.Sqrt(move * move - altDelta * altDelta); if (double.IsNaN(moveInHorizontalPlane)) { MoveToPointImmediately(lat, lng, alt); return; } // 更新纬度。 //Longitude += moveInHorizontalPlane * Math.Sin(direction) * GeographyUtils.CalcMetersToLngSpan(Latitude); Longitude += moveInHorizontalPlane * _Lng_delta; Latitude += moveInHorizontalPlane * _Lat_delta; // 更新经度。 //Latitude += moveInHorizontalPlane * Math.Cos(direction) * GeographyUtils.METERS_TO_LAT_SPAN; } //新版本小航点计算移动位置 private void UpdateWithDestination_v2(double lat, double lng, float alt) { //_flytime 总飞行时间 秒 //_startTicks 开始飞行时间ms // _distance_xy 米 // _distance_z 米 //当前飞行时间 if ((lat == Latitude) && (lng == Longitude) && (alt == Altitude)) return; currflytime =(float)( DateTime.Now -_startTicks).TotalMilliseconds;//实际飞行时间 ms //超时直接移动到目标点 if (currflytime >= _flytime) { MoveToPointImmediately(lat, lng, alt); return; } //if (currflytime > 13000) // return; // 根据飞行时间计算飞行距离 float vspeed = 0; GC_xy.getspeeddist(_flytype, _flytime / 1000, _distance_xy, currflytime / 1000, acc_xy,maxspeed_xy , out currdis_xy, out vspeed); if (alt> Altitude) GC_z.getspeeddist(_flytype, _flytime / 1000, _distance_z, currflytime / 1000, acc_z,maxspeed_up, out currdis_z, out vspeed); else GC_z.getspeeddist(_flytype, _flytime / 1000, _distance_z, currflytime / 1000, acc_z,maxspeed_down, out currdis_z, out vspeed); Console.WriteLine($"{this.Id}:time:{currflytime / 1000} to {currdis_z}"); // 距离已经很近,直接移动到目标点。 if ((Math.Abs(_distance_xy-currdis_xy) < 0.1)&& (Math.Abs(_distance_z - currdis_z) < 0.1)) { Console.WriteLine($"{this.Id} to tlat:{lat}tlng:{lng}"); MoveToPointImmediately(lat, lng, alt); return; } // 更新位置 Altitude = _startAlt+ currdis_z; Longitude = _startLng + currdis_xy*_Lng_delta; Latitude = _startLat + currdis_xy *_Lat_delta; } } }