EMC2 Gamepad Pendant: Joystick Axis Lockout

Nothing like sleeping on a problem. It turns out that a chunk of HAL code can do a nice job of locking out an inactive joystick axis.

The general idea:

  • A priority encoder selects one axis when both go active simultaneously
  • The prioritized outputs set flipflops that remember the active axis
  • The active axis locks out the other one until they’re both inactive

That way, you can start to jog either axis on a knob without worrying about accidentally jogging the other axis by moving the knob at a slight diagonal. I hate it when that happens.

The other tweak is that the quartet of buttons on the right act as a “hat” for the Z and A axes, jogging them at the current maximum speed.

Because it’s tough to accidentally push two buttons at once, there’s no need to lock them out. So you can jog diagonally by deliberately pushing adjoining buttons, but you must want to do that.

Rather than dumping the whole program again, here are the key parts…

Figuring out if a joystick axis is active uses the window comparators. It seems the idle counts value varies slightly around 127, so I relaxed the window limits. Should the window comparator go active with the knob centered, the buttons for that axis won’t produce any motion.

net		x-jog-count-int	input.0.abs-x-counts	conv-s32-float.0.in
net		x-jog-count-raw	conv-s32-float.0.out	wcomp.0.in
setp	wcomp.0.min		125
setp	wcomp.0.max		130
net		X-inactive		wcomp.0.out				not.0.in
net		X-active		not.0.out

The priority encoder is just a gate that prevents Y (or A) from being selected if X (or Z) is simultaneously active. Here’s a sketch for the ZA knob:

Axis priority encoder
Axis priority encoder

The active and inactive signals come from the window detectors. The sketch gives the K-map layout, although there’s not a whole lot of optimization required.

The corresponding code:

net		Z-inactive		and2.5.in0
net		A-active		and2.5.in1
net		A-select		and2.5.out				# select A only when Z inactive

net		Z-inactive		and2.6.in0
net		A-inactive		and2.6.in1
net		ZA-Deselect		and2.6.out				# reset flipflops when both inactive

net		Z-active		and2.7.in0				# set Z gate when knob is active
net		A-gate-not		and2.7.in1				# and A is not already gated
net		Z-set			and2.7.out					flipflop.2.set

net		ZA-Deselect		flipflop.2.reset		# reset when neither is active
net		Z-gate			flipflop.2.out				not.6.in
net		Z-gate-not		not.6.out

net		A-select		and2.8.in0				# set A gate when knob is active
net		Z-gate-not		and2.8.in1				# and Z is not already gated
net		A-set			and2.8.out					flipflop.3.set

net		ZA-Deselect		flipflop.3.reset		# reset flipflop when both inactive
net		A-gate			flipflop.3.out				not.7.in
net		A-gate-not		not.7.out

The flipflops remember which axis went active first and lock out the other one. When both axes on a knob return to center, the flipflops reset.

The quartet of buttons produce binary outputs, rather than the floats from the Hat, so a pair of multiplexers emit -1.0, 0.0, or +1.0, depending on the state of the buttons, for each axis.

setp	mux2.6.in0	0.0
setp	mux2.6.in1	-1.0
net		A-btn-neg		input.0.btn-trigger		mux2.6.sel
net		A-btn-neg-value	mux2.6.out				sum2.1.in0

setp	mux2.7.in0	0.0
setp	mux2.7.in1	1.0
net		A-btn-pos		input.0.btn-thumb2		mux2.7.sel
net		A-btn-pos-value	mux2.7.out				sum2.1.in1

net		A-jog-button	sum2.1.out

net		A-btn-neg		or2.1.in0
net		A-btn-pos		or2.1.in1

net		A-btn-any		or2.1.out				or2.2.in0
net		A-gate			or2.2.in1
net		A-motion		or2.2.out

The A-motion signal is true when either of the A jog buttons or the A joystick axis is active. That gates the MAX_ANGULAR_VELOCITY value to halui.jog-speed, rather than the default MAX_LINEAR_VELOCITY. Or, depending on the state of the toggle from the two joystick push switches, 5% of that maximum. A mere 5% may be too slow for the A axis, but it’ll take some experience to determine that.

With that in hand, the final step is gating either the knob or the button values to halui.jog.*.analog.

net		Z-jog-button	mux2.8.in0
net		Z-jog-knob-inv	mux2.8.in1
net		Z-gate			mux2.8.sel
net		Z-jog			mux2.8.out				halui.jog.2.analog

net		A-jog-button	mux2.9.in0
net		A-jog-knob		input.0.abs-z-position	mux2.9.in1
net		A-gate			mux2.9.sel
net		A-jog			mux2.9.out				halui.jog.3.analog

The complete source file (Logitech Dual Action Gamepad – joystick axis lockout – custom_postgui-hal.odt) is over on the G-code and Suchlike page, so you can download it as one lump. It’s an OpenOffice document because WordPress doesn’t allow plain text files.

I loves me my new joggy thing!

6 thoughts on “EMC2 Gamepad Pendant: Joystick Axis Lockout

  1. I finally got it working thanks to your examples. It would have taken me a LOT longer to get it figured out without you having done the leg work first. I have a three axis machine X2 with a cncfusion/xylotec kits installed. With the mode button selected it locks out both the x & y axis from being selected at the same time on the hat and knob buttons. It has three speed selections using the 3 right buttons with the lowest speed allowing me to jog at .00025 at a time. I’m going to try and post the contents of the custom hal file in hopes that it might save others some pain in creating there own.

    Thank again,

    1. post the contents of the custom hal file

      It’d probably be better as an addition to the EMC2 wiki or doc, as they have a page for joystick things and it’d be visible to more folks there than here.

  2. There must be a limit to the comment size because it won’t accept the size of the file but I’d be glad to sent it to you to post if you like. I prefer the way the speed selection as it allows for very fine jog speeds using the knobs.

Comments are closed.