Hello,
I’m working on a project which takes data from DCS world ( a flight simulator ) and sends it to an Arduino UNO via a program written in C#.
The way it does this is via a plugin for the simulator called export.lua.
I’ve just used an example provided by eagle dynamics (dev of DCS) .
I have no experience in LUA but just used the example and adjusted it to my needs
MainPanel = GetDevice(0)
function LuaExportStart()
package.path = package.path..";"..lfs.currentdir().."/LuaSocket/?.lua"
package.cpath = package.cpath..";"..lfs.currentdir().."/LuaSocket/?.dll"
socket = require("socket")
IPAddress = "127.0.0.1"
Port = 31090
MySocket = socket.try(socket.connect(IPAddress, Port))
MySocket:setoption("tcp-nodelay",true)
end
function LuaExportBeforeNextFrame()
end
function LuaExportAfterNextFrame()
--getting all the variables:
local pitch, bank, yaw = LoGetADIPitchBankYaw() -- Pitch, bank & yaw in radians
local AccelX = LoGetAccelerationUnits().x -- X-acceleration (G)
local AccelY = LoGetAccelerationUnits().y -- Y-acceleration (G)
local AccelZ = LoGetAccelerationUnits().z -- Z-acceleration (G)
local PitchAngularVelocity= LoGetAngularVelocity().x -- Rotation speed around x (pitch in rad/s)
local RollAngularVelocity = LoGetAngularVelocity().y -- Rotation speed around y (roll in rad/s)
-- Rotation speed around z (yaw in rad/s)
local PitchAngularAcceleration = LoGetHelicopterFMData().angular_acceleration.x -- Pitch angular acceleration (rad/s2)
local RollAngularAcceleration = LoGetHelicopterFMData().angular_acceleration.y -- Roll angular acceleration (rad/s2)
-- Yaw angular acceleration (rad/s2)
local AirborneState = LoGetAltitudeAboveGroundLevel()
--Sending it in the string format required for arduino
socket.try(MySocket:send(string.format("<Data: \n Game:3 \n Pitch: %.2f \n PitchAngularAcceleration:%.2f \n Bank:%.2f \n RollAngularAcceleration: %.2f \n AccelX: %.2f \n AccelY: %.2f \n AccelZ:%.2f \n Xseat: %.2f \n Yseat:%.2f \n Simstate:%.2f \n Airbornestate:%.2f \n Crashstate:%.2f \n,> \n",
pitch * 57.2958,
PitchAngularAcceleration,
bank,
RollAngularAcceleration,
AccelX,
AccelY,
AccelZ,
Xseat,
YSeat,
Simstate,
AirborneState,
Crashstate
)))
end
function LuaExportStop()
if MySocket then
socket.try(MySocket:send("exit"))
MySocket:close()
end
end
function LuaExportActivityNextEvent(t)
end
The way the string is formatted is important for the arduino part:
<Data, Game, Pitch, PitchAngularAcceleration, Roll, RollAngularAcceleration, AccelX, AccelY, AccelZ, AccelXSeat,AccelYSeat, SimState, AirborneState, crashstate, >
The code used in the C# program:
public MainWindow()
{
InitializeComponent();
SendTimer.Interval = TimeSpan.FromMilliseconds(10); // Timer to send data at specified interval (ms)
Ports = SerialPort.GetPortNames(); // storing available ports
foreach (var port in Ports)
{
PortSelection.Items.Add(port); // adding available ports to dropdown box
}
if (PortSelection.SelectedValue == null) // Setting the first item in the portselection
{ // combobox to prevent NULL exception.
PortSelection.SelectedIndex = 0;
}
ComBridge.BaudRate = 115200;
listener.Start(); // Start listener for DCS connection
}
private void DCS_Tick(object sender, EventArgs e)
{
DCSStream = reader.ReadLine();
DCSDataBox.Text = DCSStream;
ComBridge.Write(DCSStream);
}
I'm adding following method to the timer tick via a button click:
SendTimer.Tick += DCS_Tick;
The code used in the Arduino program:
//experimental
#include <AccelStepper.h>
#define FULLSTEP 4
#define HALFSTEP 8
//Seat motor
const int MotorPin1 = 2;
const int MotorPin2 = 3;
const int MotorPin3 = 4;
const int MotorPin4 = 5;
AccelStepper Motor (HALFSTEP, MotorPin1, MotorPin3, MotorPin2, MotorPin4);
const byte numChars = 250;
char receivedChars[numChars];
char tempChars[numChars]; // temporary array for use when parsing
// variables to hold the parsed data
char messageFromPC[numChars] = {0};
float Game = 0.0;
float Pitch = 0.0;
float PitchAngularAcceleration = 0.0;
float Roll = 0.0;
float RollAngularAcceleration = 0.0;
float AccelX = 0.0;
float AccelY = 0.0;
float AccelZ = 0.0;
float SimState = 0.0;
float AirborneState = 0.0;
float AccelXConstant = 0.0;
float AccelYConstant = 0.0;
float CrashState = 0.0;
unsigned long currentMill = 0;
unsigned long previousMillis = 0;
const long interval = 100;
float positiveDifference = 544; //90 * 11 * 0,6
float negativeDifference = -544;
boolean newData = false;
//=============================================================================================================================================================================================================================
//=============================================================================================================================================================================================================================
void setup() {
Serial.begin(115200);
}
//========================================================================================================================================================================================================================================================================
//========================================================================================================================================================================================================================================================================
void loop() {
Motor.setAcceleration(2000);
Motor.setMaxSpeed(1000);
Motor.moveTo(-Pitch);
Motor.run();
//================================================================================================================================================================================================================================================================================================================
//================================== storing the values of the sim ================================
//=================================================================================================
recvWithStartEndMarkers();
if (newData == true) {
strcpy(tempChars, receivedChars);
// this temporary copy is necessary to protect the original data
// because strtok() used in parseData() replaces the commas with \0
parseData();
newData = false;
}
}
//======================= method for storing the serial data =============================================
void recvWithStartEndMarkers() { //part where we tell te program that '<' is the start of the data and '>' the end.
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
//============
void parseData() { // split the data into its parts
char * strtokIndx; // this is used by strtok() as an index
strtokIndx = strtok(tempChars, ","); // get the first part - the string
strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC
strtokIndx = strtok(NULL, ",");
Game = atof(strtokIndx); // convert the Game value to a float (1 = Xplane 11 , 2 = Assetto Corsa (Competizione)
strtokIndx = strtok(NULL, ",");
Pitch = atof(strtokIndx); // convert the pitch value to a float
strtokIndx = strtok(NULL, ",");
PitchAngularAcceleration = atof(strtokIndx); // convert the PitchAngularAcceleration value to a float
strtokIndx = strtok(NULL, ",");
Roll = atof(strtokIndx); // convert the Roll value to a float
strtokIndx = strtok(NULL, ",");
RollAngularAcceleration = atof(strtokIndx); // convert the RollAngularAcceleration value to a float
strtokIndx = strtok(NULL, ",");
AccelX = atof(strtokIndx); // convert the accelX value to a float
strtokIndx = strtok(NULL, ",");
AccelY = atof(strtokIndx); // convert the accelY value to a float
strtokIndx = strtok(NULL, ",");
AccelZ = atof(strtokIndx); // convert the accelZ value to a float
strtokIndx = strtok(NULL, ",");
AccelXConstant = atof(strtokIndx); // convert the AccelXConstant value to a float
strtokIndx = strtok(NULL, ",");
AccelYConstant = atof(strtokIndx); // convert the AccelYConstant value to a float
strtokIndx = strtok(NULL, ",");
SimState = atof(strtokIndx); // convert the simstate value to a float
strtokIndx = strtok(NULL, ",");
AirborneState = atof(strtokIndx); // convert the airbornestate value to a float
strtokIndx = strtok(NULL, ",");
CrashState = atof(strtokIndx); // convert the CrashState value to a float
}
//============================================================================================
//==================================================================================================================================================================
I’m getting the data out of DCS, but there seems to be a significant delay for the motor to move. (couple of seconds.)
I’m using a single motor as output just to test the data.
When I’m using a console application to check the data, so not sending it to the Arduino, there seems to be no delay so my guess would be that the serial communication is causing this delay.
Could anyone provide me with an insight as to why this delay might be happening and how to possibly solve it?
Does the TCP communication have anything to do with it?
Would communicating via UDP solve it?
Rgds