Homing and limit switches

Help with eShapeoko electronics
Post Reply
cvoinescu
Site Admin
Posts: 7
Joined: Thu 24 May 2018 10:32

Homing and limit switches

Post by cvoinescu »

Some of the most common questions I get are about connecting limit switches to an Arduino running GRBL, with a GAUPS or similar shield that does not have support for limit switches.

First, to clarify the terms, a homing switch helps get the machine to a known position at startup. The machine does not have any position sensing, so it executes a homing cycle, moving slowly until it presses a switch on each axis. These switches are located at known positions, often at the end of travel in the positive direction of each axis (by convention, this is the right-hand side of the X axis, the rear side of the Y axis, and the top of the Z axis). After homing is done, homing switches don't do anything anymore.

A limit switch detects when the machine accidentally overshoots the end of travel on an axis. This should never happen. The controller may not be able to stop the machine before it hits the hard stop, but at least it knows that something went wrong and that the position of the machine is no longer known, and it prevents it from continuing the job (and causing more damage).

With most small machines, one limit switch on each axis doubles as a homing switch. The switches are used as homing switches during a homing cycle, and as limit switches at all other times. To keep things simple, I will refer to them as limit switches from now on.

If you are using these microswitches, the pin functions are marked on the body of the swtich. C is common, NO is normally open, and NC is normally closed. When not pressed, the switch connects C to NC. When pressed, it connects C to NO. Note that all microswitches of this type have the contacts in the same order, and the common contact is the one on the same side as the plunger. Here's how a microswitch works, if you're curious.

limit switch 00 microswitch.png
limit switch 00 microswitch.png (11.24 KiB) Viewed 2434 times

The GRBL documentation used to recommend NO (normally-open) switches connected between ground and the respective Arduino pin (D9, D10 and D12); it now shows a few other ideas, and I'll get to them too. Note that ground means the GND terminal on the Arduino, not an earth ground connection.

limit switch 01 NO single.png
limit switch 01 NO single.png (12.4 KiB) Viewed 2434 times

If you have switches at both ends of an axis, simply connect them in parallel, so that when either is pressed, the Arduino input pin is connected to ground and reads low. Like this (showing only one of the three axes):

limit switch 02 NO twin.png
limit switch 02 NO twin.png (9.46 KiB) Viewed 2434 times

When neither switch is pressed, the input pin is not connected to anything* except a resistor (called a pull-up resistor, built into the Arduino) tied to the positive logic supply voltage**, making it read high (hence the name, pull-up).


This simple configuration works for many people. However, some report that GRBL detects false triggering of limit switches, or that the homing cycle sometimes fails. The false signals happen either randomly, or can be traced to devices that generate electromagnetic interference (spindles, vacuum cleaners, refrigerator compressors, or even lights), especially when they turn on or off. There are many ways for electrical noise to make its way to the input pins of the Arduino, but long wires in proximity to noisy devices (spindle, motors) certainly don't help, and neither do noisy power supply circuits.

I am one of the lucky people who experience plenty of spurious limit switch alarms and failed homing cycles when using the simple method, so I took advantage of that and tested several different ways of solving the problem. I'll talk about them in the next few posts, and rate them for complexity and effectiveness.

_____________
* not connected to anything, except a long wire acting as a nice antenna for receiving all sorts of interference.

** logic supply voltage is +5 V in the case of an Arduino Uno or Mega, but some other models (Due, Zero) use +3.3 V. You'll also see this voltage referred to as VCC or VDD in schematics. All non-ancient Arduino boards also have a pin named IOREF, which is connected to the correct voltage for that type of Arduino (+5 V or +3.3 V). It's best to always use this IOREF pin.
cvoinescu
Site Admin
Posts: 7
Joined: Thu 24 May 2018 10:32

Re: Homing and limit switches

Post by cvoinescu »

Solution: use NC (normally closed) switches.

This is the simplest solution. It reduces the chance of false triggering tremendously, but may not eliminate the problem completely (it didn't for me). Homing cycles can still fail, or, rarely, succeed, but be slightly off.

Configure GRBL to invert the limit switch pins, so that "connected to ground" means limit not reached, and "not connected" means a limit switch has been activated. This also tells you how to wire the switches. If there's a single switch on an axis, simply connect the NC contact between GND and the input pin. If there are two switches, one at each end, wire them in series:

limit switch 03 NC twin.png
limit switch 03 NC twin.png (9.03 KiB) Viewed 2432 times

This is an improvement because electrical interference has a tougher time affecting circuits with a low impedance. When the switch is closed, which is most of the time, it connects the input directly and firmly to ground, so interference is less likely to cause a false "high" reading. When the limit is reached, the switch is open and the circuit has a much higher impedance (that of the fairly weak built-in pull-up resistor), so interference can more easily cause a false "low" reading. This is not important when a limit switch is triggered, but can still cause trouble during homing.

It also has the advantage that a broken wire causes a limit switch alarm, instead of the switch simply failing to register.
cvoinescu
Site Admin
Posts: 7
Joined: Thu 24 May 2018 10:32

Re: Homing and limit switches

Post by cvoinescu »

Solution: NC switches with stronger pull-up resistors

Only slightly more complicated. The wiring is the same, but there are three additional resistors on the Arduino end. As usual, only one of three identical axes shown:

limit switch 04 NC pull-up twin.png
limit switch 04 NC pull-up twin.png (12.08 KiB) Viewed 2431 times

Any resistor between 470 Ω and 1 kΩ will do (the built-in pull-up resistor is between 20 and 50 kΩ). This provides a lower impedance while the switch is open, and makes it harder to read low during that time. It still doesn't fix the problem for everyone, perhaps because interference is of more than one type and couples into the circuit in more than one way.

Note connection to IOREF, which is either +3.3 V or +5 V, whatever is the right I/O voltage for that type of Arduino. It's always +5 V for Arduino Uno, but it's good practice to use the IOREF pin.
cvoinescu
Site Admin
Posts: 7
Joined: Thu 24 May 2018 10:32

Re: Homing and limit switches

Post by cvoinescu »

Solution: changeover switches

Requires three wires to each switch, but that's easy to do if you wire them like that from the beginning. Reduces the chances of false reading even more. They can be wired so that GRBL sees them as either NC or NO switches. If mimicking NO switches, as shown, GRBL works with the default settings.

We want the input pin to be connected positively to either a low or a high level, without relying on a pull-up resistor. This is easy to do with a single switch per axis: connect the NO terminal of the switch to GND, NC to +5 V, and C (common) to the input pin. This is a changeover switch, also known as a dual-throw (DT) switch.

limit switch 05 DT single.png
limit switch 05 DT single.png (7.23 KiB) Viewed 2429 times

With two switches per axis, wire them like this:

limit switch 06 DT twin.png
limit switch 06 DT twin.png (11.62 KiB) Viewed 2429 times

You can think of the normally open contacts being in parallel, and the normally closed ones being in series.

You may see that we lost the ability to detect a broken wire that disables the switches. We want to keep that feature, so we'll add a pull-down resistor.

limit switch 07 DT pull-up twin.png
limit switch 07 DT pull-up twin.png (13.14 KiB) Viewed 2429 times

This works with the default configuration, because 1 kΩ beats the 20-50 kΩ internal pull-up handily, but, to be technically correct, you can configure GRBL to disable the internal pull-ups.

For most people, this will solve all the problems. Even if it doesn't, there's no good reason not to always wire the switches this way. The extra wire costs very little, and the few additional connections at the Arduino end are definitely worth it.

:idea: To save yourself work later, always wire each switch independently, and connect them together only at the Arduino end. If you ever moved to a controller that had separate positive and negative limit switch inputs, you'd be happy you didn't have to rewire the machine. Wire is cheap!
cvoinescu
Site Admin
Posts: 7
Joined: Thu 24 May 2018 10:32

Re: Homing and limit switches

Post by cvoinescu »

Solution: use a low-pass RC filter to reject high-frequency noise

This needs a little more work on the Arduino end, and uses enough components to make it impractical to wire without a breadboard or a small PCB (protoboard will do). It's very effective, though.

We use a pull-down resistor to ground, followed by a series resistor, and a capacitor to ground:

limit switch 08 DT low-pass twin.png
limit switch 08 DT low-pass twin.png (15.77 KiB) Viewed 2428 times

Any change in the state of the switch must now charge or discharge the capacitor C1 through the series resistor R2, so it takes some time before the pin registers it. Simplifying a little, if the interference is shorter than this time, it doesn't register. We don't want to slow down the response too much*; 1 microsecond is plenty and will block a lot of interference. Almost everything that can be easily picked up by our limit switch wiring will be shorter (higher frequency) than that.

The series resistor and the parallel capacitor form what's called a low-pass RC filter. RC stands for resistor-capacitor (a bit obvious), and it's a filter because it lets only some frequencies through and blocks others. Specifically, it lets low frequencies through, so it's a low-pass filter. How low? Multiply R and C to get the time constant of the filter, which gives you an idea of how long a pulse needs to be to make it through. Go ahead, type "1 kiloohm * 1 nF" into Google search (with spaces as shown, but without the quotes). Neat, eh?
______________
* We would not mind a time constant of 10 µs or even more, because that's still fast compared to the time it takes the software to respond, or a stepper motor to take one step. However, slow-varying input levels are a problem for the type of circuit that the Arduino uses internally to read the input pins, so keep that filter to 1 µs for now.
cvoinescu
Site Admin
Posts: 7
Joined: Thu 24 May 2018 10:32

Re: Homing and limit switches

Post by cvoinescu »

Solution: use a low-pass RC filter and a Schmitt trigger buffer

More components! Well, only one more, really, but it's a 14-pin integrated circuit. This is a huge improvement, and I was not able to cause any spurious readings at all, even though I ran most of my limit switch wiring zip-tied to the motor wiring and the spindle supply cable (none of them shielded).

package 14DIP sm.png
package 14DIP sm.png (10.66 KiB) Viewed 2420 times
pinout 7414.png
pinout 7414.png (35.63 KiB) Viewed 2420 times

The intergrated circuit has six identical sections, each with an input and an output pin. These account for 12 pins; the remaining two are for getting power to the IC. One is connected to ground (GND), one to the positive logic supply (VCC or VDD). We don't usually draw these on a schematic, but they need to be connected too.

Each input pin is of a special type, which works to reduce the effect of noise. The inputs have histeresis, which is a fancy way of saying that, if you raised the voltage on the input enough for it to switch from leading low to reading high, you now have to lower it quite a bit more before it switches to low again, and vice-versa.

In other words, if the circuit was a dog, a regular input would work like this: if you were at 7 m or further, it would sit quietly; if you were at 3 m or closer, it would bark at you continuously. If you were anywhere between 3 m and 7 m, it might bark or not, it might bark intermittently, it may growl in a way you could not categorize clearly as either barking or not-barking, and it may even bite its own tail and hurt itself if you lingered at the in-between distance for too long.

The type of input we have, called a Schmitt trigger, would work like this: as you approached the dog, it would be completely quiet until you reached 4 m, then it would start barking. It would continue to bark until you retreated to 6 m or further. Then it would be quiet, and stay quiet until you approached to 4 m or closer again. There would be no distance that would confuse or hurt the dog, and if you wobbled on your feet you could not induce it to bark intermittently — you need to move a good bit to get it to start or stop.

A Schmitt trigger works well with slow-varying signals and still gives a sharp transition at its output, so we can lengthen the time constant of our RC filter to something like 10 µs.

limit switch 09 DT schmitt twin.png
limit switch 09 DT schmitt twin.png (20.32 KiB) Viewed 2420 times

The circuit I chose, the 74HC14, is an inverting buffer, meaning that when an input is low, the corresponding output is high, and vice-versa. Because of this, I flipped the connections to the switches around. That spaghetti maze of wires gives a high signal when either switch is actuated, low when neither is. The inverter function causes the Arduino pin to be low when either switch is actuated, high when neither is. This is what GRBL expects with its default settings: it's the same logic as the normally-open switch between the pin and ground we started with.

The integrated circuit has six inverters, but we only need three. We could use some of the remaining inverters to filter another input, such as a touch probe. Until then, we need to connect all unused inputs to either GND or VDD. With some types of IC, it's safe to leave unused inputs unconnected, but the 74HC family uses what's called CMOS technology, which requires all inputs to be connected to a defined logic level. In any case, unused outputs we leave unconnected (written N/C or NC, as in no connection).

You may notice that I drew this schematic with the switches on the left and the Arduino on the right. This is because having inverters pointing to the left offends my sensibilities. Seriously though, it's customary for schematics to read left to right, and they really do look weird the other way round.
cvoinescu
Site Admin
Posts: 7
Joined: Thu 24 May 2018 10:32

Re: Homing and limit switches

Post by cvoinescu »

Here's the complete schematic for the Schmitt trigger version, showing all three axes, with all connections drawn explicitly. (This way of drawing a schematic is also weird and offends my sensibilities, but you may find it useful if you're not yet used to the conventions.)

limit switch 10 DT schmitt XYZ.png
limit switch 10 DT schmitt XYZ.png (55.42 KiB) Viewed 2419 times
Baxter
Posts: 4
Joined: Tue 01 Jan 2019 15:13

Re: Homing and limit switches

Post by Baxter »

Thanks - this is very useful!
Post Reply