To MAP() or not to MAP()

Greetings.
I am continuing with my home cockpit using X-Plane and have come to an abrupt stop in attempting to interface a flaps gauge.

On my flaps gauge indicator (of which, there are two on my instrument panel, 1 for outboard flaps, 1 for inboard flaps), there are 8 positions which represent the degrees of flap deployment during flight operations. These positions are represented as degrees….0, 2, 5, 15, 20, 25, 30 and 40. Internally, they are operated with synchro receivers which will be driven by a stand alone NEMA stepper motor and using the AccelStepper library function to include step and direction for the sake of simplicity (e.g., only 2 pins to/from the DRV8825 board and stepper). The steppers are meshed with external gears to a synchro transmitter to send signals to the gauge’s internal synchro receiver.
Each position has a data ref, which is a value assigned by X-Plane for each flap position. Thes values remain constant for each flap setting.
Given my limited knowledge of the MAP() function, I do not believe there is a way to accurately map values; The data refs values are as follows:
0 = 0
2 = 0.142857
5 = 0.285714
15 = 0.428571
20 = 0.571429
25 = 0.714286
30 = 0.857143
40 = 1
With the map() function, fractional values are truncated and are not rounded. I have considered defining each value as an integer but am not sure if this is a possibility.

I will post the sketch I’ve compiled when I’m at home and have access to the PC it is loaded on.

In the meantime, I would appreciate thoughts on this so I can proceed.

Thank you kindly in advance.

Jay

I'm not sure that map() is what you want. The relationships between the 2 sets of numbers is not linear.

The map() function only does linear interpolation on integers. The mapping from degrees to number is not linear.

Is there a defined curve from which the numbers are derived?

If you only need those 8 steps, just keep a table of values and pick the nearest one. If you want all values from 0.0 to 40.0 you really need a formula but you might get by with piecewise linear interpolation (the value for 35 would be halfway between the defined value for 30 (0.857143) and the defined value for 40 (1.0)).

A straight line fit to the data is not all that bad. You need to decide how much you can believe the supplied data points, and how much error you can live with.

Capture

1 Like

The 'data points' turn out to be the array index divided by 7:

0 = 0 = 0/7
2 = 0.142857 = 1/7
5 = 0.285714 = 2/7
15 = 0.428571 = 3/7
20 = 0.571429 = 4/7
25 = 0.714286 = 5/7
30 = 0.857143 = 6/7
40 = 1 = 7/7

I wonder whether the first column of data points is believable.

In this case, the measuring sensor is still cold. :wink:

I mention the map() function because years ago, I had seen a similar flaps gauge operating and it used the map() function. Granted, the values were all integers (operating with Flight Sim X) but since X-Plane (in this case) uses exact and fractional values, I cannot replicate nor modify that original sketch.
Am getting ready to board a trans-con flight right now and will post more on this topic later. I’ll include my ‘inspiration’ from the old sketch I had seen and what I’d complied thus far, which gives me minimal success, in that the gauge moves exactly as designed and matches what’s happening in the flight sim from 0-degrees to 2-degrees and from 2-degrees to 5-degrees but from 5-degrees to anything higher, the stepper speeds-up considerably and is no where close when it stops on the selected setting.
Frustrating.

Actually, I do have that map() function from the original FSX script on my iPhine here, albeit not in code format:
if (flapMeasure==0){ //Flaps 0 on 737 in FSX
return 0;
}
if (flapMeasure==1){ //Flaps 1
return 36;
}
if (flapMeasure==3){ //Flaps 2
return 72;
}
if (flapMeasure<=7){ //Flaps 5 Setting
return map(flapMeasure, 3, 7, 72, 114);
}
if (flapMeasure<=14){ //Flaps 10 Setting
return map(flapMeasure, 7, 14, 114, 146);
}
if (flapMeasure<=21){ //Flaps 15 Setting
return map(flapMeasure, 14, 21, 146, 180);
}
if (flapMeasure<=36){ //Flaps 25
return map(flapMeasure, 21, 36, 180, 215);
}
if (flapMeasure<=43){ //Flaps 30
return map(flapMeasure, 36, 43, 215, 240);
}
else{
return map(flapMeasure, 43, 57, 240, 270);

More later when I can get to my PC at home.

Thank you, in advance, for the interest and replies thus far.

Jay

UPDATE——

As luck would have it, I do have MY sketch for X-Plane where it does work except for settingsabove 5-degrees:

FLAPS GAUGE T E S T I N G

// FLAPS GAUGES TESTING
//

// 208000 steps/revolution
// 1/32 micro-stepping

// Stepper motor.. 92 teeth
// Transmitter.... 92 teeth

#include <AccelStepper.h>

AccelStepper FLAPSobL(1, 16, 17); //1=Library function, 16=Step, 17=Dir Outboard Left flaps position
AccelStepper FLAPSobR(1, 14, 15); //1=Library function, 14=Step, 15=Dir Outboard Right flaps position

FlightSimFloat FlapOBleft;
FlightSimFloat FlapOBright;

float FLAPSobL_pos; // Outboard LEFT
float FLAPSobR_pos; // Outboard RIGHT

const long STEPS_PER_REVOLUTION = 208000;
const float STEPS_PER_DEGREE = ((float) STEPS_PER_REVOLUTION) / 360.0;

void setup() {
Serial.begin(9600);
FLAPSobL.setMaxSpeed(2000);
FLAPSobL.setAcceleration(500);
FLAPSobR.setMaxSpeed(2000);
FLAPSobR.setAcceleration(500);

FlapOBleft = XPlaneRef("sim/flightmodel2/wing/flap2_deg[2]");
FlapOBright = XPlaneRef("sim/flightmodel2/wing/flap2_deg[3]");
}

void loop() {
FlightSim.update();

FLAPSobL_pos = FlapOBleft * STEPS_PER_DEGREE;
FLAPSobL.moveTo(FLAPSobL_pos);
FLAPSobL.run();
FLAPSobR_pos = FlapOBright * STEPS_PER_DEGREE;
FLAPSobR.moveTo(FLAPSobR_pos);
FLAPSobR.run();

}

After a long (and delayed flight…thank God for lie-flat seats and unlimited adult beverages), I am home and trying to solve this dilemma of mine.
Somewhere between the second and third drink last night, I got to thinking about possible options to get the stepper to move ‘in time’ with the flight sim’s gauge(s) and not race like a bat from Hell above the 5-degree setting.
Is it possible to assign integers for the various fractional values (e.g., 0=0, 2=0.85714, 5=0.285714, 15=0.428571, etc.) and THEN use the map() function?
These seems logical to me, however, being a relative newcomer to coding/writing sketches and based upon my limited knowledge, I’m unsure if this is feasible.
I’m anxious to learn any thoughts on this.

Thank you again for your valuable input.

Jay

Those values 0,2,5,15,20,25,30 & 40 are digital values you receive from X-Plane? (It's been a long time since I played with X-Plane).

So the 5 will always be 5 and not 4.9 or 5.1? If so, then you could use a simple switch statement or a bunch of if .. else if statements to return those specific fractional values you need.

Note that if those fractional values from 0 to 1 then have to be converted into other values to drive the flaps gauge, then you can skip the additional conversion step and just return the actual values needed to make the flaps gauge go to the specific positions you need.

Multiply the value given by seven, round up, and take the integer part.
Use integer part as array index.

Mark;
Thanks for the reply!
The 0, 5, 15, 20, 25, 30 and 40 are the degrees of flaps and are not editable.
Their values are the 0, 0.85714, 0.142857, 0.285714, 0.428571, 0.571429, etc. These fractional values are the data ref values from X-Plane for each flap setting and also are not editable.
Since map() is not possible with non-integer values, I am wondering if each data ref value could be assigned as an integer and then use the map() and return map() functions.
I hope I’m making sense here.
I’m curious to learn more about your if/else statement proposition.
Jay

This will give you an index from 0 to 7 that you can use to look up the flap degrees in a table:

const byte flapDegrees[] = {0, 2, 15, 20, 25, 30, 40};

int index = (data_ref * 7) + 0.5;
int degrees = flapDegrees[index];

Ah, ok, so XPlane sends those fractional values. Do they come across as ASCII text or binary? If it's ASCII text, then you can look at the 1st digit after the decimal point to determine which flap setting it relates to. If binary, then you probably need to carry out a range based comparison as checking for exact values with floating point numbers almost always fails due to the approximation of the floating point value. For your 0.85714 value, you could check if the received value is greater than 0.8 but less than 0.9 for example.

I lost all internet/wi-fi and TV access yesterday at my house, courtesy of my local cable provider. Then, on the way to a friend’s house to watch MLB and get online with the world, was involved in an auto accident. No, it was not a good day. No injuries, thank God; just a major inconvenience with a police report, insurance company b.s. and scrambling to rent a car. My first experience with airbags deploying…
So my Friday was a complete write-off!!!

@johnwasser Very interesting prospect here.

const byte flapDegrees[] = {0, 2, 5, 15, 20, 25, 30, 40};

int index = (data_ref * 7) + 0.5;
int degrees = flapDegrees[index];
(I added the ‘5’ degree to yours.)

I’m unclear as to where/how I should include the actual fractional values for each setting; each data ref value isn’t ‘read’ by X-Plane as a specific flap degree as shown in your brilliant “const byte” definition but rather by their assigned fractional values.

I’d certainly appreciate additional conversation on this.

Here’s to a MUCH better day today!

Thank you, all, again.

Jay

@markd833
Given my limited knowledge on the topic, I can’t say with any amount of certainty if it’s binary or ASCII…the fractional values within X-Plane change when a setting is selected.

Jay

What do you want to do with the flap angles?

Is there not an X-Plane manual that tells you this sort of thing. In the ancient version of X-Plane I used a long time ago, I think that X-Plane sent out as UDP packets of data over a LAN.

Ok, I think I found something. This link below is to the X-Plane 11 desktop manual and the data i/o.
https://www.x-plane.com/manuals/desktop/#datainputandoutputfromx-plane

That seems to be how you tell X-Plane what you are interested in. A lot more user friendly that it was when I used X-Plane!

The following is a github page from NASA (yep, the space people!)

Look at the FORMAT section at the start for the letter codes you need. Then scroll down to the CTRL section. That details the UDP packet that sends out the control surfaces positions (amongst other things). Flaps are a 32-bit float at byte position 22,23,24 & 25, so it's binary data.

I'm not clear on how much progress you have made in receiving this data. Have you been able to receive the packet from X-Plane and maybe simply print out in ASCII the raw packet contents?

My best guess is that it is supposed to work like this:

// FLAPS GAUGES TESTING
//

// 208000 steps/revolution
// 1/32 micro-stepping

// Stepper motor.. 92 teeth
// Transmitter.... 92 teeth

#include <AccelStepper.h>

AccelStepper FLAPSobL(1, 16, 17); //1=Library function, 16=Step, 17=Dir Outboard Left flaps position
AccelStepper FLAPSobR(1, 14, 15); //1=Library function, 14=Step, 15=Dir Outboard Right flaps position

FlightSimFloat FlapOBleft;
FlightSimFloat FlapOBright;

float FLAPSobL_pos; // Outboard LEFT
float FLAPSobR_pos; // Outboard RIGHT

const long STEPS_PER_REVOLUTION = 208000;
const float STEPS_PER_DEGREE = ((float) STEPS_PER_REVOLUTION) / 360.0;

const byte FlapDegrees[] = {0, 2, 15, 20, 25, 30, 40};


void setup()
{
  Serial.begin(9600);
  FLAPSobL.setMaxSpeed(2000);
  FLAPSobL.setAcceleration(500);
  FLAPSobR.setMaxSpeed(2000);
  FLAPSobR.setAcceleration(500);

  FlapOBleft = XPlaneRef("sim/flightmodel2/wing/flap2_deg[2]");
  FlapOBright = XPlaneRef("sim/flightmodel2/wing/flap2_deg[3]");
}

void loop()
{
  FLAPSobL.run();
  FLAPSobR.run();

  FlightSim.update();

  int degrees;
  
  degrees = FlapDegrees[int((FlapOBleft * 7) + 0.5)];
  FLAPSobL_pos = degrees * STEPS_PER_DEGREE;
  FLAPSobL.moveTo(FLAPSobL_pos);

  degrees = FlapDegrees[int((FlapOBright * 7) + 0.5)];
  FLAPSobR_pos = degrees * STEPS_PER_DEGREE;
  FLAPSobR.moveTo(FLAPSobR_pos);
}