Improved joystick (wheel, pedal, h-shifter) support...

113 views
Skip to first unread message

Marcel Offermans

unread,
Jun 21, 2022, 2:31:56 PM6/21/22
to ProjectChrono
Hi all, I've been working a bit on the ChIrrGuiDriver class, a class that provides "human in the loop" support for many of the vehicle demos. That said, in it's current state, it definitely had some serious limitations. Before offering a PR, I put up a commit with my changes so far in a fork of Chrono I have on my github, because there might be some discussion points that need to be addressed.

This is the commit (so far):

So what did I change? First and foremost, I implemented support for assigning joystick axis and buttons in a scenario where you have more than one "joystick" attached. This is pretty common when you talk about modern simulators. They come with pedals (separate USB device), a wheel (one or sometimes even two devices), an H-shifter (separate device) and a button box (again, separate device with tons of buttons to change in-car systems).

On top of that I added basic support to calibrate each of those axis, setting the minimum and maximum (raw) value for that axis as well as the intended (scaled) output values. More could be added here for sure, such as deadzones and non-linear behavior, but I'm putting those features up for discussion first.

Also, I changed the way you map your axis and buttons. Instead of hardcoding them, there is now a "../data/joystick.json" file that allows you to assign all axis and buttons. An example, for my development machine that only has an XBox controller (and it does not map all the H-shifter buttons, an exercise that can easily be done by the reader):

{
    "steering": {
        "name": "Controller (Xbox One For Windows)",
        "axis": 0,
        "min": -32768,
        "max": 32767,
        "scaled_min": 1,
        "scaled_max": -1
    },
    "throttle": {
        "name": "Controller (Xbox One For Windows)",
        "axis": 2,
        "min": -1,
        "max": -32767,
        "scaled_min": 0,
        "scaled_max": 1
    },
    "brake": {
        "name": "Controller (Xbox One For Windows)",
        "axis": 2,
        "min": 0,
        "max": 32767,
        "scaled_min": 0,
        "scaled_max": 1
    },
    "clutch": {
        "name": "Controller (Xbox One For Windows)",
        "axis": 4,
        "min": 0,
        "max": 32767,
        "scaled_min": 0,
        "scaled_max": 1
    },
    "shiftUp": {
        "name": "Controller (Xbox One For Windows)",
        "button": 4
    },
    "shiftDown": {
        "name": "Controller (Xbox One For Windows)",
        "button": 5
    }
}


So I think the values more or less explain themselves. By using the names of the controllers, it does not matter in what order they show up on your system. At startup, they get mapped to joystick IDs.

I also added sequential shifter support. The underlying code right now will only let you shift if you have a manual gearbox. I left that as is for now, but you could argue that it makes sense, even in the scenario of an automatic gearbox, to allow drivers to manually override gears.

There was some code in there too for H-shifter support, but in its current state I could not get that to work. I modified the code a bit to support up to 9 forward gears and added support for shifting (as long as you have the clutch pressed down). Again, you can argue if that (pressing the clutch) is needed. Especially modern race cars typically allow shifting without clutch. Up for discussion!

Now another issue I encountered is that there were some bits of API that I had to modify:
  1. There were methods to Get/Set JoystickAxes directly, but those did not take into account what Joystick (ID or name) to use, so I commented those out. As far as I can see, nobody was using them (but that could be different for upstream projects using Chrono).
  2. I had to make the SetGear() method public so it could be accessed from the driver. I saw no other way to implement the H-shifter and make it change gears. The existing code had nothing to shift?!?
I also added a few minor things such as:
  • Protection against "double shifts" (timeout currently hardcoded).
  • Debug mode that will, twice per second, print all the values of the joytick axes and buttons connected, very handy when you're writing a joystick.json file, can be disabled otherwise.
I'm sure I accidentally left in a bug or two as well, so feel free to point out anything that can be improved, or suggest different ways of doing things.

Greetings, Marcel

Radu Serban

unread,
Jun 22, 2022, 8:12:06 AM6/22/22
to ProjectChrono

Hi Marcel,

 

This part of the code was indeed more experimental and has not seen much use as implemented in the main Chrono repository.  Having said that, students in the lab have implemented more sophisticated joystick interfaces, as well as interfaces to driving wheel controllers (such as the Logitech sets).  As you suspected, these were implemented in external projects that are built on top of Chrono & Chrono::Vehicle and which we use for human-in-the-loop simulations.

 

Having said that, more robust support for such controllers in Chrono is probably not a bad idea and you seem to have implemented a pretty comprehensive interface.  I think this would be a nice addition to Chrono and encourage you to submit it as a PR.

 

As for making ChPowertrain::SetGear() public, that’s fine.  For what we needed so far, we’ve always use ShiftUp and ShiftDown, but a fully manual transmission box would indeed allow you to traverse gears non-sequentially.

 

Thanks,
--Radu

--
You received this message because you are subscribed to the Google Groups "ProjectChrono" group.
To unsubscribe from this group and stop receiving emails from it, send an email to projectchron...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/projectchrono/b9db4907-3086-445e-b2a9-016c4f41a0ban%40googlegroups.com.

Marcel Offermans

unread,
Jun 22, 2022, 11:28:53 AM6/22/22
to ProjectChrono
Hello Radu,

Thanks for the feedback, I will work towards a PR. One other question came to mind, since you say you've implemented something for the Logitech wheels (assuming you're talking about the G25, 27, 29, ... range of consumer wheels here): did you also implement any force feedback? Although I'm not sure if the IrrLicht interface supports that, going directly to DirectX/DirectInput would, so that could be another thing to add that would improve the feeling of the cars a lot.

Greetings, Marcel

Marcel Offermans

unread,
Jun 27, 2022, 11:31:06 AM6/27/22
to ProjectChrono
I've further evolved and tested my earlier solution and made sure it works on different systems here, including both sequential and H-shifter setups. I've created a pull request here: https://github.com/projectchrono/chrono/pull/405

Looking forward to any feedback!

Greetings, Marcel

Radu Serban

unread,
Jun 27, 2022, 3:19:59 PM6/27/22
to ProjectChrono

Hi Marcel,

 

Thank you for the PR!  I just merged it.

 

Regarding force feedback, I don’t know for sure, but I doubt the students working on this implemented it.  A main roadblock for that is that we currently do not model the steering column (steering input is used to directly actuate the steering mechanism, e.g., through a rotational angle motor on the Pitman arm’s revolute joint).  I have a draft of a (compliant) steering column model but put it on the backburner as I ran into some difficulties.  I’ll revisit that when I get a chance.

 

Best,
Radu

Marcel Offermans

unread,
Jun 28, 2022, 9:33:50 AM6/28/22
to ProjectChrono
Regarding force feedback, thanks for the update, please let me know if you have time to revisit this. I'm still learning to find my way around Chrono so I don't think I can be of much help right now, but I could definitely help with the controller part of such an implementation.
Reply all
Reply to author
Forward
0 new messages