Board index FlightGear Support Hardware

Writing Joystick Code - wiki article  Topic is solved

Joysticks, pedals, monitors.

Re: Writing Joystick Code - wiki article

Postby macnab » Tue Oct 16, 2012 2:20 pm

If there is no chance of modifiers, then on the list of "possibles" I suggest (not in any order), for beginners:
Gear
Flaps
Elevator Trim
Aileron Trim
Leave the hat as look around.
Throttle
Brakes
Reverse Thrust (Beginners love to start off with the 777 as their first attempt at flying.)

That's 7 buttons. A lot for most joysticks.

If they have more buttons:
Propeller-Pitch
I don't know if anyone uses Mixture, as it's all virtual-fuel.
Spoilers.
Adjust-Heading-Bug
Condition (although you could make it that mixture and condition are both adjusted with one button, as they are mutually exclusive.)

That's my 10c worth.
macnab
 
Posts: 886
Joined: Tue Aug 02, 2011 7:20 am
Location: Johannesburg, South Africa
Callsign: ZS-ILH
Version: Git
OS: Win7Pro 64bit SP1

Re: Writing Joystick Code - wiki article

Postby macnab » Tue Oct 16, 2012 2:29 pm

Stuart, another suggestion.

With the trims, add these:
Code: Select all
  gui.popupTip(sprintf("Elevator-trim: %.2f", 4.5 * getprop("/controls/flight/elevator-trim")));
  gui.popupTip(sprintf("Aileron-trim: %.3f", getprop("/controls/flight/aileron-trim")));


Having a visual display of trim setting is a real boon.

Or maybe it should be added permanently to controls.nas? I'm sure no-one will complain.
macnab
 
Posts: 886
Joined: Tue Aug 02, 2011 7:20 am
Location: Johannesburg, South Africa
Callsign: ZS-ILH
Version: Git
OS: Win7Pro 64bit SP1

Re: Writing Joystick Code - wiki article

Postby Philosopher » Tue Oct 16, 2012 2:36 pm

macnab wrote in Tue Oct 16, 2012 1:56 pm:
Also, you might want to make a helper function for non-repeatable trim


Done. Aileron, Elevator, Rudder trims, and also Throttle, Propeller-Pitch and Mixture. See further up this thread. :D


Sorry, I meant that you should make a function that accepts two things: a name of the property it's going to interpolate and the value that is usually passed to startElevatorTrim (or whatever). Then it would look like this:
Code: Select all
startElevatorTrim = func(n) {startInterpolation("/controls/flight/elevator-trim", n)};

And then:
Code: Select all
stopElevatorTrim = func {startInterpolation("/controls/flight/elevator-trim", 0)};

Then you only need the code that does the interpolation proper in one place (controms.startInterpolation) and just call it wherever it's needed.
Thanks,
Philosopher
(inactive but lurking occasionally...)
Philosopher
 
Posts: 1590
Joined: Sun Aug 12, 2012 6:29 pm
Location: Stuck in my head...
Callsign: AFTI
Version: Git
OS: Mac OS X 10.7.5

Re: Writing Joystick Code - wiki article

Postby macnab » Tue Oct 16, 2012 2:59 pm

startElevatorTrim = func(n) {startInterpolation("/controls/flight/elevator-trim", n)};


I presume you mean have only startInterpolation in controls.nas?

The whole point of the exercise is to make xml code shorter, because parsing it is slow. Hence all the code being in controls.nas.

What I could have done, but I didn't think it really necessary, is to do something along the lines of perIndexAxisHandler and have:
Code: Select all
controls.startTrim(x,n)

where x is 1 for aileron, 2 for elevator and 3 for rudder. And n is of course -1, 0, 1.
macnab
 
Posts: 886
Joined: Tue Aug 02, 2011 7:20 am
Location: Johannesburg, South Africa
Callsign: ZS-ILH
Version: Git
OS: Win7Pro 64bit SP1

Re: Writing Joystick Code - wiki article

Postby macnab » Tue Oct 16, 2012 3:15 pm

On reflection I think maybe you meant, in controls.nas, define a function doInterpolation, with all the ifs and buts in it, and then call it from the 3 startTrim functions. Less repetition of code. Good idea. it also makes doInterpolation available for other things.

I'll do that tomorrow. Now it is time for a glass of wine and supper, and then read. If I don't clear my mind of forthcoming tasks, I don't sleep. :(
macnab
 
Posts: 886
Joined: Tue Aug 02, 2011 7:20 am
Location: Johannesburg, South Africa
Callsign: ZS-ILH
Version: Git
OS: Win7Pro 64bit SP1

Re: Writing Joystick Code - wiki article

Postby Philosopher » Tue Oct 16, 2012 11:06 pm

Yeah, that's what I was suggesting. Just copy the idea of perIndexAxisHandler if I am/was unclear.

Don't stay up 'till 1 reading your book ;),
Philosopher
Thanks,
Philosopher
(inactive but lurking occasionally...)
Philosopher
 
Posts: 1590
Joined: Sun Aug 12, 2012 6:29 pm
Location: Stuck in my head...
Callsign: AFTI
Version: Git
OS: Mac OS X 10.7.5

Re: Writing Joystick Code - wiki article

Postby macnab » Wed Oct 17, 2012 8:46 am

Ok. I've rationalised the code.


We now have:

Surface
startTrimElevator(x)
startTrimAileron(x)
startTrimRudder(x)

Where x is -1, 0, 1.

For those who are using modes and need to pass a variable
startTrimSurface(s, x)

Where s is 0 = aileron, 1 = elevator, 2 = rudder. Alphabetic to aid memory.


Engines
startAdjustThrottle(x, e...)
startAdjustMixture(x, e...)
startAdjustPropeller(x, e...)

e is optional. If left out, does all engines. If included, is in the form e1, e2, e3, ...

For those who are using modes and need to pass variables
startAdjustEngine(a, x, e...)

a is 0 = throttle, 1 = mixture, 2 = propeller-pitch. Same as perIndexAxisHandler.

Examples
Increase throttle for all engines
startAdjustThrottle(1)

Increase throttle for engines 3 and 5
startAdjustThrottle(1, 3, 5)

Increase throttle for engines 2, 4, and 6
startAdjustEngines(0,1, 2, 4, 6)

Increase throttle for all engines
startAdjustEngines(0, 1)

This should satisfy everybody's needs.

I'll wait for comments before I ask for a commit.

Here is the code for those interested in looking at it
Code: Select all
##
# Do trim interpolations.
# Don't call from other contexts.
# Arg[0] is the node for the surface to be trimmed. Arg[1] is the starting point.
# Arg[2] is the direction.
# Force dir to be +1 or - 1
var doTrimInterpolation = func(which, start, dir) {
    var diff = 0;
    var speed = 30;

    if (dir == 0) {
         # Stop interpolate
         interpolate(which, start, 0);
         return;
    }

    if (dir < 0) {
        # Head towards -1. Calculate diff depending on sign of current position.
        dir = -1;
        if (start >= 0) {
            diff = 1 + start
        } else {
            diff = 1 - abs(start)
        }
    }

    if (dir > 0) {
        # Head towards +1. Calculate diff depending on sign of current position.
        dir = 1;
        if (start <= 0) {
            diff = 1 + abs(start)
        } else {
            diff = 1 - start
        }
    }
   
    interpolate(which, dir, diff * speed)
}

##
# Trim aileron, elevator and rudder with non-repeating buttons.
# Pressing button callsstartTrimxxxx(-1 or +1). Non-repeating button, so nothing else
# happens until button is released, which calls startTrimxxxx(0).
# in zero seconds, stopping interpolation and trim.
#
# If the argument is 0, stop interpolation at current position. Otherwise start interpolate, either positive or negative.
#
# eg  startTrimElevator(-1) starts trimming the elevator and stops it when startTrimElevator(0) received.
# Takes 30 seconds to get from 0 to extremes. Scaled if not starting at 0.
#
var startTrimElevator = func(dir) {
    var node = props.globals.getNode("/controls/flight/elevator-trim");
    var current = node.getValue();

    doTrimInterpolation(node, current, dir)
}

var startTrimAileron = func(dir) {
    var node = props.globals.getNode("/controls/flight/aileron-trim");
    var current = node.getValue();

    doTrimInterpolation(node, current, dir)
}

var startTrimRudder = func(dir) {
    var node = props.globals.getNode("/controls/flight/rudder-trim");
    var current = node.getValue();

    doTrimInterpolation(node, current, dir)
}

##
# Trim surface
# Calls startTrimAileron, startTrimElevator, startTrimRudder according to arg[0].
#
var startTrimSurface = func(which, dir) {

  if (which > 2) return;
  if (which == 0) startTrimAileron(dir);
  if (which == 1) startTrimElevator(dir);
  if (which == 2) startTrimRudder(dir)
}

##
# Do engine interpolations.
# Don't call from other contexts.
# Arg[0] is the node for the surface to be trimmed. Arg[1] is the starting point.
# Arg[2] is the direction.
# Dir is forced to -1 or +1
# Called for each engine in turn
#
var doEngineInterpolation = func(which, current, dir) {
    var diff = 0;
    var speed = 15;

    if (dir == 0) {
         # Stop interpolate
         interpolate(which, current, 0);
         return;
    }

    if (dir < 0) {
        # Head towards 0.
        dir = -1;
        diff = current;
    }

    if (dir > 0) {
        # Head towards 1.
        dir = 1;
        diff = 1 - current;
    }
       
    interpolate(which, dir, diff * speed)
}

##
# Adjust throttle, propeller-pitch and mixture with non-repeating buttons.
# Pressing button calls startAdjustxxxx(-1 or +1). Non-repeating button, so nothing else
# happens until button is released, which calls startAdjustxxxx(0).
#
# If the arg[0] is 0, stop interpolation at current position. Otherwise start interpolate, either positive or negative.
# Optional arg[1} specifies engine number, else all are done.
#
# eg  startaAdjustMixture(1) starts making the mixture richer and stops when startAdjustMixture(0) received.
# Takes 15 seconds to move between extremes. Scaled if started somewhere in the middle.
#
var startAdjustMixture = func(dir, which...) {

    if (!size(which)) {
      foreach(var e; engines)
        if(e.selected.getValue()) {
          var node = e.controls.getNode("micture");
          var current = node.getValue();

          doEngineInterpolation(node, current, dir)
        }
    }
    else {
      foreach(var i; which)
        foreach(var e; engines)
          if(e.index == i) {
            var node = e.controls.getNode("mixture");
            var current = node.getValue();
     
            doEngineInterpolation(node, current, dir)
          }
    }
}

var startAdjustThrottle = func(dir, which...) {
    if (!size(which)) {
      foreach(var e; engines)
        if(e.selected.getValue()) {
          var node = e.controls.getNode("throttle");
          var current = node.getValue();

          doEngineInterpolation(node, current, dir)
        }
    }
    else {
      foreach(var i; which)
       foreach(var e; engines)
          if(e.index == i) {
            var node = e.controls.getNode("throttle");
            var current = node.getValue();
     
            doEngineInterpolation(node, current, dir)
          }
    }
}

var startAdjustPropeller = func(dir, which...) {

    if (!size(which)) {
      foreach(var e; engines)
        if(e.selected.getValue()) {
          var node = e.controls.getNode("propeller-pitch");
          var current = node.getValue();

          doEngineInterpolation(node, current, dir)
        }
    }
    else {
      foreach(var i; which)
        foreach(var e; engines)
          if(e.index == i) {
            var node = e.controls.getNode("propeller-pitch");
            var current = node.getValue();
     
            doEngineInterpolation(node, current, dir)
          }
    }
}

##
# Adjust Engines.
# Calls startAdjustThrottle, startAdjustMixture or startAdlustPropeller
# according to the value of arg[0].
# Does all engines.
#
var startAdjustEngine = func(axis, dir, which...) {
  if (axis > 2) return;
  if (axis == 0) {
    foreach(var i; which)
     startAdjustThrottle(dir, i)
  }
  if (axis == 1) {
    foreach(var i; which)
      startAdjustMixture(dir, i);
  }
  if (axis == 2) {
    foreach(i; which)
      startAdjustPropeller(dir, i)
  }
}

macnab
 
Posts: 886
Joined: Tue Aug 02, 2011 7:20 am
Location: Johannesburg, South Africa
Callsign: ZS-ILH
Version: Git
OS: Win7Pro 64bit SP1

Re: Writing Joystick Code - wiki article

Postby macnab » Wed Oct 17, 2012 12:25 pm

Just to let you know, with help from hooray, I have made it that, when specifying engines, you can leave it out for all engines, specify an engine with the engine number as is or between [], and for a group of engines you list them between [], thus [1, 3, 4].

So
Increase throttle for engines 2, 4, and 6
startAdjustEngines(0, 1, 2, 4, 6)

becomes
Increase throttle for engines 2, 4, and 6
startAdjustEngines(0, 1, [2, 4, 6])

A bit easier to follow.

Lots of checking still to do, and I will post the code tomorrow.
macnab
 
Posts: 886
Joined: Tue Aug 02, 2011 7:20 am
Location: Johannesburg, South Africa
Callsign: ZS-ILH
Version: Git
OS: Win7Pro 64bit SP1

Re: Writing Joystick Code - wiki article

Postby Philosopher » Wed Oct 17, 2012 1:11 pm

Verrrrry nice coding there! Seriously, I, a nitpicky person, can't find anything to change. You even did the e.selected! Very nice, very nice.
Thanks,
Philosopher
(inactive but lurking occasionally...)
Philosopher
 
Posts: 1590
Joined: Sun Aug 12, 2012 6:29 pm
Location: Stuck in my head...
Callsign: AFTI
Version: Git
OS: Mac OS X 10.7.5

Re: Writing Joystick Code - wiki article

Postby macnab » Wed Oct 17, 2012 1:19 pm

Thanks. Just a question of learning Nasal. Been programming in numerous languages since I did a FORTRAN IV course in 1972, using punch-cards.

With the startAdjustEngine() you'll be able to program your joystick to your heart's content!!!
macnab
 
Posts: 886
Joined: Tue Aug 02, 2011 7:20 am
Location: Johannesburg, South Africa
Callsign: ZS-ILH
Version: Git
OS: Win7Pro 64bit SP1

Re: Writing Joystick Code - wiki article

Postby Philosopher » Wed Oct 17, 2012 1:34 pm

Haha, from article 4:
This is fine if you are using the joystick on your system. But imagine that you have worked out a brilliant button assignment scheme, using modifiers, so that the joystick is a joy to use. You want to post your code in the forum so everyone can use it.


Totally ;).

I like the per-OS axis reversing, I'll use it in like since the hat switch was reversed after the switch from Linux. One thing you might want to mention is that if the Mac number is not defined, the unix number is used for both Linux and Mac.
Thanks,
Philosopher
(inactive but lurking occasionally...)
Philosopher
 
Posts: 1590
Joined: Sun Aug 12, 2012 6:29 pm
Location: Stuck in my head...
Callsign: AFTI
Version: Git
OS: Mac OS X 10.7.5

Re: Writing Joystick Code - wiki article

Postby macnab » Wed Oct 17, 2012 1:39 pm

if the Mac number is not defined, the unix number is used for both Linux and Mac.


I don't know if you get different joystick xml files if you download the setup files for different OSs, but 99% of the ones I have only use <buton n="4> forms, which I presume is for Windows. Hence my plea for help.
macnab
 
Posts: 886
Joined: Tue Aug 02, 2011 7:20 am
Location: Johannesburg, South Africa
Callsign: ZS-ILH
Version: Git
OS: Win7Pro 64bit SP1

Re: Writing Joystick Code - wiki article

Postby Philosopher » Wed Oct 17, 2012 2:00 pm

You don't get different files because they are pretty much direct from GIT, which has no knowledge of OSs. As for the buttons, I think the drivers are just more consistent and use the same buttons assignments, as the only things to distinguish a button from the next is its number, since it doesn't have to have this function usually. I'd be very surprised to find two things: a case where the trigger isn't n=0 and where buttons do not have the same number across OSs. Basically, you don't really need to worry about numbers, they are easy to figure out besides the fact that they are needed for axes across different OSs. Now we could start work on a general rule, like I've seen that it usually goes [aileron, elevator, throttle0, rudder, throttle1] and sometimes the rudder and throttle are switched per OS.
Thanks,
Philosopher
(inactive but lurking occasionally...)
Philosopher
 
Posts: 1590
Joined: Sun Aug 12, 2012 6:29 pm
Location: Stuck in my head...
Callsign: AFTI
Version: Git
OS: Mac OS X 10.7.5

Re: Writing Joystick Code - wiki article

Postby macnab » Wed Oct 17, 2012 2:12 pm

I could suggest that people just use the format
Code: Select all
<axis>
  <number>
    <windows></windows>
    ...
  </number>
</axis>

and then people who download it can fill in their own axis numbers. As you say, not hard to figure out.
macnab
 
Posts: 886
Joined: Tue Aug 02, 2011 7:20 am
Location: Johannesburg, South Africa
Callsign: ZS-ILH
Version: Git
OS: Win7Pro 64bit SP1

Previous

Return to Hardware

Who is online

Users browsing this forum: No registered users and 1 guest