Board index FlightGear Support Hardware

Writing Joystick Code - wiki article  Topic is solved

Joysticks, pedals, monitors.

Re: Writing Joystick Code - wiki article

Postby Hooray » Mon Oct 15, 2012 3:21 pm

And the next cool thing is being available to provide a library of code snippets for frequently used stuff, which could be also saved in an XML file - so that people wouldn't necessarily need to create all their code from scratch, but could look at existing snippets and customize those as required.

I'd suggest you take a look at the Nasal console and the JS config dialog and see for yourself.
As to running the latest code, that doesn't necessarily require building everything from source, you can also download a "nightly" (pre-compiled snapshot) and then simply use fgdata from git (if you aren't already).

The details are covered in the wiki.
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11951
Joined: Tue Mar 25, 2008 8:40 am

Re: Writing Joystick Code - wiki article

Postby macnab » Mon Oct 15, 2012 3:36 pm

Having trouble finding the correct wiki article.

Can I download and install this http://flightgear.simpits.org:8080/job/ ... sfulBuild/ ?
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 Hooray » Mon Oct 15, 2012 3:45 pm

Yes, that should work - note that this is JUST the binary program (fgfs.exe, 32 bit) - you still need the latest fgdata (base package), either as a download or via git - which should be documented somewhere in the wiki, too. I suggest to use a GUI on Windows to get the base package - note that it's ~5 GB in size, because it includes ALL of the aircraft and other stuff that isn't by default included in any of the releases - so it may take a while to get the full package, but updating will just take seconds afterwards.
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11951
Joined: Tue Mar 25, 2008 8:40 am

Re: Writing Joystick Code - wiki article

Postby macnab » Mon Oct 15, 2012 4:10 pm

note that it's ~5 GB in size


That is my entire bandwidth allocation for the month. (Bandwidth is not cheap in South Africa.) Will trust Stuart and others to get the dialog to work correctly. Will in the meantime concentrate on simplifying the code needed to implement any action. After all, it is better if on-the-fly configuration gives a reasonable range of actions. Will need a wiki to explain them.

More complicated situations such as using mod buttons and the like will have to remain the the realm of those prepared to edit xml files.

There are those who just want to fly and those who want to assign 4 functions to every button on their joystick.

I will concentrate on simplifying bindings. As far as I can see, they can be put in controls.nas.That way, the list of "bindings" in the joystick configuration dialog would be restricted to controls.xxx and setProp.xxx.
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 Hooray » Mon Oct 15, 2012 4:26 pm

Maybe you know someone close to you who could download the data and sent it to you on a DVD or USB stick?
What about other FG users from South Africa?
Note that only the initial clone will be that large, future downloads will be less than that - and incrementally done.
So maybe you can find someone to download the git bundle and send it to you ?
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11951
Joined: Tue Mar 25, 2008 8:40 am

Re: Writing Joystick Code - wiki article

Postby macnab » Mon Oct 15, 2012 4:45 pm

I do know someone who has a large available bandwidth outside working hours. And he's run out of things to download.

We are forever sharing things with flash-drives. I will look into it tomorrow. After I've had supper and a night's sleep. :)

And the weekend must come so he has his "free" download time.
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 12:10 am

I found a better way to find the namespace a joystick is loaded into:
Code: Select all
var Joystick = cmdarg().getParent().getPath();
var namespace = cmdarg().getNode("module").getValue();
io.load_nasal(getprop("/sim/fg-root") ~ "/Input/Joysticks/Saitek/Cyborg-X/functions.nas", namespace); #import functions first
io.load_nasal(getprop("/sim/fg-root") ~ "/Input/Joysticks/Saitek/Cyborg-X/buttons.nas", namespace);
var config = gui.Dialog.new(Joystick ~ "/dialog","Input/Joysticks/Saitek/Cyborg-X/Dialog-Cyborg");


I updated my earlier post to use this. Basically cmdarg() passes two things: nasal/module and nasal/script which contain the initialization script and the module that it is run in, respectively. Then you can use cmdarg().getParent().getPath() to retrieve the "root" directory that the joystick is loaded into. Voilá! No hacks anymore :D.
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 1:16 am

This is for the intrepid user who wants to program his joystick in fancy ways. I don't know how close you are to finishing it. Then I need your functions.nas and buttons.nas and I will write a wiki about it.

In the meantime (or at the same time) I will work on expanding controls.nas so that bindings are always simple. This for Stuart's on-the-fly programming for people who just want to fly, but need to change one or two things.
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 7:18 am

Ok. I have written extensions to controls.nas. They enable adjusting elevator-, aileron- and rudder-trim, mixture and throttle with non-repeatable buttons.

An example is:

Button pressed
Code: Select all
  controls.startAdjustThrottle(1)

starts the throttle setting increasing.

When the button is released
Code: Select all
  controls.startAdjustThrottle(0)

stops the throttle setting right where it is.

Using -1 reduces the throttle setting.

Here is the code
Code: Select all
##
# Trim aileron, elevator and rudder with non-repeating buttons.
# Pressing button starts trim by calling interpolate. Non-repeating button, so nothing else
# happens until button is released, which will interpolate from current position to current position
# in zero seconds, stopping interpolation and trim.
#
# If the argument is 0, stop interpolate. 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(d) {
    var diff = 0;
    var elevatortrim = props.globals.getNode("/controls/flight/elevator-trim");
    var current = elevatortrim.getValue();
    var speed = 30;

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

var startTrimAileron = func(d) {
    var diff = 0;
    var ailerontrim = props.globals.getNode("/controls/flight/aileron-trim");
    var current = ailerontrim.getValue();
    var speed = 30;

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

var startTrimRudder = func(d) {
    var diff = 0;
    var ruddertrim = props.globals.getNode("/controls/flight/rudder-trim");
    var current = ruddertrim.getValue();
    var speed = 30;

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


##
# Adjust mixture with non-repeating buttons.
# Pressing button starts adjust by calling interpolate. Non-repeating button, so nothing else
# happens until button is released, which will interpolate from current position to current position
# in zero seconds, stopping interpolation and adjust.
#
# If the argument is 0, stop interpolate. Otherwise start interpolate, either positive or negative.
#
# eg  startaAdjustMixture(1) starts making the mixture richer and stops when startAdjustMixture(0) received.
# Takes 10 seconds to move between extremes. Scaled if started somewhere in the middle.
#
var startAdjustMixture = func(d) {
    var diff = 0;
    var mixture = props.globals.getNode("/controls/engines/engine/mixture");
    var current = mixture.getValue();
    var speed = 10;

    # Do nothing if at either limit
    if ((current == 0) or (current == 1)) {
         return
    }

    if (d == 0) {
         # Stop interpolate
         interpolate(mixture, current, 0);
    }
    if (d < 0) {
        # Head towards 0.
        diff = current;
        interpolate(mixture, 0, diff * speed)
    }
    if (d > 0) {
        # Head towards 1.
        diff = 1 - current;
        interpolate(mixture, 1, diff * speed)
    }
}

##
# Adjust throttle with non-repeating buttons.
# Pressing button starts adjust by calling interpolate. Non-repeating button, so nothing else
# happens until button is released, which will interpolate from current position to current position
# in zero seconds, stopping interpolation and adjust.
#
# If the argument is 0, stop interpolate. Otherwise start interpolate, either positive or negative.
#
# eg  startAdjustThrottle(1) starts increasing the throttle setting and stops when startAdjustThrottle(0) received.
# Takes 10 seconds to move between extremes. Scaled if started somewhere in the middle.
#
var startAdjustThrottle = func(d) {
    var diff = 0;
    var throttle = props.globals.getNode("/controls/engines/engine/throttle");
    var current = throttle.getValue();
    var speed = 10;

    # Do nothing if at either limit
    if ((current == 0) or (current == 1)) {
         return
    }

    if (d == 0) {
         # Stop interpolate
         interpolate(throttle, current, 0);
    }
    if (d < 0) {
        # Head towards 0.
        diff = current;
        interpolate(throttle, 0, diff * speed)
    }
    if (d > 0) {
        # Head towards 1.
        diff = 1 - current;
        interpolate(throttle, 1, diff * speed)
    }
}


Could someone please check it, test it if you can, and, if approved, commit it. If committed, Stuart must know about it for his joystick settings dialog.


EDIT: If have removed the "do nothing if at either limit." Stupid.
Last edited by macnab on Tue Oct 16, 2012 1:21 pm, edited 2 times in total.
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 10:34 am

Here is the code for propeller. Just thought of it. :)

On reflection I have changed the "speed" for throttle, mixture and propeller to 10 seconds. Code in previous post hs been changed.

Code: Select all
##
# Adjust propeller with non-repeating buttons.
# Pressing button starts adjust by calling interpolate. Non-repeating button, so nothing else
# happens until button is released, which will interpolate from current position to current position
# in zero seconds, stopping interpolation and adjust.
#
# If the argument is 0, stop interpolate. Otherwise start interpolate, either positive or negative.
#
# eg  startAdjustPropeller(1) starts increasing the propeller setting and stops when startAdjustPropeller(0) received.
# Takes 10 seconds to move between extremes. Scaled if started somewhere in the middle.
#
var startAdjustPropeller = func(d) {
    var diff = 0;
    var propeller = props.globals.getNode("/controls/engines/engine/propeller-pitch");
    var current = propeller.getValue();
    var speed = 10;

    if (d == 0) {
         # Stop interpolate
         interpolate(propeller, current, 0);
    }
    if (d < 0) {
        # Head towards 0.
        diff = current;
        interpolate(propeller, 0, diff * speed)
    }
    if (d > 0) {
        # Head towards 1.
        diff = 1 - current;
        interpolate(propeller, 1, diff * speed)
    }
}


EDIT: If have removed the "do nothing if at either limit." Stupid.
Last edited by macnab on Tue Oct 16, 2012 1:23 pm, edited 2 times in total.
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 stuart » Tue Oct 16, 2012 12:09 pm

Hi Guys,

Thanks to macnab for pointing me at this topic.

The joystick configuration dialog needs has dependencies on the git binaries, so you won't be able to simply copying it over an existing 2.6.0 or 2.8.0 installation. Sorry.

Adding the ability to write Nasal for a given button was something I considered, but didn't implement. Partly this was due to time constraints, but it was also because I didn't think there was a use-case for it. The joystick configuration dialog is really targeted at new users who don't have any XML or Nasal experience. IMO anyone who knows enough to write Nasal joystick bindings will have enough knowledge to edit the joystick XML files directly and use the Nasal Console.

On a different note, I'm interested to see what bindings people are using on joysticks, to check that the set of button bindings that are supported in the configuration dialog are sufficient.

At present the dialog supports trim settings, but sets the button to be repeatable. Is there are a particular reason for not using the repeatable flag, or is it purely for people who have mode-switches and might have another (non-repeatable) function assigned to the button?

(I'll also check that I've got the prop/mixture/throttle adjustments available as button bindings)

-Stuart
G-MWLX
User avatar
stuart
Moderator
 
Posts: 1603
Joined: Wed Nov 29, 2006 9:56 am
Location: Edinburgh
Callsign: G-MWLX

Re: Writing Joystick Code - wiki article

Postby macnab » Tue Oct 16, 2012 1:08 pm

Is there are a particular reason for not using the repeatable flag


Precisely because of mode switching. Just giving the people a chance to use both types for these functions.

The joystick configuration dialog is really targeted at new users who don't have any XML or Nasal experience.


I presume the dialog will not have the possibility of mode-switching?
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 stuart » Tue Oct 16, 2012 1:47 pm

The Joystick Configuration GUI has logic to determine whether a button should be repeatable or not based on the the function. So, it sets up Gear Down to be non-repeatable, but sets trim buttons to be repeatable. So, the user doesn't need to know about repeatable buttons at all.

The GUI is easier to experience than to describe, but effectively the user identifies the button they want to configure and then chooses the function from a list.

The dialog doesn't support mod-keys - that's considered a bit too complicated. It's too complicated for me anyway!

-Stuart
G-MWLX
User avatar
stuart
Moderator
 
Posts: 1603
Joined: Wed Nov 29, 2006 9:56 am
Location: Edinburgh
Callsign: G-MWLX

Re: Writing Joystick Code - wiki article

Postby Philosopher » Tue Oct 16, 2012 1:52 pm

Hey, Stuart's here! ;)

Yes, the non-repeatable trim buttons is only for use with modifiers. And, only three Saitek ones as far as I have found have tried to combine rudder trim and views :lol:. See my post here.

@macnab: I'm fairly sure that Stuart has a list of bindings together with whether they are able to be repeatable or not. Also, you might want to make a helper function for non-repeatable trim, controls.nas right now has a "perIndexAxisHandler" helper function that does all the work for controls.throttleAxis, etc., so that they reuse the same piece of code, albeit with a slightly different argument.

P.S. Modifiers aren't hard, sim's proven that, double click && hold down at the same time with modifiers is hard!
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 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
macnab
 
Posts: 886
Joined: Tue Aug 02, 2011 7:20 am
Location: Johannesburg, South Africa
Callsign: ZS-ILH
Version: Git
OS: Win7Pro 64bit SP1

PreviousNext

Return to Hardware

Who is online

Users browsing this forum: No registered users and 3 guests