API Question I need help deciphering Dragonfly's "Pulse Mode"

Hlynkacg

Aspiring rocket scientist
Addon Developer
Tutorial Publisher
Donator
Joined
Dec 27, 2010
Messages
1,870
Reaction score
3
Points
0
Location
San Diego
The way that "pulse mode" works is that rather than directly controlling the throttle each individual movement of a joystick out of the center position (or press of a button) impart's a certain amount of dV or rotational velocity.

The stock dragonfly has this functionality and I am trying to adapt it to my own addon.

I've copy/pasted portions of the dragonfly's code into my Lunar Lander and even have the pulse control mode kind off working. The problem is that I have no idea how the function actually works so I can debug it.

I need someone who's code-fu is stronger to help explain what is going on.

here is the pertinent code as it appears in my clbkpoststep
Code:
// pulse control (copied from stock Dragonfly's thruster controls)
double tlevel; // thruster setting
double tlevel_r; // reciprical of 'tlevel'
static int lin_x,lin_y,lin_z;
static int rot_x,rot_y,rot_z;

if ((tlevel = GetManualControlLevel(THGROUP_ATT_PITCHUP, MANCTRL_ANYDEVICE, MANCTRL_ROTMODE)) && (!rot_x++)) SetThrusterGroupLevel(th_rot_pup, tlevel*dlevel); 
if ((tlevel_r = GetManualControlLevel(THGROUP_ATT_PITCHDOWN, MANCTRL_ANYDEVICE, MANCTRL_ROTMODE)) && (!rot_x++)) SetThrusterGroupLevel(th_rot_pdown, tlevel_r*dlevel);
if (tlevel + tlevel_r==0) rot_x=0;

...repeats for each axis in turn

It works too, the problem is that as soon as I try to put it in a boolean or switch function (so the orbinaut can turn pulse mode on/off) all hell breaks loose.

My thruster settings either become stuck or the just start firing off randomly.

I need some help to figure out what's going on.
:hailprobe:
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,627
Reaction score
2,345
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
The first expression is simple:

"Set tlevel to the manual input level and interpret this as true, if tlevel is not zero afterwards."

This is because the assignment operator returns a constant return value to which value the variable was set, because you can this way construct statements like:

Code:
a = b = c = 0;

Which is interpreted as:

Code:
a = (b = (c = 0));

"!rot_x++" means in simple English:

  1. Return true if rot_x is zero.
  2. After the statement as been executed, increment rot_x by 1.

Yes, it is valid C++ code. No, it is not nice. It is terrible to maintain such code and it produces no better machine code than a multi-line version of it.

Especially the rot_x variable is pretty annoying there, since it is essentially only a flag: If thruster was already fired and ignition signal was not reset, inhibit a second firing.

What makes the code especially bad: rot_x is static. It is the same variable for ANY Dragonfly in the simulation. You can imagine what happens if you have two Dragonflys trying to use the pulse mode. Luckily it never manifests itself as long as the pulse mode only activates on user input, since Orbiter is single-user.

It is also time-step dependent and as such terrible for accurate simulations: Depending on your framerate, the thruster will produce different impulses. dlevel is no way to correct this unless your firing interval is ALWAYS shorter than a timestep.
 

Hlynkacg

Aspiring rocket scientist
Addon Developer
Tutorial Publisher
Donator
Joined
Dec 27, 2010
Messages
1,870
Reaction score
3
Points
0
Location
San Diego
"Set tlevel to the manual input level and interpret this as true, if tlevel is not zero afterwards."

This is because the assignment operator returns a constant return value to which value the variable was set, because you can this way construct statements

Where is the setting done? I would have expected this to happen prior the if statement not within.

"!rot_x++" means in simple English:

  1. Return true if rot_x is zero.
  2. After the statement as been executed, increment rot_x by 1.

Yes, it is valid C++ code. No, it is not nice. It is terrible to maintain such code and it produces no better machine code than a multi-line version of it.

Especially the rot_x variable is pretty annoying there, since it is essentially only a flag: If thruster was already fired and ignition signal was not reset, inhibit a second firing.

I figured it was something like that but was unsure. Nice to have my intuition confirmed.

What makes the code especially bad: rot_x is static. It is the same variable for ANY Dragonfly in the simulation. You can imagine what happens if you have two Dragonflys trying to use the pulse mode. Luckily it never manifests itself as long as the pulse mode only activates on user input, since Orbiter is single-user.

It is also time-step dependent and as such terrible for accurate simulations: Depending on your framerate, the thruster will produce different impulses. dlevel is no way to correct this unless your firing interval is ALWAYS shorter than a timestep.

x_rot's staticness jumped out at me as well and I thought it might be the source of some of the other issues I was having.

In general how would you suggest going about cleaning it up?
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,627
Reaction score
2,345
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
Where is the setting done? I would have expected this to happen prior the if statement not within.

In the if statement. Remember:

= is the assignment operator
== is the equality comparison operator

It is a common error to use = instead of == in an if statement, because both is valid code for the compiler, but there is an important difference in the runtime behavior.

If you write "if(a = b)" it will only considered to be true, if b is not zero, and a will be set to b.

(Thus the good old trick of writing the constant on the left side of a comparison. "0 = b" is a compiler error, "b = 0" is not)
 

Hlynkacg

Aspiring rocket scientist
Addon Developer
Tutorial Publisher
Donator
Joined
Dec 27, 2010
Messages
1,870
Reaction score
3
Points
0
Location
San Diego
Thank you, i've got it working for the most part now but I do have a further question...

It is also time-step dependent and as such terrible for accurate simulations: Depending on your framerate, the thruster will produce different impulses. dlevel is no way to correct this unless your firing interval is ALWAYS shorter than a timestep.

How would you go about solving this bit?

I want to be able to make my thruster pulses consistantly .2 seconds but I don't know how.
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,627
Reaction score
2,345
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
Have a countdown variable for each thruster (or thruster group) and use it like that:

if countdown bigger than length of timestep: Apply full thrust
if countdown smaller than length of timestep: Apply full thrust * countdown/length of timestep.
 
Top