Compare commits

...

26 Commits

Author SHA1 Message Date
15d4fa5011 Physics 2025-06-10 22:01:14 +03:00
4ff3c2c5da Update FormMain.Designer.cs 2025-06-10 18:27:19 +03:00
b4f2ecb18e +++ 2025-06-09 16:17:00 +03:00
fdbfd85180 +++ 2025-06-06 23:51:08 +03:00
c22f4d825d +++ 2025-06-06 23:33:18 +03:00
48c07bf59f === 2025-06-06 17:37:04 +03:00
3dcf30882a +++ 2025-06-06 14:59:22 +03:00
afece52bb2 +++ 2025-06-06 03:27:21 +03:00
72ea9fd6a6 +++ 2025-06-05 19:49:56 +03:00
a97e618695 +++ 2025-06-05 00:13:53 +03:00
2d56ea0ae1 www 2025-06-03 03:17:41 +03:00
89f4a186ff +++ 2025-05-26 04:47:47 +03:00
2b595ba585 + 2025-05-23 19:48:37 +03:00
3d39f7da12 + 2025-05-23 11:37:04 +03:00
3a462be82d + 2025-05-22 23:52:47 +03:00
90cec037eb update 2025-05-22 01:47:54 +03:00
e0f3e3db19 Add drone state window 2025-05-16 01:27:03 +03:00
7bf2553455 ;) 2025-04-27 20:04:11 +03:00
cdf8c18d9b Add real mode (bar) 2025-04-15 01:23:54 +03:00
376ce81a8a update 2025-04-12 01:10:12 +03:00
bac52d315b Update 2025-04-11 21:59:06 +03:00
64c0637e6a cpp 2025-04-11 14:56:04 +03:00
6aeb99968e update 2025-04-06 20:58:15 +03:00
21b60b7f4c update 2025-04-06 20:56:02 +03:00
da7f5a8404 update 2025-04-06 17:17:15 +03:00
fd2318cbf6 Удалить www.txt 2025-04-04 11:35:28 +00:00
37 changed files with 5443 additions and 228 deletions

3
.gitignore vendored
View File

@ -1,3 +1,4 @@
.vs/
obj/
bin/
bin/
x64/

View File

@ -1,21 +1,25 @@
using System.Runtime.InteropServices;
using DroneData;
using System.Diagnostics.Metrics;
using System.Drawing;
using System.Numerics;
using System.Runtime.InteropServices;
namespace DroneClient
{
internal class Drone
{
public struct DataOut
{
public float AccX, AccY, AccZ;
public float GyrX, GyrY, GyrZ;
public float PosX, PosY;
public float LaserRange;
}
public struct DataIn
{
public float MotorUL, MotorUR, MotorDL, MotorDR;
}
public float AccX, AccY, AccZ;
public float GyrX, GyrY, GyrZ;
public uint TimeAcc, TimeGyr;
public float PosX, PosY;
public float LaserRange;
public uint TimeRange;
public Vector2 OF = Vector2.Zero;
public float MotorUL, MotorUR, MotorDL, MotorDR;
public static byte[] getBytes(object data)
{
@ -58,5 +62,273 @@ namespace DroneClient
return mem;
}
private byte[] SendDataMotor4()
{
DroneData.DataMotor4 mot4 = new DroneData.DataMotor4();
mot4.Head.Size = Marshal.SizeOf(typeof(DroneData.DataMotor4));
mot4.Head.Mode = DroneData.DataMode.Response;
mot4.Head.Type = DroneData.DataType.DataMotor4;
mot4.UL = MotorUL;
mot4.UR = MotorUR;
mot4.DL = MotorDL;
mot4.DR = MotorDR;
return getBytes(mot4);
}
private byte[]? RecvDataAcc(byte[] data)
{
DroneData.DataAcc imu = (DroneData.DataAcc)fromBytes(data, typeof(DroneData.DataAcc));
AccX = imu.Acc.X; AccY = imu.Acc.Y; AccZ = imu.Acc.Z;
TimeAcc= imu.Time;
return new byte[0];
}
private byte[]? RecvDataGyr(byte[] data)
{
DroneData.DataGyr imu = (DroneData.DataGyr)fromBytes(data, typeof(DroneData.DataGyr));
GyrX = imu.Gyr.X; GyrY = imu.Gyr.Y; GyrZ = imu.Gyr.Z;
TimeGyr = imu.Time;
return new byte[0];
}
private byte[]? RecvDataRange(byte[] data)
{
DroneData.DataRange pos = (DroneData.DataRange)fromBytes(data, typeof(DroneData.DataRange));
LaserRange = pos.LiDAR;
TimeRange = pos.Time;
return new byte[0];
}
private byte[]? RecvDataLocal(byte[] data)
{
DroneData.DataLocal pos = (DroneData.DataLocal)fromBytes(data, typeof(DroneData.DataLocal));
PosX = pos.Local.X; PosY = pos.Local.Y;
return new byte[0];
}
private byte[]? RecvDataOF(byte[] data)
{
DroneData.DataOF of = (DroneData.DataOF)fromBytes(data, typeof(DroneData.DataOF));
OF.X = of.X;
OF.Y = of.Y;
return new byte[0];
}
private byte[]? ClientRequestResponse(DroneData.DataHead head, byte[] body)
{
byte[] zero = new byte[0];
switch (head.Type)
{
case DroneData.DataType.DataAcc:
{
if (head.Mode == DroneData.DataMode.Request)
{
// Запрос данных
// ... //
//
return zero;
}
else
{
// Пришли данные
return RecvDataAcc(body);
}
}
case DroneData.DataType.DataGyr:
{
if (head.Mode == DroneData.DataMode.Request)
{
// Запрос данных
// ... //
//
return zero;
}
else
{
// Пришли данные
return RecvDataGyr(body);
}
}
case DroneData.DataType.DataRange:
{
if (head.Mode == DroneData.DataMode.Request)
{
// Запрос данных
// ... //
//
return zero;
}
else
{
// Пришли данные
return RecvDataRange(body);
}
}
case DroneData.DataType.DataLocal:
{
if (head.Mode == DroneData.DataMode.Request)
{
// Запрос данных
// ... //
//
return zero;
}
else
{
// Пришли данные
return RecvDataLocal(body);
}
}
case DroneData.DataType.DataOF:
{
if (head.Mode == DroneData.DataMode.Request)
{
// Запрос данных
// ... //
//
return zero;
}
else
{
// Пришли данные
return RecvDataOF(body);
}
}
case DroneData.DataType.DataMotor4:
{
if (head.Mode == DroneData.DataMode.Request)
{
// Запрос данных
return SendDataMotor4();
}
else
{
// Пришли данные
// ... //
//
return zero;
}
}
}
return zero;
}
private const int DroneStreamCount = 512;
private byte[] DroneStreamData = new byte[DroneStreamCount];
private int DroneStreamIndex = 0;
private DroneData.DataHead DroneStreamHead = new DroneData.DataHead() { Mode = DroneData.DataMode.None, Size = 0, Type = DroneData.DataType.None };
public List<byte[]?>? DataStream(byte[]? data, int size)
{
List<byte[]?> ret = new List<byte[]?>();
if (data == null) return ret; // Последовательность не сформирована, ждать данных
if (size + DroneStreamIndex > DroneStreamCount) return null; // Ошибка переполнения, поток сломан (конец)
Array.Copy(data, 0, DroneStreamData, DroneStreamIndex, size);
DroneStreamIndex += size;
while (true)
{
if (DroneStreamHead.Size == 0) // Заголовок ещё не получен
{
if (DroneStreamIndex < DroneData.DataHead.StrLen) return ret; // Нечего слать
DroneStreamHead = (DroneData.DataHead)fromBytes(DroneStreamData, typeof(DroneData.DataHead));
}
if (DroneStreamHead.Size > DroneStreamIndex) break; // Пакет ещё не полный
byte[] body = new byte[DroneStreamHead.Size];
Array.Copy(DroneStreamData, 0, body, 0, DroneStreamHead.Size);
int shift = DroneStreamHead.Size;
DroneStreamIndex -= shift;
Array.Copy(DroneStreamData, shift, DroneStreamData, 0, DroneStreamIndex); // Сдвигаем массив влево, убрав использованные данные
DroneStreamHead.Size = 0; // Отменяем прошлый заголовок
ret.Add(ClientRequestResponse(DroneStreamHead, body));
}
return ret;
}
public byte[] SendReqest()
{
DroneData.DataHead acc = new DroneData.DataHead();
acc.Size = DroneData.DataHead.StrLen;
acc.Mode = DroneData.DataMode.Request;
acc.Type = DroneData.DataType.DataAcc;
DroneData.DataHead gyr = new DroneData.DataHead();
gyr.Size = DroneData.DataHead.StrLen;
gyr.Mode = DroneData.DataMode.Request;
gyr.Type = DroneData.DataType.DataGyr;
DroneData.DataHead range = new DroneData.DataHead();
range.Size = DroneData.DataHead.StrLen;
range.Mode = DroneData.DataMode.Request;
range.Type = DroneData.DataType.DataRange;
DroneData.DataHead local = new DroneData.DataHead();
local.Size = DroneData.DataHead.StrLen;
local.Mode = DroneData.DataMode.Request;
local.Type = DroneData.DataType.DataLocal;
DroneData.DataHead of = new DroneData.DataHead();
of.Size = DroneData.DataHead.StrLen;
of.Mode = DroneData.DataMode.Request;
of.Type = DroneData.DataType.DataOF;
List<byte[]> list = new List<byte[]>();
list.Add(getBytes(acc));
list.Add(getBytes(gyr));
list.Add(getBytes(range));
list.Add(getBytes(local));
list.Add(getBytes(of));
list.Add(SendDataMotor4());
int count = 0;
foreach (byte[] d in list) count += d.Length;
byte[] send = new byte[count];
count = 0;
foreach (byte[] d in list)
{
d.CopyTo(send, count);
count += d.Length;
}
return send;
}
}
}

123
DroneClient/DroneData.cs Normal file
View File

@ -0,0 +1,123 @@
using System.Runtime.InteropServices;
namespace DroneData
{
public enum DataMode : ushort
{
None = 0, Response = 1, Request = 2
};
public enum DataType : ushort
{
None = 0, Head = 1,
// Output
DataAcc = 1001, DataGyr = 1002, DataMag = 1003, DataRange = 1004, DataLocal = 1005, DataBar = 1006, DataOF = 1007,
// Input
DataMotor4 = 2001, DataMotor6 = 2002,
// State
DataQuat = 3001,
};
public struct DataHead
{
public int Size;
public DataMode Mode;
public DataType Type;
public uint Time; // Общее время
static public int StrLen = Marshal.SizeOf(typeof(DroneData.DataHead));
}
public struct XYZ { public float X, Y, Z; }
public struct DataAcc
{
public DataHead Head;
public XYZ Acc;
public uint Time; // Последнее время изменения данных
static public int StrLen = Marshal.SizeOf(typeof(DroneData.DataAcc));
}
public struct DataGyr
{
public DataHead Head;
public XYZ Gyr;
public uint Time; // Последнее время изменения данных
static public int StrLen = Marshal.SizeOf(typeof(DroneData.DataGyr));
}
public struct DataMag
{
public DataHead Head;
public XYZ Mag;
public uint Time; // Последнее время изменения данных
static public int StrLen = Marshal.SizeOf(typeof(DroneData.DataMag));
}
public struct DataRange
{
public DataHead Head;
public float LiDAR; // Датчик посадки
public uint Time; // Последнее время изменения данных
static public int StrLen = Marshal.SizeOf(typeof(DroneData.DataRange));
}
public struct DataLocal
{
public DataHead Head;
public XYZ Local; // Локальные координаты
public uint Time; // Последнее время изменения данных
static public int StrLen = Marshal.SizeOf(typeof(DroneData.DataLocal));
}
public struct DataBar
{
public DataHead Head;
public float Pressure; // Давление
public uint Time; // Последнее время изменения данных
static public int StrLen = Marshal.SizeOf(typeof(DroneData.DataBar));
}
public struct DataOF
{
public DataHead Head;
public float X, Y; // Угловой сдвиг
public uint Time; // Последнее время изменения данных
static public int StrLen = Marshal.SizeOf(typeof(DroneData.DataOF));
}
public struct DataMotor4
{
public DataHead Head;
public float UL, UR, DL, DR;
static public int StrLen = Marshal.SizeOf(typeof(DroneData.DataMotor4));
}
public struct DataMotor6
{
public DataHead Head;
public float UL, UR, LL, RR, DL, DR;
static public int StrLen = Marshal.SizeOf(typeof(DroneData.DataMotor6));
}
}

View File

@ -38,12 +38,14 @@
label3 = new Label();
label1 = new Label();
groupBox2 = new GroupBox();
label_time_acc = new Label();
label_Acc_Z = new Label();
label7 = new Label();
label_Acc_Y = new Label();
label5 = new Label();
label_Acc_X = new Label();
groupBox3 = new GroupBox();
label_time_gyr = new Label();
label_Gyr_Z = new Label();
label9 = new Label();
label_Gyr_Y = new Label();
@ -51,6 +53,7 @@
label_Gyr_X = new Label();
label13 = new Label();
groupBox4 = new GroupBox();
label_time_range = new Label();
label_Pos_L = new Label();
label6 = new Label();
label_Pos_Y = new Label();
@ -65,12 +68,22 @@
label_Pow = new Label();
button_ML = new Button();
button_MR = new Button();
groupBox5 = new GroupBox();
label_time_of = new Label();
label_OF_Y = new Label();
label17 = new Label();
label_OF_X = new Label();
label19 = new Label();
trackBar_Value = new TrackBar();
label4 = new Label();
groupBox1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)numericUpDown_Server_Port).BeginInit();
groupBox2.SuspendLayout();
groupBox3.SuspendLayout();
groupBox4.SuspendLayout();
((System.ComponentModel.ISupportInitialize)trackBar_Power).BeginInit();
groupBox5.SuspendLayout();
((System.ComponentModel.ISupportInitialize)trackBar_Value).BeginInit();
SuspendLayout();
//
// timer_Test
@ -89,7 +102,7 @@
groupBox1.Dock = DockStyle.Top;
groupBox1.Location = new Point(0, 0);
groupBox1.Name = "groupBox1";
groupBox1.Size = new Size(275, 80);
groupBox1.Size = new Size(446, 80);
groupBox1.TabIndex = 3;
groupBox1.TabStop = false;
groupBox1.Tag = "";
@ -156,6 +169,7 @@
//
// groupBox2
//
groupBox2.Controls.Add(label_time_acc);
groupBox2.Controls.Add(label_Acc_Z);
groupBox2.Controls.Add(label7);
groupBox2.Controls.Add(label_Acc_Y);
@ -164,11 +178,20 @@
groupBox2.Controls.Add(label1);
groupBox2.Location = new Point(6, 86);
groupBox2.Name = "groupBox2";
groupBox2.Size = new Size(78, 100);
groupBox2.Size = new Size(100, 118);
groupBox2.TabIndex = 5;
groupBox2.TabStop = false;
groupBox2.Text = "Acc";
//
// label_time_acc
//
label_time_acc.AutoSize = true;
label_time_acc.Location = new Point(6, 100);
label_time_acc.Name = "label_time_acc";
label_time_acc.Size = new Size(13, 15);
label_time_acc.TabIndex = 25;
label_time_acc.Text = "0";
//
// label_Acc_Z
//
label_Acc_Z.AutoSize = true;
@ -216,19 +239,29 @@
//
// groupBox3
//
groupBox3.Controls.Add(label_time_gyr);
groupBox3.Controls.Add(label_Gyr_Z);
groupBox3.Controls.Add(label9);
groupBox3.Controls.Add(label_Gyr_Y);
groupBox3.Controls.Add(label11);
groupBox3.Controls.Add(label_Gyr_X);
groupBox3.Controls.Add(label13);
groupBox3.Location = new Point(95, 86);
groupBox3.Location = new Point(112, 86);
groupBox3.Name = "groupBox3";
groupBox3.Size = new Size(78, 100);
groupBox3.Size = new Size(103, 118);
groupBox3.TabIndex = 6;
groupBox3.TabStop = false;
groupBox3.Text = "Gyr";
//
// label_time_gyr
//
label_time_gyr.AutoSize = true;
label_time_gyr.Location = new Point(3, 100);
label_time_gyr.Name = "label_time_gyr";
label_time_gyr.Size = new Size(13, 15);
label_time_gyr.TabIndex = 26;
label_time_gyr.Text = "0";
//
// label_Gyr_Z
//
label_Gyr_Z.AutoSize = true;
@ -285,19 +318,29 @@
//
// groupBox4
//
groupBox4.Controls.Add(label_time_range);
groupBox4.Controls.Add(label_Pos_L);
groupBox4.Controls.Add(label6);
groupBox4.Controls.Add(label_Pos_Y);
groupBox4.Controls.Add(label10);
groupBox4.Controls.Add(label_Pos_X);
groupBox4.Controls.Add(label14);
groupBox4.Location = new Point(188, 86);
groupBox4.Location = new Point(221, 86);
groupBox4.Name = "groupBox4";
groupBox4.Size = new Size(78, 100);
groupBox4.Size = new Size(103, 118);
groupBox4.TabIndex = 7;
groupBox4.TabStop = false;
groupBox4.Text = "Pos";
//
// label_time_range
//
label_time_range.AutoSize = true;
label_time_range.Location = new Point(6, 100);
label_time_range.Name = "label_time_range";
label_time_range.Size = new Size(13, 15);
label_time_range.TabIndex = 27;
label_time_range.Text = "0";
//
// label_Pos_L
//
label_Pos_L.AutoSize = true;
@ -437,11 +480,93 @@
button_MR.MouseDown += button_UU_MouseDown;
button_MR.MouseUp += button_UU_MouseUp;
//
// groupBox5
//
groupBox5.Controls.Add(label_time_of);
groupBox5.Controls.Add(label_OF_Y);
groupBox5.Controls.Add(label17);
groupBox5.Controls.Add(label_OF_X);
groupBox5.Controls.Add(label19);
groupBox5.Location = new Point(330, 86);
groupBox5.Name = "groupBox5";
groupBox5.Size = new Size(104, 118);
groupBox5.TabIndex = 24;
groupBox5.TabStop = false;
groupBox5.Text = "OF";
//
// label_time_of
//
label_time_of.AutoSize = true;
label_time_of.Location = new Point(6, 100);
label_time_of.Name = "label_time_of";
label_time_of.Size = new Size(13, 15);
label_time_of.TabIndex = 27;
label_time_of.Text = "0";
//
// label_OF_Y
//
label_OF_Y.AutoSize = true;
label_OF_Y.Location = new Point(19, 45);
label_OF_Y.Name = "label_OF_Y";
label_OF_Y.Size = new Size(13, 15);
label_OF_Y.TabIndex = 7;
label_OF_Y.Text = "0";
//
// label17
//
label17.AutoSize = true;
label17.Location = new Point(6, 45);
label17.Name = "label17";
label17.Size = new Size(17, 15);
label17.TabIndex = 6;
label17.Text = "Y:";
//
// label_OF_X
//
label_OF_X.AutoSize = true;
label_OF_X.Location = new Point(19, 19);
label_OF_X.Name = "label_OF_X";
label_OF_X.Size = new Size(13, 15);
label_OF_X.TabIndex = 5;
label_OF_X.Text = "0";
//
// label19
//
label19.AutoSize = true;
label19.Location = new Point(6, 19);
label19.Name = "label19";
label19.Size = new Size(17, 15);
label19.TabIndex = 4;
label19.Text = "X:";
//
// trackBar_Value
//
trackBar_Value.Location = new Point(349, 240);
trackBar_Value.Maximum = 100;
trackBar_Value.Minimum = 1;
trackBar_Value.Name = "trackBar_Value";
trackBar_Value.Orientation = Orientation.Vertical;
trackBar_Value.Size = new Size(45, 195);
trackBar_Value.TabIndex = 25;
trackBar_Value.Value = 1;
//
// label4
//
label4.AutoSize = true;
label4.Location = new Point(347, 219);
label4.Name = "label4";
label4.Size = new Size(47, 15);
label4.TabIndex = 26;
label4.Text = "POWER";
//
// Form_Main
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(275, 447);
ClientSize = new Size(446, 447);
Controls.Add(label4);
Controls.Add(trackBar_Value);
Controls.Add(groupBox5);
Controls.Add(button_MR);
Controls.Add(button_ML);
Controls.Add(label_Pow);
@ -468,6 +593,9 @@
groupBox4.ResumeLayout(false);
groupBox4.PerformLayout();
((System.ComponentModel.ISupportInitialize)trackBar_Power).EndInit();
groupBox5.ResumeLayout(false);
groupBox5.PerformLayout();
((System.ComponentModel.ISupportInitialize)trackBar_Value).EndInit();
ResumeLayout(false);
PerformLayout();
}
@ -509,5 +637,16 @@
private Label label_Pow;
private Button button_ML;
private Button button_MR;
private Label label4;
private Label label_time_acc;
private Label label_time_range;
private Label label_time_gyr;
private GroupBox groupBox5;
private Label label_time_of;
private Label label_OF_Y;
private Label label17;
private Label label_OF_X;
private Label label19;
private TrackBar trackBar_Value;
}
}

View File

@ -1,4 +1,4 @@
using System.Text;
using System.Text;
using System.Numerics;
using System.Windows.Forms;
using static DroneSimulator.NetClient;
@ -21,34 +21,37 @@ namespace DroneSimulator
if (!data.Connect)
{
Invoke((MethodInvoker)delegate
try
{
button_Connect.Text = "Connect";
button_Connect.BackColor = Color.Transparent;
MessageBox.Show("Connection closed");
});
Invoke((MethodInvoker)delegate
{
button_Connect.Text = "Connect";
button_Connect.BackColor = Color.Transparent;
MessageBox.Show("Connection closed");
});
}
catch { }
return;
}
byte[] send = Drone.getBytes(sendDrone);
data.Server.Send(send);
}
Drone.DataIn sendDrone;
Drone.DataOut recvDrone;
Drone dataDrone = new Drone();
private void ReceiveCallback(object o)
{
ReceiveData data = (ReceiveData)o;
recvDrone = (Drone.DataOut)Drone.fromBytes(data.Buffer, typeof(Drone.DataOut));
List<byte[]?>? send = dataDrone.DataStream(data.Buffer, data.Size);
byte[] send = Drone.getBytes(sendDrone);
try { data.Server.Send(send); }
if (send == null) return;
try
{
foreach (byte[]? b in send)
{
if (b != null) data.Server?.Send(b);
}
}
catch { }
}
@ -88,17 +91,30 @@ namespace DroneSimulator
private void timer_Test_Tick(object sender, EventArgs e)
{
label_Acc_X.Text = recvDrone.AccX.ToString();
label_Acc_Y.Text = recvDrone.AccY.ToString();
label_Acc_Z.Text = recvDrone.AccZ.ToString();
label_Acc_X.Text = dataDrone.AccX.ToString();
label_Acc_Y.Text = dataDrone.AccY.ToString();
label_Acc_Z.Text = dataDrone.AccZ.ToString();
label_Gyr_X.Text = recvDrone.GyrX.ToString();
label_Gyr_Y.Text = recvDrone.GyrY.ToString();
label_Gyr_Z.Text = recvDrone.GyrZ.ToString();
label_time_acc.Text = dataDrone.TimeAcc.ToString();
label_Pos_X.Text = recvDrone.PosX.ToString();
label_Pos_Y.Text = recvDrone.PosY.ToString();
label_Pos_L.Text = recvDrone.LaserRange.ToString();
label_Gyr_X.Text = dataDrone.GyrX.ToString();
label_Gyr_Y.Text = dataDrone.GyrY.ToString();
label_Gyr_Z.Text = dataDrone.GyrZ.ToString();
label_time_gyr.Text = dataDrone.TimeGyr.ToString();
label_Pos_X.Text = dataDrone.PosX.ToString();
label_Pos_Y.Text = dataDrone.PosY.ToString();
label_Pos_L.Text = dataDrone.LaserRange.ToString();
label_time_range.Text = dataDrone.TimeRange.ToString();
label_OF_X.Text = dataDrone.OF.X.ToString();
label_OF_Y.Text = dataDrone.OF.Y.ToString();
label_time_of.Text = dataDrone.TimeRange.ToString();
netClient.SendData(dataDrone.SendReqest());
}
private void trackBar_Power_Scroll(object sender, EventArgs e)
@ -107,44 +123,44 @@ namespace DroneSimulator
label_Pow.Text = pow.ToString();
sendDrone.MotorUL = sendDrone.MotorUR = sendDrone.MotorDL = sendDrone.MotorDR = pow;
dataDrone.MotorUL = dataDrone.MotorUR = dataDrone.MotorDL = dataDrone.MotorDR = pow;
}
private void button_UU_MouseDown(object sender, MouseEventArgs e)
{
const float pow = 0.1f;
float pow = ((float)trackBar_Value.Value) / 10.0f;
if (sender == button_UU)
{
sendDrone.MotorUL -= pow; sendDrone.MotorUR -= pow;
sendDrone.MotorDL += pow; sendDrone.MotorDR += pow;
dataDrone.MotorUL -= pow; dataDrone.MotorUR -= pow;
dataDrone.MotorDL += pow; dataDrone.MotorDR += pow;
}
if (sender == button_DD)
{
sendDrone.MotorUL += pow; sendDrone.MotorUR += pow;
sendDrone.MotorDL -= pow; sendDrone.MotorDR -= pow;
dataDrone.MotorUL += pow; dataDrone.MotorUR += pow;
dataDrone.MotorDL -= pow; dataDrone.MotorDR -= pow;
}
if (sender == button_LL)
{
sendDrone.MotorUL -= pow; sendDrone.MotorUR += pow;
sendDrone.MotorDL -= pow; sendDrone.MotorDR += pow;
dataDrone.MotorUL -= pow; dataDrone.MotorUR += pow;
dataDrone.MotorDL -= pow; dataDrone.MotorDR += pow;
}
if (sender == button_RR)
{
sendDrone.MotorUL += pow; sendDrone.MotorUR -= pow;
sendDrone.MotorDL += pow; sendDrone.MotorDR -= pow;
dataDrone.MotorUL += pow; dataDrone.MotorUR -= pow;
dataDrone.MotorDL += pow; dataDrone.MotorDR -= pow;
}
if (sender == button_ML)
{
sendDrone.MotorUL -= pow; sendDrone.MotorUR += pow;
sendDrone.MotorDL += pow; sendDrone.MotorDR -= pow;
dataDrone.MotorUL -= pow; dataDrone.MotorUR += pow;
dataDrone.MotorDL += pow; dataDrone.MotorDR -= pow;
}
if (sender == button_MR)
{
sendDrone.MotorUL += pow; sendDrone.MotorUR -= pow;
sendDrone.MotorDL -= pow; sendDrone.MotorDR += pow;
dataDrone.MotorUL += pow; dataDrone.MotorUR -= pow;
dataDrone.MotorDL -= pow; dataDrone.MotorDR += pow;
}
}

View File

@ -41,9 +41,7 @@ namespace DroneSimulator
{
if (Connected)
{
try { ServerSocket?.Shutdown(SocketShutdown.Both); } catch { }
ServerSocket?.Close();
Connected = false;
Close();
return ClientState.Stop;
}
@ -99,5 +97,10 @@ namespace DroneSimulator
try { ServerSocket?.BeginReceive(cd.Buffer, 0, ServerData.size, 0, new AsyncCallback(ReadCallback), cd); }
catch { }
}
public void SendData(byte[] data)
{
try { ServerSocket?.Send(data); } catch { }
}
}
}

106
DroneClientCpp/Client.cpp Normal file
View File

@ -0,0 +1,106 @@
#pragma once
#include "Client.h"
Client::Client(const char* ip, int port) : running(true), Connection(INVALID_SOCKET)
{
if (!ConnectToServer(ip, port))
{
std::cerr << "Failed to connect to server!" << std::endl;
}
}
Client::~Client()
{
Stop();
CloseConnection();
}
bool Client::ConnectToServer(const char* ip, int port)
{
WSAData wsaData;
WORD DLLVersion = MAKEWORD(2, 2);
if (WSAStartup(DLLVersion, &wsaData) != 0)
{
std::cerr << "Error: WSAStartup failed" << std::endl;
return false;
}
SOCKADDR_IN addr;
inet_pton(AF_INET, ip, &addr.sin_addr);
addr.sin_port = htons(port);
addr.sin_family = AF_INET;
Connection = socket(AF_INET, SOCK_STREAM, 0);
if (Connection == INVALID_SOCKET)
{
std::cerr << "Error: Failed to create socket" << std::endl;
WSACleanup();
return false;
}
if (connect(Connection, (SOCKADDR*)&addr, sizeof(addr)) != 0)
{
std::cerr << "Error: Failed to connect to server" << std::endl;
closesocket(Connection);
WSACleanup();
return false;
}
return true;
}
void Client::CloseConnection()
{
if (Connection != INVALID_SOCKET)
{
closesocket(Connection);
WSACleanup();
Connection = INVALID_SOCKET;
}
}
void Client::ReceiveHandler()
{
while (running)
{
DataIn tempData;
int result = recv(Connection, (char*)&tempData, sizeof(tempData), 0);
if (result <= 0)
{
std::cerr << "Error: Connection lost (recv failed)" << std::endl;
running = false;
break;
}
std::lock_guard<std::mutex> lock(dataMutex);
dataIn = tempData;
}
}
void Client::SendHandler()
{
while (running)
{
{
std::lock_guard<std::mutex> lock(dataMutex);
send(Connection, (char*)&dataOut, sizeof(dataOut), 0);
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
void Client::Start()
{
recvThread = std::thread(&Client::ReceiveHandler, this);
sendThread = std::thread(&Client::SendHandler, this);
}
void Client::Stop()
{
running = false;
if (recvThread.joinable()) recvThread.join();
if (sendThread.joinable()) sendThread.join();
}

44
DroneClientCpp/Client.h Normal file
View File

@ -0,0 +1,44 @@
#pragma once
#include <iostream>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <thread>
#include <atomic>
#include <mutex>
#pragma comment(lib, "Ws2_32.lib")
class Client
{
public:
Client(const char* ip, int port);
~Client();
void Start(); // Запуск потоков
void Stop(); // Остановка потоков
struct DataIn
{
float AccX, AccY, AccZ;
float GyrX, GyrY, GyrZ;
float PosX, PosY, LaserRange;
} dataIn;
struct DataOut
{
float MotorUL, MotorUR, MotorDL, MotorDR;
} dataOut;
bool ConnectToServer(const char* ip, int port);
void CloseConnection();
private:
std::atomic<bool> running;
std::mutex dataMutex;
SOCKET Connection;
std::thread recvThread;
std::thread sendThread;
void ReceiveHandler();
void SendHandler();
};

255
DroneClientCpp/Drone.cpp Normal file
View File

@ -0,0 +1,255 @@
#include "Drone.h"
namespace DroneClient {
// Реализация статического метода GetBytes
array<Byte>^ Drone::GetBytes(Object^ data)
{
int size = Marshal::SizeOf(data);
array<Byte>^ arr = gcnew array<Byte>(size);
IntPtr ptr = IntPtr::Zero;
try
{
ptr = Marshal::AllocHGlobal(size);
Marshal::StructureToPtr(data, ptr, true);
Marshal::Copy(ptr, arr, 0, size);
}
finally
{
Marshal::FreeHGlobal(ptr);
}
return arr;
}
// Реализация статического метода FromBytes
Object^ Drone::FromBytes(array<Byte>^ arr, Type^ type)
{
Object^ mem = gcnew Object();
int size = Marshal::SizeOf(type);
IntPtr ptr = IntPtr::Zero;
try
{
ptr = Marshal::AllocHGlobal(size);
Marshal::Copy(arr, 0, ptr, size);
mem = Marshal::PtrToStructure(ptr, type);
}
finally
{
Marshal::FreeHGlobal(ptr);
}
return mem;
}
// Реализация приватного метода SendDataMotor4
array<Byte>^ Drone::SendDataMotor4()
{
DroneData::DataMotor4 mot4;
mot4.Head.Size = Marshal::SizeOf(DroneData::DataMotor4::typeid);
mot4.Head.Mode = DroneData::DataMode::Response;
mot4.Head.Type = DroneData::DataType::DataMotor4;
mot4.UL = MotorUL;
mot4.UR = MotorUR;
mot4.DL = MotorDL;
mot4.DR = MotorDR;
return GetBytes(mot4);
}
array<Byte>^ Drone::RecvDataAcc(array<Byte>^ data)
{
DroneData::DataAcc imu = (DroneData::DataAcc)FromBytes(data, DroneData::DataAcc::typeid);
AccX = imu.Acc.X; AccY = imu.Acc.Y; AccZ = imu.Acc.Z;
TimeAcc = imu.Time;
return gcnew array<Byte>(0);
}
array<Byte>^ Drone::RecvDataGyr(array<Byte>^ data)
{
DroneData::DataGyr imu = (DroneData::DataGyr)FromBytes(data, DroneData::DataGyr::typeid);
GyrX = imu.Gyr.X; GyrY = imu.Gyr.Y; GyrZ = imu.Gyr.Z;
TimeGyr = imu.Time;
return gcnew array<Byte>(0);
}
array<Byte>^ Drone::RecvDataRange(array<Byte>^ data)
{
DroneData::DataRange pos = (DroneData::DataRange)FromBytes(data, DroneData::DataRange::typeid);
LaserRange = pos.LiDAR;
TimeRange = pos.Time;
return gcnew array<Byte>(0);
}
array<Byte>^ Drone::RecvDataLocal(array<Byte>^ data)
{
DroneData::DataLocal pos = (DroneData::DataLocal)FromBytes(data, DroneData::DataLocal::typeid);
PosX = pos.Local.X; PosY = pos.Local.Y;
return gcnew array<Byte>(0);
}
array<Byte>^ Drone::ClientRequestResponse(DroneData::DataHead head, array<Byte>^ body)
{
array<Byte>^ zero = gcnew array<Byte>(0);
switch (head.Type)
{
case DroneData::DataType::DataAcc:
if (head.Mode == DroneData::DataMode::Request)
{
return zero; // Запрос данных (не реализовано)
}
else
{
return RecvDataAcc(body); // Пришли данные
}
case DroneData::DataType::DataGyr:
if (head.Mode == DroneData::DataMode::Request)
{
return zero; // Запрос данных (не реализовано)
}
else
{
return RecvDataGyr(body); // Пришли данные
}
case DroneData::DataType::DataRange:
if (head.Mode == DroneData::DataMode::Request)
{
return zero; // Запрос данных (не реализовано)
}
else
{
return RecvDataRange(body); // Пришли данные
}
case DroneData::DataType::DataLocal:
if (head.Mode == DroneData::DataMode::Request)
{
return zero; // Запрос данных (не реализовано)
}
else
{
return RecvDataLocal(body); // Пришли данные
}
case DroneData::DataType::DataMotor4:
if (head.Mode == DroneData::DataMode::Request)
{
return SendDataMotor4(); // Запрос данных
}
else
{
return zero; // Пришли данные (не реализовано)
}
}
return zero;
}
// Реализация конструктора
Drone::Drone()
{
DroneStreamData = gcnew array<Byte>(DroneStreamCount); // Инициализация массива
DroneStreamIndex = 0;
DroneStreamHead.Mode = DroneData::DataMode::None;
DroneStreamHead.Size = 0;
DroneStreamHead.Type = DroneData::DataType::None;
}
// Реализация метода DataStream
List<array<Byte>^>^ Drone::DataStream(array<Byte>^ data, int size)
{
System::Collections::Generic::List<array<Byte>^>^ ret = gcnew System::Collections::Generic::List<array<Byte>^>();
if (data == nullptr) return ret; // Последовательность не сформирована
if (size + DroneStreamIndex > DroneStreamCount) return nullptr; // Ошибка переполнения
Array::Copy(data, 0, DroneStreamData, DroneStreamIndex, size);
DroneStreamIndex += size;
while (true)
{
if (DroneStreamHead.Size == 0) // Заголовок еще не получен
{
if (DroneStreamIndex < DroneData::DataHead::StrLen) return ret;
DroneStreamHead = (DroneData::DataHead)FromBytes(DroneStreamData, DroneData::DataHead::typeid);
}
if (DroneStreamHead.Size > DroneStreamIndex) break; // Пакет еще не полный
array<Byte>^ body = gcnew array<Byte>(DroneStreamHead.Size);
Array::Copy(DroneStreamData, 0, body, 0, DroneStreamHead.Size);
int shift = DroneStreamHead.Size;
DroneStreamIndex -= shift;
Array::Copy(DroneStreamData, shift, DroneStreamData, 0, DroneStreamIndex); // Сдвиг массива
DroneStreamHead.Size = 0; // Сброс заголовка
ret->Add(ClientRequestResponse(DroneStreamHead, body));
}
return ret;
}
// Реализация метода SendRequest
array<Byte>^ Drone::SendRequest()
{
DroneData::DataHead^ acc = gcnew DroneData::DataHead();
acc->Size = DroneData::DataHead::StrLen;
acc->Mode = DroneData::DataMode::Request;
acc->Type = DroneData::DataType::DataAcc;
DroneData::DataHead^ gyr = gcnew DroneData::DataHead();
gyr->Size = DroneData::DataHead::StrLen;
gyr->Mode = DroneData::DataMode::Request;
gyr->Type = DroneData::DataType::DataGyr;
DroneData::DataHead^ range = gcnew DroneData::DataHead();
range->Size = DroneData::DataHead::StrLen;
range->Mode = DroneData::DataMode::Request;
range->Type = DroneData::DataType::DataRange;
DroneData::DataHead^ local = gcnew DroneData::DataHead();
local->Size = DroneData::DataHead::StrLen;
local->Mode = DroneData::DataMode::Request;
local->Type = DroneData::DataType::DataLocal;
List<array<byte>^>^ list = gcnew List<array<byte>^>();
list->Add(GetBytes(acc));
list->Add(GetBytes(gyr));
list->Add(GetBytes(range));
list->Add(GetBytes(local));
list->Add(SendDataMotor4());
int count = 0;
for each(array<byte>^ d in list) count += d->Length;
array<byte>^ send = gcnew array<byte>(count);
count = 0;
for each (array<byte> ^ d in list)
{
d->CopyTo(send, count);
count += d->Length;
}
return send;
}
}

51
DroneClientCpp/Drone.h Normal file
View File

@ -0,0 +1,51 @@
#pragma once
#include "DroneData.h"
#include <Windows.h>
#include <vcclr.h>
#using <System.dll>
#using <mscorlib.dll>
using namespace System;
using namespace System::Collections::Generic;
using namespace System::Runtime::InteropServices;
namespace DroneClient {
public ref class Drone
{
public:
float AccX, AccY, AccZ;
float GyrX, GyrY, GyrZ;
unsigned int TimeAcc, TimeGyr;
float PosX, PosY;
float LaserRange;
unsigned int TimeRange;
float MotorUL, MotorUR, MotorDL, MotorDR;
static array<Byte>^ GetBytes(Object^ data);
static Object^ FromBytes(array<Byte>^ arr, Type^ type);
private:
array<Byte>^ SendDataMotor4();
array<Byte>^ RecvDataAcc(array<Byte>^ data);
array<Byte>^ RecvDataGyr(array<Byte>^ data);
array<Byte>^ RecvDataRange(array<Byte>^ data);
array<Byte>^ RecvDataLocal(array<Byte>^ data);
array<Byte>^ ClientRequestResponse(DroneData::DataHead head, array<Byte>^ body);
literal int DroneStreamCount = 512;
array<Byte>^ DroneStreamData;
int DroneStreamIndex;
DroneData::DataHead DroneStreamHead;
public:
Drone(); // Конструктор для инициализации
System::Collections::Generic::List<array<Byte>^>^ DataStream(array<Byte>^ data, int size);
array<Byte>^ SendRequest();
};
}

View File

@ -0,0 +1,65 @@
#pragma once
#include <Windows.h>
#include <vcclr.h>
#using <System.dll>
#using <mscorlib.dll>
using namespace System;
using namespace System::Runtime::InteropServices;
namespace DroneClient {
public ref class Drone
{
public:
value struct DataOut
{
float AccX, AccY, AccZ;
float GyrX, GyrY, GyrZ;
float PosX, PosY;
float LaserRange;
};
value struct DataIn
{
float MotorUL, MotorUR, MotorDL, MotorDR;
};
static array<Byte>^ GetBytes(Object^ data)
{
int size = Marshal::SizeOf(data);
array<Byte>^ arr = gcnew array<Byte>(size);
IntPtr ptr = IntPtr::Zero;
try
{
ptr = Marshal::AllocHGlobal(size);
Marshal::StructureToPtr(data, ptr, true);
Marshal::Copy(ptr, arr, 0, size);
}
finally
{
Marshal::FreeHGlobal(ptr);
}
return arr;
}
static Object^ FromBytes(array<Byte>^ arr, Type^ type)
{
int size = Marshal::SizeOf(type);
IntPtr ptr = IntPtr::Zero;
try
{
ptr = Marshal::AllocHGlobal(size);
Marshal::Copy(arr, 0, ptr, size);
return Marshal::PtrToStructure(ptr, type);
}
finally
{
Marshal::FreeHGlobal(ptr);
}
}
};
}

View File

@ -0,0 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.12.35527.113
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DroneClientCpp", "DroneClientCpp.vcxproj", "{690C304C-A70B-4B0F-BF61-8C51290BF444}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{690C304C-A70B-4B0F-BF61-8C51290BF444}.Debug|x64.ActiveCfg = Debug|x64
{690C304C-A70B-4B0F-BF61-8C51290BF444}.Debug|x64.Build.0 = Debug|x64
{690C304C-A70B-4B0F-BF61-8C51290BF444}.Debug|x86.ActiveCfg = Debug|Win32
{690C304C-A70B-4B0F-BF61-8C51290BF444}.Debug|x86.Build.0 = Debug|Win32
{690C304C-A70B-4B0F-BF61-8C51290BF444}.Release|x64.ActiveCfg = Release|x64
{690C304C-A70B-4B0F-BF61-8C51290BF444}.Release|x64.Build.0 = Release|x64
{690C304C-A70B-4B0F-BF61-8C51290BF444}.Release|x86.ActiveCfg = Release|Win32
{690C304C-A70B-4B0F-BF61-8C51290BF444}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<ProjectGuid>{690C304C-A70B-4B0F-BF61-8C51290BF444}</ProjectGuid>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<Keyword>ManagedCProj</Keyword>
<RootNamespace>DroneClientCpp</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CLRSupport>true</CLRSupport>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CLRSupport>true</CLRSupport>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CLRSupport>true</CLRSupport>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CLRSupport>true</CLRSupport>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<AdditionalDependencies />
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<AdditionalDependencies />
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<AdditionalDependencies />
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<AdditionalDependencies />
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Drone.cpp" />
<ClCompile Include="FormMain.cpp" />
<ClCompile Include="NetClient.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Drone.h" />
<ClInclude Include="DroneData.h" />
<ClInclude Include="FormMain.h">
<FileType>CppForm</FileType>
</ClInclude>
<ClInclude Include="NetClient.h" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="FormMain.resx">
<DependentUpon>FormMain.h</DependentUpon>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Исходные файлы">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Файлы заголовков">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Файлы ресурсов">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="FormMain.cpp">
<Filter>Исходные файлы</Filter>
</ClCompile>
<ClCompile Include="NetClient.cpp">
<Filter>Исходные файлы</Filter>
</ClCompile>
<ClCompile Include="Drone.cpp">
<Filter>Исходные файлы</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="FormMain.h">
<Filter>Файлы заголовков</Filter>
</ClInclude>
<ClInclude Include="NetClient.h">
<Filter>Файлы заголовков</Filter>
</ClInclude>
<ClInclude Include="DroneData.h">
<Filter>Файлы заголовков</Filter>
</ClInclude>
<ClInclude Include="Drone.h">
<Filter>Файлы заголовков</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>

117
DroneClientCpp/DroneData.h Normal file
View File

@ -0,0 +1,117 @@
#pragma once
#include <Windows.h>
#include <vcclr.h>
using namespace System;
using namespace System::Runtime::InteropServices;
namespace DroneData {
public enum class DataMode : unsigned short
{
None = 0, Response = 1, Request = 2
};
public enum class DataType : unsigned short
{
None = 0, Head = 1,
// Output
DataAcc = 1001, DataGyr = 1002, DataMag = 1003, DataRange = 1004, DataLocal = 1005,
// Input
DataMotor4 = 2001, DataMotor6 = 2002
};
public value struct DataHead
{
public:
long Size;
DataMode Mode;
DataType Type;
unsigned long Time;
static const int StrLen = sizeof(DataHead);
};
public value struct XYZ
{
public:
float X, Y, Z;
};
public value struct DataAcc
{
public:
DataHead Head;
XYZ Acc;
unsigned long Time;
static const int StrLen = sizeof(DataAcc);
};
public value struct DataGyr
{
public:
DataHead Head;
XYZ Gyr;
unsigned long Time;
static const int StrLen = sizeof(DataGyr);
};
public value struct DataMag
{
public:
DataHead Head;
XYZ Mag;
unsigned long Time;
static const int StrLen = sizeof(DataMag);
};
public value struct DataRange
{
public:
DataHead Head;
float LiDAR;
unsigned long Time;
static const int StrLen = sizeof(DataRange);
};
public value struct DataLocal
{
public:
DataHead Head;
XYZ Local;
unsigned long Time;
static const int StrLen = sizeof(DataLocal);
};
public value struct DataMotor4
{
public:
DataHead Head;
float UL, UR, DL, DR;
static const int StrLen = sizeof(DataMotor4);
};
public value struct DataMotor6
{
public:
DataHead Head;
float UL, UR, LL, RR, DL, DR;
static const int StrLen = sizeof(DataMotor6);
};
}

View File

@ -0,0 +1,12 @@
#include "FormMain.h"
#include <Windows.h>
using namespace DroneClientCpp;
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
Application::EnableVisualStyles();
Application::SetCompatibleTextRenderingDefault(false);
Application::Run(gcnew FormMain);
return 0;
}

BIN
DroneClientCpp/FormMain.h Normal file

Binary file not shown.

View File

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="backgroundWorker1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="timer1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>310, 17</value>
</metadata>
</root>

12
DroneClientCpp/MyForm.cpp Normal file
View File

@ -0,0 +1,12 @@
#include "MyForm.h"
#include <Windows.h>
using namespace DroneClientCpp;
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
Application::EnableVisualStyles();
Application::SetCompatibleTextRenderingDefault(false);
Application::Run(gcnew MyForm);
return 0;
}

BIN
DroneClientCpp/MyForm.h Normal file

Binary file not shown.

120
DroneClientCpp/MyForm.resx Normal file
View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,105 @@
#include "NetClient.h"
namespace DroneSimulator {
// Конструктор ConnectData
NetClient::ConnectData::ConnectData(bool connect, Socket^ server)
{
Connect = connect;
Server = server;
}
// Конструктор ReceiveData
NetClient::ReceiveData::ReceiveData(array<Byte>^ buffer, int size, Socket^ server)
{
Buffer = buffer;
Size = size;
Server = server;
}
// Конструктор NetClient
NetClient::NetClient()
{
Connected = false;
ServerSocket = nullptr;
DataServer = gcnew ServerData(); // Инициализация DataServer
}
// Реализация метода Connect
NetClient::ClientState NetClient::Connect(String^ Addr, int Port, ClientCallback^ Connection, ClientCallback^ Receive)
{
if (Connected)
{
Close();
return ClientState::Stop;
}
ConnectionCallback = Connection;
ReceiveCallback = Receive;
IPEndPoint^ ep = gcnew IPEndPoint(IPAddress::Parse(Addr), Port);
ServerSocket = gcnew Socket(AddressFamily::InterNetwork, SocketType::Stream, ProtocolType::Tcp);
try { if (ServerSocket) ServerSocket->Connect(ep); }
catch (...) { ServerSocket->Close(); return ClientState::Error; }
Connected = true;
ConnectionCallback(gcnew ConnectData(true, ServerSocket));
ReceiveData^ receiveData = gcnew ReceiveData(DataServer->buffer, ServerData::size, ServerSocket);
try { if (ServerSocket) ServerSocket->BeginReceive(DataServer->buffer, 0, ServerData::size, SocketFlags::None, gcnew AsyncCallback(this, &NetClient::ReadCallback), receiveData); }
catch (...) {}
return ClientState::Connected;
}
// Реализация метода Close
void NetClient::Close()
{
try { if(ServerSocket) ServerSocket->Shutdown(SocketShutdown::Both); }
catch (...) {}
if(ServerSocket) ServerSocket->Close();
Connected = false;
}
// Реализация метода Send
void NetClient::Send(array<Byte>^ data)
{
if (ServerSocket != nullptr && Connected)
{
try { if (ServerSocket) ServerSocket->Send(data); }
catch (...) {}
}
}
// Реализация метода ReadCallback
void NetClient::ReadCallback(IAsyncResult^ ar)
{
ReceiveData^ cd = (ReceiveData^)ar->AsyncState;
if (cd == nullptr) return;
int bytes = 0;
try { bytes = ServerSocket->EndReceive(ar); }
catch (...) {}
if (bytes == 0)
{
if (ServerSocket) ServerSocket->Close();
Connected = false;
if (ServerSocket != nullptr)
{
ConnectionCallback(gcnew ConnectData(false, nullptr));
}
return;
}
ReceiveCallback(gcnew ReceiveData(cd->Buffer, bytes, ServerSocket));
try { if (ServerSocket) ServerSocket->BeginReceive(cd->Buffer, 0, ServerData::size, SocketFlags::None, gcnew AsyncCallback(this, &NetClient::ReadCallback), cd); }
catch (...) {}
}
}

View File

@ -0,0 +1,68 @@
#pragma once
#include <Windows.h>
#include <vcclr.h>
#using <System.dll>
#using <System.Net.dll>
using namespace System;
using namespace System::Net;
using namespace System::Net::Sockets;
namespace DroneSimulator {
public ref class NetClient
{
public:
ref class ConnectData
{
public:
bool Connect;
Socket^ Server;
ConnectData(bool connect, Socket^ server);
};
ref class ReceiveData
{
public:
array<Byte>^ Buffer;
int Size;
Socket^ Server;
ReceiveData(array<Byte>^ buffer, int size, Socket^ server);
};
private:
ref class ServerData
{
public:
literal int size = 1024;
array<Byte>^ buffer = gcnew array<Byte>(size);
};
bool Connected;
Socket^ ServerSocket;
ServerData^ DataServer;
public:
delegate void ClientCallback(Object^ o);
private:
ClientCallback^ ConnectionCallback;
ClientCallback^ ReceiveCallback;
public:
NetClient(); // Добавлен конструктор
enum class ClientState { Error, Connected, Stop };
ClientState Connect(String^ Addr, int Port, ClientCallback^ Connection, ClientCallback^ Receive);
void Close();
void Send(array<Byte>^ data);
private:
void ReadCallback(IAsyncResult^ ar);
};
}

11
DroneClientCpp/Source.cpp Normal file
View File

@ -0,0 +1,11 @@
#include "MyForm.h"
using namespace MyWinFormsApp; // ???????????? ???? ?????? ???????
[STAThread]
int main(array<String^>^ args) {
Application::EnableVisualStyles(); // ???????? ??????????? ????? ????????? ??????????
Application::SetCompatibleTextRenderingDefault(false); // ????????? ?????????? ??????
Application::Run(gcnew MyForm()); // ?????? ?????
return 0;
}

27
DroneSimulator/Area.cs Normal file
View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;
namespace DroneSimulator
{
internal class Area
{
public struct Poisition
{
public struct Freeze{ public static bool X, Y, Z; }
}
public struct Wind
{
public static bool Enable;
public struct Speed { public static float From, To; }
public static float Direction;
public static float Density;
public static float PosResist;
public static float RotResist;
}
}
}

View File

@ -1,24 +1,28 @@
using System.Numerics;
using System.Runtime.InteropServices;
using static System.Net.Mime.MediaTypeNames;
namespace DroneSimulator
{
internal class Drone
{
public int ID;
public float Mass; // Масса
public bool Active; // Живой?
public float Length; // Длинна лучей
public const float Dynamic = 10; // Динамика вращения
public Vector3 PosXYZ, SpdXYZ, AccXYZ; // Положение в пространстве: Позиция, Скорость, Ускорение
public Quaternion Quat; // Основной кватернион
public float Power = 0; // Тяга всех двигателей
public float MaxPower; // Тяга всех двигателей
public float Power = 0; // Тяга всех двигателей (0-1)
public Vector3 SpdPRY, AccPRY; // Поворот в пространстве: pitch roll yaw
public Vector3 Acc, Gyr; // Имитация: Акселерометр, Гироскоп
public float LaserRange; // Имитация: Дальномер
public Vector4 Orientation;
private uint DataTimer;
private const float Gravity = 9.8f;
private const float TO_GRAD = 180 / MathF.PI;
@ -27,7 +31,21 @@ namespace DroneSimulator
private Thread DroneThread;
private int Timer;
private static int CounterID = 0;
private Vector2 MoveOF = Vector2.Zero;
public struct Physics
{
static public float Mass; // Масса
static public float Length; // Длинна лучей
static public float MaxPower; // Максимальная Тяга всех двигателей (КГ)
}
private RealMode.Accelerometer RealAcc = new RealMode.Accelerometer();
private RealMode.Gyroscope RealGyr = new RealMode.Gyroscope();
private RealMode.Position RealPos = new RealMode.Position();
private RealMode.Barometer RealBar = new RealMode.Barometer();
private RealMode.Range RealRange = new RealMode.Range();
private RealMode.OpticalFlow RealOF = new RealMode.OpticalFlow();
public static byte[] getBytes(object data)
{
@ -70,52 +88,35 @@ namespace DroneSimulator
return mem;
}
public struct DataOut
public VisualData.VisualDrone GetVisual(int count, int index)
{
public float AccX, AccY, AccZ;
public float GyrX, GyrY, GyrZ;
public float PosX, PosY;
public float LaserRange;
}
VisualData.VisualDrone drone = new VisualData.VisualDrone();
public DataOut GetDataOut()
{
DataOut data = new DataOut();
drone.Head.Size = Marshal.SizeOf(typeof(VisualData.VisualDrone));
drone.Head.Type = VisualData.VisualHead.VisualType.Drone;
data.AccX = Acc.X; data.AccY = Acc.Y; data.AccZ = Acc.Z;
data.GyrX = Gyr.X; data.GyrY = Gyr.Y; data.GyrZ = Gyr.Z;
drone.Count = count;
drone.Index = index;
data.PosX = PosXYZ.X; data.PosY = PosXYZ.Y;
drone.ID = ID;
drone.Color.A = 255; drone.Color.R = 255; drone.Color.G = 0; drone.Color.B = 0;
data.LaserRange = LaserRange;
drone.Rotate.X = Quat.X; drone.Rotate.Y = Quat.Y; drone.Rotate.Z = Quat.Z; drone.Rotate.W = Quat.W;
drone.Position.X = PosXYZ.X; drone.Position.Y = PosXYZ.Y; drone.Position.Z = PosXYZ.Z;
drone.Scale = 1.0f;
return data;
}
drone.State = VisualData.VisualDrone.DroneState.Active;
public struct DataIn
{
public float MotorUL, MotorUR, MotorDL, MotorDR;
}
drone.Power = Power;
public struct DataVisual
{
public int ID; // Идентификатор
public float W, X, Y, Z; // Кватернион вращения
public float PosX, PosY, PosZ; // Координаты в пространстве
}
public DataVisual GetVisual()
{
return new DataVisual() { ID = this.ID, W = this.Quat.W, X = this.Quat.X, Y = this.Quat.Y, Z = this.Quat.Z, PosX = this.PosXYZ.X, PosY = this.PosXYZ.Y, PosZ = this.PosXYZ.Z };
return drone;
}
private void ThreadFunction()
{
while (DroneThread != null)
{
float time = Environment.TickCount - Timer;
Timer = Environment.TickCount;
Action(time / 1000);
Action(Environment.TickCount);
Thread.Sleep(1);
}
}
@ -134,12 +135,8 @@ namespace DroneSimulator
DroneThread.Start();
}
public int Create(float power, float mass, float len)
public int Create()
{
Mass = mass;
Length = len;
MaxPower = power;
Active = true;
return ID;
@ -183,7 +180,7 @@ namespace DroneSimulator
{
Quaternion grav = new Quaternion(0, 0, 1, 0);
grav = (Quat * grav) * Quaternion.Inverse(Quat);
grav = Quat * grav * Quaternion.Inverse(Quat);
float yaw = 2 * MathF.Atan2(Quat.Z, Quat.W) * TO_GRAD;
if (yaw < 0.0f) yaw = 360.0f + yaw;
@ -191,8 +188,11 @@ namespace DroneSimulator
return new Vector4(GetAngle(grav.Y, grav.X, grav.Z), GetAngle(-grav.X, grav.Y, grav.Z), yaw, grav.Z);
}
public void Action(float time)
public void Action(int tick)
{
float time = (tick - Timer) / 1000.0f;
Timer = tick;
if (!Active) return;
float flow = Power;
@ -202,16 +202,45 @@ namespace DroneSimulator
flow += flow * 0.1f; // Воздушная подушка
}
SpdPRY += AccPRY * (Dynamic * time / (Mass * Length));
float wind_x = 0, wind_y = 0, wind_z = 0;
float wind_p = 0, wind_r = 0, wind_w = 0;
if (Area.Wind.Enable)
{
Quaternion dir = Quaternion.CreateFromAxisAngle(new Vector3(0, 0, 1), Area.Wind.Direction * TO_RADI * 2);
Quaternion spd = new Quaternion(0, Area.Wind.Speed.From, 0, 0) * dir;
float spd_x = spd.X - SpdXYZ.X;
float spd_y = spd.Y - SpdXYZ.Y;
float spd_z = spd.Z - SpdXYZ.Z;
wind_x = 0.5f * Area.Wind.Density * Area.Wind.PosResist * (spd_x * MathF.Abs(spd_x));
wind_y = 0.5f * Area.Wind.Density * Area.Wind.PosResist * (spd_y * MathF.Abs(spd_y));
wind_z = 0.5f * Area.Wind.Density * Area.Wind.PosResist * (spd_z * MathF.Abs(spd_z));
wind_p = 0.5f * Area.Wind.Density * Area.Wind.RotResist * (SpdPRY.X * MathF.Abs(SpdPRY.X));
wind_r = 0.5f * Area.Wind.Density * Area.Wind.RotResist * (SpdPRY.Y * MathF.Abs(SpdPRY.Y));
wind_w = 0.5f * Area.Wind.Density * Area.Wind.RotResist * (SpdPRY.Z * MathF.Abs(SpdPRY.Z));
AccPRY.X -= wind_p; AccPRY.Y -= wind_r; AccPRY.Z -= wind_w;
}
SpdPRY += AccPRY * (Dynamic * time / (Physics.Mass * Physics.Length));
Quaternion pow = Quaternion.Inverse(Quat) * new Quaternion(0, 0, flow, 0) * Quat;
AccXYZ = new Vector3(pow.X, pow.Y, pow.Z) * (Gravity / Mass);
AccXYZ = new Vector3(pow.X + wind_x, pow.Y + wind_y, pow.Z + wind_z) * (Gravity / Physics.Mass);
SpdXYZ += (AccXYZ + new Vector3(0, 0, -Gravity)) * time;
PosXYZ += SpdXYZ * time;
AccXYZ /= Gravity; // Вернуть измерения в G
if (Area.Poisition.Freeze.X) { SpdXYZ.X = 0; PosXYZ.X = 0; }
if (Area.Poisition.Freeze.Y) { SpdXYZ.Y = 0; PosXYZ.Y = 0; }
if (Area.Poisition.Freeze.Z) { SpdXYZ.Z = 0; PosXYZ.Z = 5; }
if (PosXYZ.Z < 0)
{
SpdPRY = Vector3.Zero;
@ -223,6 +252,8 @@ namespace DroneSimulator
Vector4 ori = GetOrientation();
Orientation = ori;
if (PosXYZ.Z < 0)
{
PosXYZ.Z = 0;
@ -250,17 +281,28 @@ namespace DroneSimulator
//Active = false; // Перевернулся вверх ногами
}
Quaternion grav = new Quaternion(AccXYZ.X, AccXYZ.Y, AccXYZ.Z, 0);
//grav = (Quat * grav) * Quaternion.Inverse(Quat); // Инерциальный акселерометр (тест)
Quaternion grav = Quat * new Quaternion(AccXYZ.X, AccXYZ.Y, AccXYZ.Z, 0) * Quaternion.Inverse(Quat);
Acc = new Vector3(grav.X, grav.Y, grav.Z);
Gyr = SpdPRY;
float tilt = (MathF.Abs(ori.X) + MathF.Abs(ori.Y)) * TO_RADI;
float tilt = MathF.Sqrt((ori.X * ori.X) + (ori.Y * ori.Y)) * TO_RADI;
if (tilt < 90 && ori.W > 0) LaserRange = PosXYZ.Z / MathF.Cos(tilt);
else LaserRange = float.MaxValue;
}
MoveOF.X += SpdXYZ.X - Gyr.Y;
MoveOF.Y += SpdXYZ.Y + Gyr.X;
RealAcc.Update(Acc, (uint)tick);
RealGyr.Update(Gyr, (uint)tick);
RealRange.Update(LaserRange, (uint)tick);
RealBar.Update(PosXYZ.Z * 11, (uint)tick);
RealPos.Update(PosXYZ, (uint)tick);
RealOF.Update(MoveOF, LaserRange, (uint)tick);
DataTimer = (uint)tick;
}
private float Range(float pow)
@ -268,7 +310,7 @@ namespace DroneSimulator
if (pow > 1) pow = 1;
if (pow < 0) pow = 0;
return pow * MaxPower;
return pow * Physics.MaxPower;
}
public void SetQadroPow(float ul, float ur, float dl, float dr)
@ -281,5 +323,257 @@ namespace DroneSimulator
AccPRY.X = ((ul + ur) - (dl + dr));
AccPRY.Z = ((ul + dr) - (dl + ur)) / 4;
}
private void RecvDataMotor4(byte[] data)
{
DroneData.DataMotor4 mot = (DroneData.DataMotor4)fromBytes(data, typeof(DroneData.DataMotor4));
/* обработка */
SetQadroPow(mot.UL, mot.UR, mot.DL, mot.DR);
}
private byte[] SendDataAcc()
{
DroneData.DataAcc acc = new DroneData.DataAcc();
acc.Head.Size = Marshal.SizeOf(typeof(DroneData.DataAcc));
acc.Head.Mode = DroneData.DataMode.Response;
acc.Head.Type = DroneData.DataType.DataAcc;
acc.Head.Time = (uint)Environment.TickCount;
acc.Acc.X = RealAcc.result.X; acc.Acc.Y = RealAcc.result.Y; acc.Acc.Z = RealAcc.result.Z;
acc.Time = RealAcc.timer;
return getBytes(acc);
}
private byte[] SendDataGyr()
{
DroneData.DataGyr gyr = new DroneData.DataGyr();
gyr.Head.Size = Marshal.SizeOf(typeof(DroneData.DataGyr));
gyr.Head.Mode = DroneData.DataMode.Response;
gyr.Head.Type = DroneData.DataType.DataGyr;
gyr.Head.Time = (uint)Environment.TickCount;
gyr.Gyr.X = RealGyr.result.X; gyr.Gyr.Y = RealGyr.result.Y; gyr.Gyr.Z = RealGyr.result.Z;
gyr.Time = RealGyr.timer;
return getBytes(gyr);
}
private byte[] SendDataMag()
{
DroneData.DataMag mag = new DroneData.DataMag();
mag.Head.Size = Marshal.SizeOf(typeof(DroneData.DataMag));
mag.Head.Mode = DroneData.DataMode.Response;
mag.Head.Type = DroneData.DataType.DataMag;
mag.Head.Time = (uint)Environment.TickCount;
mag.Mag.X = 0; mag.Mag.Y = 0; mag.Mag.Z = 0;
mag.Time = DataTimer;
return getBytes(mag);
}
private byte[] SendDataRange()
{
DroneData.DataRange range = new DroneData.DataRange();
range.Head.Size = Marshal.SizeOf(typeof(DroneData.DataRange));
range.Head.Mode = DroneData.DataMode.Response;
range.Head.Type = DroneData.DataType.DataRange;
range.Head.Time = (uint)Environment.TickCount;
range.LiDAR = RealRange.result;
range.Time = RealRange.timer;
return getBytes(range);
}
private byte[] SendDataLocal()
{
DroneData.DataLocal local = new DroneData.DataLocal();
local.Head.Size = Marshal.SizeOf(typeof(DroneData.DataLocal));
local.Head.Mode = DroneData.DataMode.Response;
local.Head.Type = DroneData.DataType.DataLocal;
local.Head.Time = (uint)Environment.TickCount;
local.Local.X = RealPos.result.X; local.Local.Y = RealPos.result.Y; local.Local.Z = RealPos.result.Z;
local.Time = RealPos.timer;
return getBytes(local);
}
private byte[] SendDataBarometer()
{
DroneData.DataBar bar = new DroneData.DataBar();
bar.Head.Size = Marshal.SizeOf(typeof(DroneData.DataBar));
bar.Head.Mode = DroneData.DataMode.Response;
bar.Head.Type = DroneData.DataType.DataBar;
bar.Head.Time = (uint)Environment.TickCount;
bar.Pressure = RealBar.result;
bar.Time = RealBar.timer;
return getBytes(bar);
}
private byte[] SendDataOF()
{
DroneData.DataOF of = new DroneData.DataOF();
of.Head.Size = Marshal.SizeOf(typeof(DroneData.DataOF));
of.Head.Mode = DroneData.DataMode.Response;
of.Head.Type = DroneData.DataType.DataOF;
of.Head.Time = (uint)Environment.TickCount;
of.X = RealOF.result.X;
of.Y = RealOF.result.Y;
of.Time = RealBar.timer;
MoveOF = Vector2.Zero;
return getBytes(of);
}
private byte[] SendDataGPS()
{
DroneData.DataGPS gps = new DroneData.DataGPS();
gps.Head.Size = Marshal.SizeOf(typeof(DroneData.DataGPS));
gps.Head.Mode = DroneData.DataMode.Response;
gps.Head.Type = DroneData.DataType.DataGPS;
gps.Head.Time = (uint)Environment.TickCount;
GPS.Point p = new GPS.Point();
p.x = PosXYZ.Y; p.y= PosXYZ.X;
GPS.GlobalCoords g = new GPS.GlobalCoords();
g.latitude=GPS.Home.Lat; g.longitude=GPS.Home.Lon;
g=GPS.localToGlobal(p, g);
gps.Lat = g.latitude; gps.Lon = g.longitude;
gps.Speed = MathF.Sqrt(SpdXYZ.X * SpdXYZ.X + SpdXYZ.Y * SpdXYZ.Y + SpdXYZ.Z * SpdXYZ.Z);
gps.Alt = GPS.Home.Alt + PosXYZ.Z;
DateTime tim = DateTime.Now;
gps.UTC = tim.Second + tim.Minute * 100 + tim.Hour * 10000;
gps.Fix = GPS.State.Fix;
gps.SatVisible = GPS.State.SatVisible;
gps.SatUsed = GPS.State.SatUsed;
gps.Noise = GPS.State.Noise;
gps.Hdop = GPS.State.Hdop;
gps.Vdop = GPS.State.Vdop;
gps.Pdop = GPS.State.Pdop;
return getBytes(gps);
}
private byte[] SendDataQuaternion()
{
DroneData.DataQuat quat = new DroneData.DataQuat();
quat.Head.Size = Marshal.SizeOf(typeof(DroneData.DataQuat));
quat.Head.Mode = DroneData.DataMode.Response;
quat.Head.Type = DroneData.DataType.DataQuat;
quat.Head.Time = (uint)Environment.TickCount;
quat.X = Quat.X; quat.Y = Quat.Y; quat.Z = Quat.Z; quat.W = Quat.W;
return getBytes(quat);
}
private byte[]? ServerRequestResponse(DroneData.DataHead head, byte[] body)
{
byte[] zero = Array.Empty<byte>();
switch (head.Type)
{
case DroneData.DataType.DataAcc:
{
if (head.Mode == DroneData.DataMode.Request)
{
// Запрос данных
return SendDataAcc();
}
else
{
// Пришли данные
// ... //
//
return zero;
}
}
case DroneData.DataType.DataGyr: if (head.Mode == DroneData.DataMode.Request) return SendDataGyr(); else return zero;
case DroneData.DataType.DataMag: if (head.Mode == DroneData.DataMode.Request) return SendDataMag(); else return zero;
case DroneData.DataType.DataRange: if (head.Mode == DroneData.DataMode.Request) return SendDataRange(); else return zero;
case DroneData.DataType.DataLocal: if (head.Mode == DroneData.DataMode.Request) return SendDataLocal(); else return zero;
case DroneData.DataType.DataBar: if (head.Mode == DroneData.DataMode.Request) return SendDataBarometer(); else return zero;
case DroneData.DataType.DataOF: if (head.Mode == DroneData.DataMode.Request) return SendDataOF(); else return zero;
case DroneData.DataType.DataGPS: if (head.Mode == DroneData.DataMode.Request) return SendDataGPS(); else return zero;
case DroneData.DataType.DataQuat: if (head.Mode == DroneData.DataMode.Request) return SendDataQuaternion(); else return zero;
case DroneData.DataType.DataMotor4: if (head.Mode == DroneData.DataMode.Response) RecvDataMotor4(body); return zero;
}
return zero;
}
private const int DroneStreamCount = 512;
private byte[] DroneStreamData = new byte[DroneStreamCount];
private int DroneStreamIndex = 0;
private DroneData.DataHead DroneStreamHead = new DroneData.DataHead() { Mode = DroneData.DataMode.None, Size = 0, Type = DroneData.DataType.None };
public List<byte[]?>? DataStream(byte[]? data, int size)
{
List<byte[]?> ret = new List<byte[]?>();
if (data == null) return ret; // Последовательность не сформирована, ждать данных
if (size + DroneStreamIndex > DroneStreamCount) return null; // Ошибка переполнения, поток сломан (конец)
Array.Copy(data, 0, DroneStreamData, DroneStreamIndex, size);
DroneStreamIndex += size;
while (true)
{
if (DroneStreamHead.Size == 0) // Заголовок ещё не получен
{
if (DroneStreamIndex < DroneData.DataHead.StrLen) return ret; // Нечего слать
DroneStreamHead = (DroneData.DataHead)fromBytes(DroneStreamData, typeof(DroneData.DataHead));
}
if (DroneStreamHead.Size > DroneStreamIndex) break; // Пакет ещё не полный
byte[] body = new byte[DroneStreamHead.Size];
Array.Copy(DroneStreamData, 0, body, 0, DroneStreamHead.Size);
int shift = DroneStreamHead.Size;
DroneStreamIndex -= shift;
Array.Copy(DroneStreamData, shift, DroneStreamData, 0, DroneStreamIndex); // Сдвигаем массив влево, убрав использованные данные
DroneStreamHead.Size = 0; // Отменяем прошлый заголовок
ret.Add(ServerRequestResponse(DroneStreamHead, body));
}
return ret;
}
}
}

152
DroneSimulator/DroneData.cs Normal file
View File

@ -0,0 +1,152 @@
using System.Net;
using System.Runtime.InteropServices;
namespace DroneData
{
public enum DataMode : ushort
{
None = 0, Response = 1, Request = 2
};
public enum DataType : ushort
{
None = 0, Head = 1,
// Output
DataAcc = 1001, DataGyr = 1002, DataMag = 1003, DataRange = 1004, DataLocal = 1005, DataBar = 1006, DataOF = 1007, DataGPS = 1008,
// Input
DataMotor4 = 2001, DataMotor6 = 2002,
// State
DataQuat = 3001,
};
public struct DataHead
{
public int Size;
public DataMode Mode;
public DataType Type;
public uint Time; // Общее время
static public int StrLen = Marshal.SizeOf(typeof(DroneData.DataHead));
}
public struct XYZ { public float X, Y, Z; }
public struct DataAcc
{
public DataHead Head;
public XYZ Acc;
public uint Time; // Последнее время изменения данных
static public int StrLen = Marshal.SizeOf(typeof(DroneData.DataAcc));
}
public struct DataGyr
{
public DataHead Head;
public XYZ Gyr;
public uint Time; // Последнее время изменения данных
static public int StrLen = Marshal.SizeOf(typeof(DroneData.DataGyr));
}
public struct DataMag
{
public DataHead Head;
public XYZ Mag;
public uint Time; // Последнее время изменения данных
static public int StrLen = Marshal.SizeOf(typeof(DroneData.DataMag));
}
public struct DataRange
{
public DataHead Head;
public float LiDAR; // Датчик посадки
public uint Time; // Последнее время изменения данных
static public int StrLen = Marshal.SizeOf(typeof(DroneData.DataRange));
}
public struct DataLocal
{
public DataHead Head;
public XYZ Local; // Локальные координаты
public uint Time; // Последнее время изменения данных
static public int StrLen = Marshal.SizeOf(typeof(DroneData.DataLocal));
}
public struct DataBar
{
public DataHead Head;
public float Pressure; // Давление
public uint Time; // Последнее время изменения данных
static public int StrLen = Marshal.SizeOf(typeof(DroneData.DataBar));
}
public struct DataOF
{
public DataHead Head;
public float X, Y; // Угловой сдвиг
public uint Time; // Последнее время изменения данных
static public int StrLen = Marshal.SizeOf(typeof(DroneData.DataOF));
}
public struct DataGPS
{
public DataHead Head;
public double Lat, Lon; // Координаты (градусы)
public float Alt; // Высота (метры)
public float Speed; // Скорость (м/с)
public int UTC; // Время UTC hhmmss
public byte Fix; // Тип решения 0-8 (NMEA Fix type)
public byte SatVisible; // Количество видимых спутников
public byte SatUsed; // Количество используемых спутников
public float Hdop, Vdop, Pdop; // Геометрический фактор
public float Noise; // Шум (db)
public uint Time; // Последнее время изменения данных
static public int StrLen = Marshal.SizeOf(typeof(DroneData.DataOF));
}
public struct DataMotor4
{
public DataHead Head;
public float UL, UR, DL, DR;
static public int StrLen = Marshal.SizeOf(typeof(DroneData.DataMotor4));
}
public struct DataMotor6
{
public DataHead Head;
public float UL, UR, LL, RR, DL, DR;
static public int StrLen = Marshal.SizeOf(typeof(DroneData.DataMotor6));
}
public struct DataQuat
{
public DataHead Head;
public float X, Y, Z, W;
static public int StrLen = Marshal.SizeOf(typeof(DroneData.DataQuat));
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,12 @@
using System.Text;
using System.Text;
using System.Numerics;
using System.Windows.Forms;
using static System.Net.Mime.MediaTypeNames;
using static System.Runtime.InteropServices.JavaScript.JSType;
using System.Security.Policy;
using System.Runtime.InteropServices;
using System.CodeDom;
using System.Linq;
namespace DroneSimulator
{
@ -19,6 +22,17 @@ namespace DroneSimulator
public Form_Main()
{
InitializeComponent();
numericUpDown_Acc_Update(null, null);
numericUpDown_Gyr_Update(null, null);
numericUpDown_Pos_Update(null, null);
numericUpDown_Bar_Update(null, null);
numericUpDown_Range_Update(null, null);
numericUpDown_OF_Update(null, null);
checkBox_Area_Freeze_CheckedChanged(null, null);
numericUpDown_Area_Wind_Update(null, null);
numericUpDown_GPS_ValueChanged(null, null);
numericUpDown_Physics_ValueChanged(null, null);
}
private void ClientConnectionCallback(object o)
@ -33,7 +47,7 @@ namespace DroneSimulator
if (data.Connect)
{
Drone drone = new Drone(data.ID);
drone.Create(1.0f, 0.5f, 1.0f);
drone.Create();
screen2D.CreateDrone(Color.Red, data.ID);
@ -69,13 +83,16 @@ namespace DroneSimulator
if (drone == null) return;
Drone.DataIn id = (Drone.DataIn)Drone.fromBytes(data.Buffer, typeof(Drone.DataIn));
List<byte[]?>? send = drone.DataStream(data.Buffer, data.Size);
drone.SetQadroPow(id.MotorUL, id.MotorUR, id.MotorDL, id.MotorDR);
Drone.DataOut od = drone.GetDataOut();
try { data.Client.Send(Drone.getBytes(od)); }
if (send == null) return;
try
{
foreach (byte[]? b in send)
{
if (b != null) data.Client?.Send(b);
}
}
catch { }
}
@ -127,12 +144,27 @@ namespace DroneSimulator
private void timer_Test_Tick(object sender, EventArgs e)
{
DateTime test = DateTime.Now;
int tim = test.Second + test.Minute * 100 + test.Hour * 10000;
if (screen2D == null) return;
foreach (Drone d in AllDrones)
listBox_Drones.Items.Clear();
try
{
screen2D.Move(d.ID, d.PosXYZ, d.GetOrientation());
foreach (Drone d in AllDrones)
{
screen2D.Move(d.ID, d.PosXYZ, d.GetOrientation());
string line = "ID:" + d.ID.ToString() + " Pitch:" + ((int)d.Orientation.X).ToString() + " Roll:" + ((int)d.Orientation.Y).ToString() + " Yaw:" + ((int)d.Orientation.Z).ToString();
listBox_Drones.Items.Add(line);
}
}
catch { }
screen2D.DrawScene();
}
@ -147,7 +179,7 @@ namespace DroneSimulator
Invoke((MethodInvoker)delegate
{
label_Clients_Num.Text = data.Count.ToString();
label_Visual_Num.Text = data.Count.ToString();
});
if (data.Connect)
@ -164,9 +196,11 @@ namespace DroneSimulator
{
NetServerVisual.ReceiveData data = (NetServerVisual.ReceiveData)o;
int index = 0;
foreach (Drone d in AllDrones)
{
Drone.DataVisual v = d.GetVisual();
VisualData.VisualDrone v = d.GetVisual(AllDrones.Count, index++);
try { data.Client.Send(Drone.getBytes(v)); }
catch { }
@ -198,5 +232,125 @@ namespace DroneSimulator
}
}
}
private void numericUpDown_Bar_Update(object sender, EventArgs e)
{
RealMode.Barometer.RealSimulation = checkBox_Model_Bar_Real.Checked;
try { RealMode.Barometer.Pressure = uint.Parse(textBox_Bar_Pressure.Text); }
catch
{
RealMode.Barometer.Pressure = 102258;
MessageBox.Show("Pressure invalid format", "Barometer error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
RealMode.Barometer.Freq = (uint)numericUpDown_Bar_Freq.Value;
RealMode.Barometer.Noise = (float)numericUpDown_Bar_Noise.Value;
RealMode.Barometer.Lateness = (float)numericUpDown_Bar_Laten.Value;
RealMode.Barometer.Enable = checkBox_Bar_Enable.Checked;
}
private void numericUpDown_Acc_Update(object sender, EventArgs e)
{
RealMode.Accelerometer.RealSimulation = checkBox_Model_Acc_Real.Checked;
RealMode.Accelerometer.Freq = (uint)numericUpDown_Acc_Freq.Value;
RealMode.Accelerometer.Noise = (float)numericUpDown_Acc_Noise.Value;
RealMode.Accelerometer.Lateness = (float)numericUpDown_Acc_Laten.Value;
RealMode.Accelerometer.ScaleLeft = (float)numericUpDown_Acc_Scale_Left.Value;
RealMode.Accelerometer.ScaleRight = (float)numericUpDown_Acc_Scale_Rigth.Value;
}
private void numericUpDown_Gyr_Update(object sender, EventArgs e)
{
RealMode.Gyroscope.RealSimulation = checkBox_Model_Gyr_Real.Checked;
RealMode.Gyroscope.Freq = (uint)numericUpDown_Gyr_Freq.Value;
RealMode.Gyroscope.Noise = (float)numericUpDown_Gyr_Noise.Value;
RealMode.Gyroscope.Lateness = (float)numericUpDown_Gyr_Laten.Value;
RealMode.Gyroscope.Shift.X = (float)numericUpDown_Gyr_Shift_X.Value;
RealMode.Gyroscope.Shift.Y = (float)numericUpDown_Gyr_Shift_Y.Value;
RealMode.Gyroscope.Shift.Z = (float)numericUpDown_Gyr_Shift_Z.Value;
}
private void numericUpDown_Pos_Update(object sender, EventArgs e)
{
RealMode.Position.RealSimulation = checkBox_Model_Pos_Real.Checked;
RealMode.Position.Freq = (uint)numericUpDown_Pos_Freq.Value;
RealMode.Position.Noise = (float)numericUpDown_Pos_Noise.Value;
RealMode.Position.Lateness = (float)numericUpDown_Pos_Laten.Value;
RealMode.Position.Enable = checkBox_Pos_Enable.Checked;
}
private void numericUpDown_Range_Update(object sender, EventArgs e)
{
RealMode.Range.RealSimulation = checkBox_Model_Range_Real.Checked;
RealMode.Range.Freq = (uint)numericUpDown_Range_Freq.Value;
RealMode.Range.Noise = (float)numericUpDown_Range_Noise.Value;
RealMode.Range.Lateness = (float)numericUpDown_Range_Laten.Value;
RealMode.Range.Enable = checkBox_Range_Enable.Checked;
RealMode.Range.MaxHeight = (float)numericUpDown_Range_Max.Value;
}
private void numericUpDown_OF_Update(object sender, EventArgs e)
{
RealMode.OpticalFlow.RealSimulation = checkBox_Model_OF_Real.Checked;
RealMode.OpticalFlow.Freq = (uint)numericUpDown_OF_Freq.Value;
RealMode.OpticalFlow.Noise = (float)numericUpDown_OF_Noise.Value;
RealMode.OpticalFlow.Lateness = (float)numericUpDown_OF_Laten.Value;
RealMode.OpticalFlow.Enable = checkBox_OF_Enable.Checked;
RealMode.OpticalFlow.Lens = (uint)numericUpDown_OF_Lens.Value * 10;
RealMode.OpticalFlow.MaxHeight = (float)numericUpDown_OF_Len.Value;
RealMode.OpticalFlow.Error = (float)numericUpDown_OF_Error.Value * 10;
RealMode.OpticalFlow.Wait = (uint)numericUpDown_OF_Wait.Value * 1000;
}
private void checkBox_Area_Freeze_CheckedChanged(object sender, EventArgs e)
{
Area.Poisition.Freeze.X = checkBox_Area_Freeze_X.Checked;
Area.Poisition.Freeze.Y = checkBox_Area_Freeze_Y.Checked;
Area.Poisition.Freeze.Z = checkBox_Area_Freeze_Z.Checked;
}
private void numericUpDown_Area_Wind_Update(object sender, EventArgs e)
{
Area.Wind.Enable = checkBox_Area_Wind_Enable.Checked;
Area.Wind.Speed.From = (float)numericUpDown_Area_Wind_Speed_From.Value;
Area.Wind.Speed.To = (float)numericUpDown_Area_Wind_Speed_To.Value;
Area.Wind.Direction = (float)numericUpDown_Area_Wind_Direction.Value;
Area.Wind.Density = (float)numericUpDown_Area_Wind_Density.Value;
Area.Wind.PosResist = ((float)numericUpDown_Area_Wind_PosResist.Value) / 1000.0f;
Area.Wind.RotResist = ((float)numericUpDown_Area_Wind_RotResist.Value) / 1000.0f;
}
private void numericUpDown_GPS_ValueChanged(object sender, EventArgs e)
{
GPS.Home.Lat = (double)numericUpDown_GPS_Lat.Value;
GPS.Home.Lon = (double)numericUpDown_GPS_Lon.Value;
GPS.Home.Alt = (float)numericUpDown_GPS_Alt.Value;
GPS.State.Fix = (byte)numericUpDown_GPS_Fix.Value;
GPS.State.SatVisible = (byte)numericUpDown_GPS_Vis.Value;
GPS.State.SatUsed = (byte)numericUpDown_GPS_Use.Value;
GPS.State.Noise = (float)numericUpDown_GPS_Noise.Value;
GPS.State.Hdop = (float)numericUpDown_GPS_HDOP.Value;
GPS.State.Vdop = (float)numericUpDown_GPS_VDOP.Value;
GPS.State.Pdop = (float)numericUpDown_GPS_PDOP.Value;
}
private void numericUpDown_Physics_ValueChanged(object sender, EventArgs e)
{
Drone.Physics.Mass = (float)numericUpDown_Physics_Mass.Value;
Drone.Physics.Length = (float)numericUpDown_Physics_Length.Value;
Drone.Physics.MaxPower = (float)numericUpDown_Physics_Power.Value;
}
}
}

View File

@ -117,14 +117,11 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="menuStrip_Menu.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="timer_Test.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>162, 5</value>
</metadata>
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>25</value>
<value>78</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">

74
DroneSimulator/GPS.cs Normal file
View File

@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace DroneSimulator
{
internal class GPS
{
static double PI = 3.14159265358979323846;
public struct Home
{
public static double Lat, Lon;
public static float Alt;
}
public struct State
{
public static byte Fix; // Тип решения 0-8 (NMEA Fix type)
public static byte SatVisible; // Количество видимых спутников
public static byte SatUsed; // Количество используемых спутников
public static float Hdop, Vdop, Pdop; // Геометрический фактор
public static float Noise; // Шум (db)
}
public struct GlobalCoords
{
public double latitude, longitude;
}
public struct Point
{
public double x, y;
}
// Конвертация градусов в радианы
static double deg2rad(double deg)
{
return deg * PI / 180.0;
}
// Конвертация радиан в градусы
static double rad2deg(double rad)
{
return rad * 180.0 / PI;
}
// Перевод локальных координат в глобальные
public static GlobalCoords localToGlobal(Point local, GlobalCoords origin)
{
const double er = 6371000; // Radius of the earth in m
// Преобразование приращений координат
double dLat = local.x / er; // В радианах
double originLatRad = deg2rad(origin.latitude);
// Вычисление новой широты
double newLatRad = originLatRad + dLat;
double newLat = rad2deg(newLatRad);
// Вычисление новой долготы (с использованием средней широты для точности)
double avgLatRad = (originLatRad + newLatRad) / 2.0;
double dLon = local.y / (er * Math.Cos(avgLatRad)); // В радианах
double newLon = origin.longitude + rad2deg(dLon);
GlobalCoords coord = new GlobalCoords();
coord.latitude = newLat;
coord.longitude = newLon;
return coord;
}
}
}

View File

@ -1,5 +1,6 @@
using System.Net.Sockets;
using System.Net;
using System.Drawing;
namespace DroneSimulator
{
@ -16,8 +17,9 @@ namespace DroneSimulator
public class ReceiveData
{
public int ID;
public byte[]? Buffer;
public byte[] Buffer;
public int Size;
public Socket? Client;
@ -27,8 +29,8 @@ namespace DroneSimulator
{
public int ID;
public Socket? workSocket = null;
public const int BufferSize = 1024;
public byte[] buffer = new byte[BufferSize];
public const int count = 1024;
public byte[] buffer = new byte[count];
}
private int SocketID = 0;
@ -101,7 +103,7 @@ namespace DroneSimulator
ConnectionCallback(new ConnectData { ID = clientData.ID, Connect = true, Count = ClientSockets.Count, Client = handler });
handler.BeginReceive(clientData.buffer, 0, ClientData.BufferSize, 0, new AsyncCallback(ReadCallback), clientData);
handler.BeginReceive(clientData.buffer, 0, ClientData.count, 0, new AsyncCallback(ReadCallback), clientData);
}
else handler.Close();
@ -132,7 +134,7 @@ namespace DroneSimulator
try
{
cd.workSocket?.BeginReceive(cd.buffer, 0, ClientData.BufferSize, 0, new AsyncCallback(ReadCallback), cd);
cd.workSocket?.BeginReceive(cd.buffer, 0, ClientData.count, 0, new AsyncCallback(ReadCallback), cd);
}
catch { }
}

416
DroneSimulator/RealMode.cs Normal file
View File

@ -0,0 +1,416 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Numerics;
using System.Reflection;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Rebar;
namespace DroneSimulator
{
internal class RealMode
{
internal class Accelerometer
{
public static uint Freq;
public static float Noise;
public static float ScaleLeft;
public static float ScaleRight;
public static float Lateness;
public static bool RealSimulation;
private uint last = 0;
private Random rand = new Random();
private const int count = 1000;
private Vector3[] laten = new Vector3[count];
private uint index = 0;
public uint timer = 0;
public Vector3 result;
public void Update(Vector3 value, uint time)
{
if (!RealSimulation)
{
result = value;
timer = time;
return;
}
float scale = (ScaleRight - ScaleLeft) / 2;
float shift = scale + ScaleLeft;
value.X = (value.X * scale) + shift;
value.Y = (value.Y * scale) + shift;
value.Z = (value.Z * scale) + shift;
int noise = (int)(Noise * 1000);
value.X += ((float)rand.Next(-noise, noise)) / 1000;
value.Y += ((float)rand.Next(-noise, noise)) / 1000;
value.Z += ((float)rand.Next(-noise, noise)) / 1000;
uint clock = (uint)(Lateness * 1000);
uint tick = time - last;
last = time;
while (tick != 0)
{
tick--;
laten[index++] = value;
if (index >= clock) index = 0;
}
value = laten[index];
uint freq = 1000 / Freq;
if (timer + freq < time)
{
result = value;
timer = time;
}
}
}
internal class Gyroscope
{
public static uint Freq;
public static float Noise;
public static Vector3 Shift;
public static float Lateness;
public static bool RealSimulation;
private uint last = 0;
private Random rand = new Random();
private const int count = 1000;
private Vector3[] laten = new Vector3[count];
private uint index = 0;
public uint timer = 0;
public Vector3 result;
public void Update(Vector3 value, uint time)
{
if (!RealSimulation)
{
result = value;
timer = time;
return;
}
value.X += Shift.X;
value.Y += Shift.Y;
value.Z += Shift.Z;
int noise = (int)(Noise * 1000);
value.X += ((float)rand.Next(-noise, noise)) / 1000;
value.Y += ((float)rand.Next(-noise, noise)) / 1000;
value.Z += ((float)rand.Next(-noise, noise)) / 1000;
uint clock = (uint)(Lateness * 1000);
uint tick = time - last;
last = time;
while (tick != 0)
{
tick--;
laten[index++] = value;
if (index >= clock) index = 0;
}
value = laten[index];
uint freq = 1000 / Freq;
if (timer + freq < time)
{
result = value;
timer = time;
}
}
}
internal class Magnetometer
{
}
internal class Position
{
public static bool Enable;
public static uint Freq;
public static float Noise;
public static float Lateness;
public static bool RealSimulation;
private uint last = 0;
private Random rand = new Random();
private const int count = 1000;
private Vector3[] laten = new Vector3[count];
private uint index = 0;
public uint timer = 0;
public Vector3 result;
public void Update(Vector3 value, uint time)
{
if (!Enable)
{
result = Vector3.NaN;
return;
}
if (!RealSimulation)
{
result = value;
timer = time;
return;
}
int noise = (int)(Noise * 1000);
value.X += ((float)rand.Next(-noise, noise)) / 1000;
value.Y += ((float)rand.Next(-noise, noise)) / 1000;
value.Z += ((float)rand.Next(-noise, noise)) / 1000;
uint clock = (uint)(Lateness * 1000);
uint tick = time - last;
last = time;
while (tick != 0)
{
tick--;
laten[index++] = value;
if (index >= clock) index = 0;
}
value = laten[index];
uint freq = 1000 / Freq;
if (timer + freq < time)
{
result = value;
timer = time;
}
}
}
internal class Barometer
{
public static bool Enable;
public static float Pressure;
public static uint Freq;
public static float Noise;
public static float Lateness;
public static bool RealSimulation;
private uint last = 0;
private Random rand = new Random();
private const int count = 1000;
private float[] laten = new float[count];
private uint index = 0;
public uint timer = 0;
public float result;
public void Update(float value, uint time)
{
value = Pressure - value;
if (!Enable)
{
result = float.NaN;
return;
}
if (!RealSimulation)
{
result = value;
timer = time;
return;
}
int noise = (int)(Noise * 1000);
value += ((float)rand.Next(-noise, noise)) / 1000;
uint clock = (uint)(Lateness * 1000);
uint tick = time - last;
last = time;
while (tick != 0)
{
tick--;
laten[index++] = value;
if (index >= clock) index = 0;
}
value = laten[index];
uint freq = 1000 / Freq;
if (timer + freq < time)
{
result = value;
timer = time;
}
}
}
internal class OpticalFlow
{
public static bool Enable;
public static float MaxHeight;
public static uint Freq;
public static float Noise;
public static float Lateness;
public static float Error;
public static uint Wait;
public static float Lens;
public static bool RealSimulation;
private uint last = 0;
private Random rand = new Random();
private const int count = 1000;
private Vector2[] laten = new Vector2[count];
private uint index = 0;
public uint delay = 0;
public uint timer = 0;
public Vector2 result;
public void Update(Vector2 value, float Range, uint time)
{
if (!Enable)
{
result = Vector2.NaN;
return;
}
if (!RealSimulation)
{
result = value;
timer = time;
return;
}
value *= Lens;
if (rand.Next(0, 1000) < (Error * 10))
{
value = Vector2.Zero;
delay = time + Wait;
}
else if (delay > time)
{
value = Vector2.Zero;
}
if (Range > MaxHeight) value = Vector2.Zero;
else
{
int noise = (int)(Noise * 1000);
value.X += ((float)rand.Next(-noise, noise)) / 1000;
value.Y += ((float)rand.Next(-noise, noise)) / 1000;
}
uint clock = (uint)(Lateness * 1000);
uint tick = time - last;
last = time;
while (tick != 0)
{
tick--;
laten[index++] = value;
if (index >= clock) index = 0;
}
value = laten[index];
uint freq = 1000 / Freq;
if (timer + freq < time)
{
result = value;
timer = time;
}
}
}
internal class Range
{
public static bool Enable;
public static float MaxHeight;
public static uint Freq;
public static float Noise;
public static float Lateness;
public static bool RealSimulation;
private uint last = 0;
private Random rand = new Random();
private const int count = 1000;
private float[] laten = new float[count];
private uint index = 0;
public uint timer = 0;
public float result;
public void Update(float value, uint time)
{
if (!Enable)
{
result = float.NaN;
return;
}
if (!RealSimulation)
{
result = value;
timer = time;
return;
}
if (value > MaxHeight) value = MaxHeight;
else
{
int noise = (int)(Noise * 1000);
value += ((float)rand.Next(-noise, noise)) / 1000;
}
uint clock = (uint)(Lateness * 1000);
uint tick = time - last;
last = time;
while (tick != 0)
{
tick--;
laten[index++] = value;
if (index >= clock) index = 0;
}
value = laten[index];
uint freq = 1000 / Freq;
if (timer + freq < time)
{
result = value;
timer = time;
}
}
}
}
}

View File

@ -106,51 +106,55 @@ namespace DroneSimulator
foreach (var d in DroneList)
{
if (d.Azimuth >= 360) d.Azimuth -= 360;
var bmp = RotateImage(d.Drone, d.Azimuth);
g.FillEllipse(new SolidBrush(Color.FromArgb(50, d.RGB)), d.PosXY.X + d.Height, d.PosXY.Y + d.Height, 130, 130);
g.DrawLine(new Pen(Color.Black), new Point(d.PosXY.X + d.Drone.Width / 2, d.PosXY.Y + d.Drone.Height / 2), new Point(d.PosXY.X + d.Height + d.Drone.Width / 2, d.PosXY.Y + d.Height + d.Drone.Height / 2));
//g.DrawImage(bmp, new Rectangle(d.PosXY.X+32, d.PosXY.Y, 65, 130));
float x1 = 0, y1 = 0;
float x2 = 130, y2 = 0;
float x3 = 0, y3 = 130;
const float TO_RADI = MathF.PI / 180;
Quaternion tilt = new Quaternion(d.TiltXY.X, d.TiltXY.Y, 0, 0);
Quaternion rotate = Quaternion.CreateFromAxisAngle(new Vector3(0, 0, 1), d.Azimuth * TO_RADI);
tilt = tilt * rotate * rotate;
if (tilt.Y > 0)
try
{
x1 = (int)(Math.Sin(tilt.Y) * 130);
x3 = (int)(Math.Sin(tilt.Y) * 130);
}
else
{
x2 = (int)(Math.Cos(tilt.Y) * 130);
}
if (d.Azimuth >= 360) d.Azimuth -= 360;
var bmp = RotateImage(d.Drone, d.Azimuth);
if (tilt.X > 0)
{
y1 = (int)(Math.Sin(tilt.X) * 130);
y2 = (int)(Math.Sin(tilt.X) * 130);
}
else
{
y3 = (int)(Math.Cos(tilt.X) * 130);
}
g.FillEllipse(new SolidBrush(Color.FromArgb(50, d.RGB)), d.PosXY.X + d.Height, d.PosXY.Y + d.Height, 130, 130);
PointF ul = new PointF(d.PosXY.X + x1, d.PosXY.Y + y1); PointF ur = new PointF(d.PosXY.X + x2, d.PosXY.Y + y2);
PointF dl = new PointF(d.PosXY.X + x3, d.PosXY.Y + y3);
PointF[] dest = { ul, ur, dl };
g.DrawLine(new Pen(Color.Black), new Point(d.PosXY.X + d.Drone.Width / 2, d.PosXY.Y + d.Drone.Height / 2), new Point(d.PosXY.X + d.Height + d.Drone.Width / 2, d.PosXY.Y + d.Height + d.Drone.Height / 2));
g.DrawImage(bmp, dest);
//g.DrawImage(bmp, new Rectangle(d.PosXY.X+32, d.PosXY.Y, 65, 130));
float x1 = 0, y1 = 0;
float x2 = 130, y2 = 0;
float x3 = 0, y3 = 130;
const float TO_RADI = MathF.PI / 180;
Quaternion tilt = new Quaternion(d.TiltXY.X, d.TiltXY.Y, 0, 0);
Quaternion rotate = Quaternion.CreateFromAxisAngle(new Vector3(0, 0, 1), d.Azimuth * TO_RADI);
tilt = tilt * rotate * rotate;
if (tilt.Y > 0)
{
x1 = (int)(Math.Sin(tilt.Y) * 130);
x3 = (int)(Math.Sin(tilt.Y) * 130);
}
else
{
x2 = (int)(Math.Cos(tilt.Y) * 130);
}
if (tilt.X > 0)
{
y1 = (int)(Math.Sin(tilt.X) * 130);
y2 = (int)(Math.Sin(tilt.X) * 130);
}
else
{
y3 = (int)(Math.Cos(tilt.X) * 130);
}
PointF ul = new PointF(d.PosXY.X + x1, d.PosXY.Y + y1); PointF ur = new PointF(d.PosXY.X + x2, d.PosXY.Y + y2);
PointF dl = new PointF(d.PosXY.X + x3, d.PosXY.Y + y3);
PointF[] dest = { ul, ur, dl };
g.DrawImage(bmp, dest);
}
catch { }
}
}

View File

@ -0,0 +1,39 @@
using System.Numerics;
namespace VisualData
{
public struct VisualHead
{
public enum VisualType : int { None = 0, Drone = 1 } // Тип объекта
public int Size; // Размер данных этой структуры в байтах (проверка для соответствия передачи структуры)
public VisualType Type; // Тип передоваемого объекта
}
public struct VisualDrone
{
public VisualHead Head;
public enum DroneState : int { Dead = 0, Disabled = 1, Waiting = 2, Active = 3 } // Переключения типа 3D модели
public int Count; // Всего дронов на полигоне
public int Index; // Номер дрона
public int ID; // Идентификатор (для привязки камеры)
public struct ARGB { public byte A, R, G, B; }
public struct Quat { public float X, Y, Z, W; }
public struct Vect3 { public float X, Y, Z; }
public ARGB Color; // Цвет корпуса
public Quat Rotate; // Кватернион вращения
public Vect3 Position; // Координаты в пространстве
public float Scale; // Масштаб модельки (1=оригинальный)
public DroneState State; // Тип прорисовываемой модели
public float Power; // Скорость всех двигателей
}
}

View File

@ -1 +0,0 @@
Hi!!!