Any Brunner Yoke Folks out there?

Cobblers! And there is another one :slight_smile:

1 Like

In case anyone is interested I have been working on something for the Brunner for a particular usage case I have, but don’t yet have the hardware to test it out. It’s regarding hardware trim.

The yoke itself has an elevator trim switch, but it may not always be convenient for me to use that, and I would rather use my Logitech trim wheel, to complement it, not replace it.

This requires sending UDP datagram packets to the CLS2Sim software. I had written a script, first in PowerShell, and later in C# that does some of this. The C# one is more fleshed out as I have spent more time with it.

I had opened a thread on the Brunner forums as there were a few things I didn’t fully understand, and one of their staff offered some pointers, and even updated their documentation to make it more clear how it works.

https://cls2sim.brunner-innovation.swiss/

Digging down into the protocol v2 page, and the “Input Control” section, it indicates that trim elevator up, and trim elevator down have the Ids 1002, and 1003 respectively. These numbers need to be converted into hex, and presented in little endian format. So that becomes 0xea03, and 0xeb03.

The command to manipulate these is 0xd5, which is a 32bit integer, so needs to be presented as 0xd5000000.

So the packet to send for trim up becomes d5000000ea03.

What I didn’t realise is that these packets “latch”, and a packet needs to tell the button to be pressed, and then released. To release all buttons you send an input control packet with not switch IDs present, releasing all buttons. That would be 0xd5 0x00 0x00 0x00.

Below is the C# code I use to send that to my currently non-existing Brunner yoke!

using System;
using System.Linq;
using System.Net.Sockets;

class Program
{
     static void Main(string[] args)
    {
        string udpIp = "127.0.0.1";
        int udpPort = 15090; // Choose any available port

        if (args.Length != 0)
        {

            byte[] data = args.Select(arg => Convert.ToByte(arg, 16)).ToArray();
            byte[] up = { data[0], 0x00, 0x00, 0x00 };
            Console.WriteLine(data[0]);
            using (UdpClient udpClient = new UdpClient())
            {
                udpClient.Send(data, data.Length, udpIp, udpPort);
                udpClient.Send(up, up.Length, udpIp, udpPort);
            }
        }
    }
}

I compiled this as UDPSend.exe, and to use it for trim up you would execute:

UDPSend.exe 0xd5 0x00 0x00 0x00 0xea 0x03

In Wireshark I see this:

The packet after it with a length of 4 has this:

The idea is I would configure SPAD to execute this command, with the trim up or down arguments, when I roll the scroll wheel, and this works great in my tests.

Additionally, what I was also told is if you have buttons on the yoke bound to these functions you must first “interdict” them. This bit I haven’t looked at yet, but it sounds like you should first interdict the physical button so it is not read, then make your remote calls to that function, then remove the interdiction so the button can be used again.

The documentation has what I suspect is a typo in it. It lists the interdiction command as:

0xD11 : InputInterdictionControl

Looking through the documentation there are no other commands that have three digits, so it may be either 0xd1, or 0x11. I need to clarify that with them. But in any case that command would likely straddle the existing two “udpClient.Send” lines towards the end of the script.

The PowerShell script could be made to do the same thing, but what I found, perhaps unsurprisingly, is that the compiled PS script was about 5 times larger, and took ~100ms longer to run.

1 Like

Updated the code with some, logical, assumptions, for the interdiction of buttons:

  1. That “0xd11” is correct, which becomes “0x11 0x0d 0x00 0x00”.
  2. That the interdiction on, and off packets should be before, and after the remote input control packets are sent.
using System;
using System.Linq;
using System.Net.Sockets;

class Program
{
     static void Main(string[] args)
    {
        string udpIp = "127.0.0.1";
        int udpPort = 15090; // Choose any available port

        if (args.Length != 0 && args.Length >= 6)
        {

            byte[] data = args.Select(arg => Convert.ToByte(arg, 16)).ToArray();
            byte[] up = { data[0], 0x00, 0x00, 0x00 };
            byte[] interdict_on = { 0x11, 0x0d, 0x00, 0x00, data[4], data[5] };
            byte[] interdict_off = { 0x11, 0x0d, 0x00, 0x00 };
            Console.WriteLine(data[0]);
            using (UdpClient udpClient = new UdpClient())
            {
                udpClient.Send(interdict_on, interdict_on.Length, udpIp, udpPort);
                udpClient.Send(data, data.Length, udpIp, udpPort);
                udpClient.Send(up, up.Length, udpIp, udpPort);
                udpClient.Send(interdict_off, interdict_off.Length, udpIp, udpPort);
                udpClient.Close();
            }
        }
    }
}

I’ve been struggling to plan the ergonomics of a yoke to work with a desk or table - on the table vs under.

I’ve decided to wait until I have a yoke, but if mounted under the desk, to be both adjustable and removable, I pictured having something like an under-counter drawer - or a thin-walled box to contain/hold the yoke securely, that can slide in to place and also be removed easily, with low-profile rails… so when not in use, there would be little to see or interfere if used on a desk. But I haven’t quite worked it out.

It’s too bad the Brunner doesn’t have an option to move the mounting bars that protrude from under the unit, to the top side, for under desk mounting.

I like the idea of keeping the table top clear for a better view of the lower part of the screen, and / or space for MCP, etc.

1 Like

I looked at that but the yoke looks pretty tall, so it would mean I would have to have the desk quite high up. Not a huge issue logistically as I have a sit/stand desk so can move it up or dawn as desired. But I couldn’t see any way of doing that, and not having it semi permanent, so I opted for the clamped rails on top instead.

Plus, I want the yoke mounted quite far into the desk so that the yoke fully aft would not have me sat on the far side of the room. :wink:

It’s roughly something like this:

I would have the yoke fully forward, then mount the yoke far enough back that my hands around it will not scuff the desk, or hit any other equipment.

At the moment my Yoko+ is edge mounted via clamp, and that means that with the yoke fully forward I am still 5-6 inches away from the desk.

I think it’s only 3.5 inches tall (90mm in the fact sheet), but when talking about desk height and ergonomics, even that amount is a lot.

I wonder if the yoke can operate properly at a shallow angle of 5 to 10 degrees (with the back lower than the front) so that when you pull the yoke it would be pulling slightly up - allowing the overall height to be slightly lower.

Or does the unit have to be level, to avoid the weight of the yoke on an angle pushing slightly with gravity…

I’m not sure the weight of the moving parts are an issue as it’s all down to the motors inside resisting your movements. The overall unit may have a lot of mass, but you aren’t actually pulling on that, but the motors inside.

I’ve just emailed to ask if the yoke can operate at a shallow angle for ergonomics, without gravity affecting it, or if it has to be level to work properly. I’m also looking at a height adjustable table for all this, as I don’t have space for a dedicated rig, and need it to be a modular multipurpose setup.

I can recommend the Flexispot E6.

1 Like

Good news, a Brunner rep replied and confirmed that, “a slight angle of 5-10° does not cause troubles.” So that may allow me to mount under the table, at a bit of a down angle, keeping the overall table top lower.

Bad news, I still need to save enough to afford one.

1 Like

I got an email earlier today indicating mine will be shipping this Friday, so I hope to get it next week sometime.

1 Like

It didn’t ship on Friday, it was delivered on Friday!


I’m waiting for one of these to be delivered, as they never added an on/off switch, and I didn’t fancy constantly ducking under my desk to flip the switch on the power strip.

Great idea, will go for something like that too as I also own their pedals …
Incomprehensible why they didn’t ad an on/off switch…

1 Like

To be fair you see that in a lot of industrial products. Why would you ever want them to turn off? If they have an off switch then it could be accidentally pressed. My firewall doesn’t have an off switch.

Not an argument against it tbh. Just place the ■■■■ thing on the back side of it. (The yoke, not the firewall :grimacing:) Why? Here goes:

Because I don’t want the full color LCD display on all the time.

Because both units emit a slight noise when powered

I really LOVE both the rudder and the yoke, even more so after my only two gripes with them had been resolved by Brunner in a very flexible way via firmware update, but no on/off? Come on :joy::joy:

Still: I would never ever fly without them anymore.

Regards

1 Like

Agreed. I can see why you wouldn’t want them to turn off inside a professional flight simulator, but I would want to as its not a permanent emplacement for me, and has to be removed so I can work from home. Although I’m now wondering whether I could perch my keyboard on top of it since I should be able to mount the yoke so far into the desk on the rails…hmmm.

The forward third of the casing is slanted but you can use velcro tape. Which I would’ve done had I not bought a movable keyboard arm.

1 Like

Quote: “The yoke itself has an elevator trim switch, but it may not always be convenient for me to use that, and I would rather use my Logitech trim wheel, to complement it, not replace it.”

Wow. I own both a Brunner CLS-E yoke and Honeycomb Bravo, which includes a trim wheel that functions as button sends, and I use them as you describe above. But I didn’t need any outside code for it, they just work, independently of each other.

I don’t use the Brunner CLS2Sim software for the yoke buttons, I do it all within the sim control assignments.

Once again, it’s the difference between software trim, and hardware trim.

I just wanted to make a post highlighting my experience with the CLS-E Mk II, having had it for a few days now.

After downloading some of the profiles, concentrating on the 172, I found that I had to turn down the force scaling a bit, by half in some cases. I found after a few days that my elbow was beginning to hurt. This was exacerbated by the perhaps unrealistic turbulence effects, which I have also disabled. It felt like I was having to constantly lean into a crosswind, and level crabbed flight was all but impossible, and it feels much better with that turned off.

I also had some issues with the CLS2Sim software, and remote control. It looks like the software ignore packets sent to it unless you have this option turned off.

image

With it on, packets sent to it should be sent straight back, but that was not my experience. With it turned off, it all works as expected, and I can see commands to it via script or program, and it works. I’ve reported this to the official forums but have not had a response yet.

The other thing I looked at was hardware trim via remote control. And this probably needs some clarification. Hardware trim is the more realistic of the two. When trimming, the yoke will physically move to its new trimmed setting. On climb you may find the yoke wheel is closer to you, and when at cruise power in level flight the yoke may be trimmed further away from you. Hardware trim is not aware of what the sim is doing, and will not update any sim settings nor will you see any trim indicators move as you trim. This is normal.

With software trim, the software sends commands to the sim, just like with a bungie corded yoke, and your trimmed position will not vary, which isn’t as realistic.

What I have found is something odd, also reported on the forums, and also awaiting feedback. If I don’t hear anything back in a few days I will open a formal support ticket for each.

So for hardware trim to work, you can configure it like this.

That works great if you are happy to use the trim switch on the yoke. But I want to use the trim wheel, and for that to work you must talk to the CLS2Sim software over the network.

  1. Each button on the yoke has a command to press it, and a general one to release it.
  2. If you have a hardware button bound to a function, and you want to command it remotely, it must be temporarily “interdicted”, so that the physical button state is not read, and remote control will then work. Or unbind the button in CLS2Sim.

I have not yet sussed out the interdiction part, and am unsure if there is a typo in my scripts/programs or something else. So for now I have left the buttons unbound when testing, so I can concentrate on remote control.

I first started with PoweShell, and came up with this:

$client = new-object net.sockets.udpclient(0)

$peerIP = "127.0.0.1"
$peerPort = "15090"
$command = $args[0]
If ($command.GetType().Name -like "String") { $command = $command.Split(",")}
[Byte[]] $command
[void] $client.send($command, $command.count, $peerIP, $peerPort)
$client.close()

So if you wanted to remotely send the trim up command to the yoke, you would do this:

.\send.ps1 0xd5,0x00,0x00,0x00,0xea,0x03

The “0xd5,0x00,0x00,0x00” part is the remote control command as described in the online documentation. The “0xea,0x03” part is the button or rather action being pressed, in this case “Trim up”. So that would depress that “button”, but keep it held down, like runaway trim! So to release it you then need to send that command again, but this time without the reference to the action, so that is:

.\send.ps1 0xd5,0x00,0x00,0x00

To get around having to do that manually each time, and after deciding to switch to C# I came up with this:

using System;
using System.Threading;
using System.Linq;
using System.Net.Sockets;

class Program
{
     static void Main(string[] args)
    {
        string udpIp = "127.0.0.1";
        int udpPort = 15090; // Choose any available port

        if (args.Length != 0 && args.Length >= 6)
        {
            byte[] data = args.Select(arg => Convert.ToByte(arg, 16)).ToArray();
            byte[] up = { data[0], 0x00, 0x00, 0x00 };
            //byte[] interdict_on = { 0x11, 0x0d, 0x00, 0x00, data[4], data[5] };
            //byte[] interdict_off = { 0x11, 0x0d, 0x00, 0x00 };
            using (UdpClient udpClient = new UdpClient())
            {
               //udpClient.Send(interdict_on, interdict_on.Length, udpIp, udpPort);
                udpClient.Send(data, data.Length, udpIp, udpPort);
                System.Threading.Thread.Sleep(100);
                udpClient.Send(up, up.Length, udpIp, udpPort);
                //udpClient.Send(interdict_off, interdict_off.Length, udpIp, udpPort);
                udpClient.Close();
            }
        }
    }
}

You will see I have commented out the “interdict” lines, with “//”, until I figure those out. They are sending butt not being acted upon for some reason. The syntax here is similar:

UDPSend.exe d5 00 00 00 ea 03

Trim down would be:

UDPSend.exe d5 00 00 00 eb 03

You don’t need to send the command to release the button as the program does that for you. There is a 100ms delay between the button being pressed, and being released. Longer delays mean the button is held down longer, and trimming is a little faster, but coarser. I still need to finesse that part so that it is on par with software trimming speed.

This all works great…except what I noticed was as I was trimming I don’t feel anything in the yoke, and I can see the virtual cockpit trim wheel moving, which should be impossible for hardware trim! I double, and triple checked that I was not somehow sending SimConnect commands to the sim, and I’m not. So it appears to be working like software trim does, and I don’t think that is right. Again, to be clarified by Brunner themselves.

I hope to get that part sorted as software trim just feels naff. It has no effect on the general feedback of the yoke, but totally ruins one of the big selling points of yokes with this feature: to be able to realistically trim out forces on the yoke.

The information for these commands can be found here:

https://cls2sim.brunner-innovation.swiss/

And specifically input control:

Trim up/down have the id 1002/1003 specifically.

Convert 1002 into little-endian hex, and you get ea03.

https://www.rapidtables.com/convert/number/decimal-to-hex.html?x=1002

Int32 means 4 bytes, so “0xd5” becomes “0xd5 0x00 0x00 0x00”. UInt16 means two bytes for the input id. When you understand that part, the rest is easy.

2 Likes