Skip to content

필사 모드: Driving Motors, Relays, and Inductive Loads: Why You Should Never Power a Motor from GPIO

English
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

Introduction — The Board Reboots Every Time the Motor Spins

Connect a small gear motor to Arduino D9 and its other lead to GND. Call digitalWrite(9, HIGH).

The motor twitches ever so slightly. Then the serial monitor shows the boot message again. The program starts over from the beginning. Turn the motor on again. It reboots again.

Here's where most people go straight to the code. Is it a watchdog? A stack overflow? A library conflict? There's nothing wrong with the code.

The problem is one number. The current an Arduino pin can safely supply is 20mA, and the current that motor demands is 200mA. Ten times over.

This post covers where that factor of ten goes, what it burns, and what the correct way to do this actually is. Motors, relays, and solenoids are all inductive loads with a coil inside, and an inductive load carries one extra danger that a resistor or LED doesn't have.

The Current a Pin Can Supply, and the Current a Motor Demands

Let's start by putting two numbers side by side.

LoadNormal running currentStartup or stall peakDirect GPIO drive possible?
Single LED15mANoneYes
Buzzer (passive)30mANoneRisky on Arduino, no on Pi
SG90 servo motor120mA700mANo
Small DC gear motor (TT motor)150–250mA800mA–1.5ANo
1-channel relay module70mANoneNo
5V solenoid lock600mA1.2ANo
WS2812B LED, 30 pixels60mA each, 1.8A totalNoneNo
12V cooling fan150mA (on the 12V side)400mANo (different voltage too)

Here's where the board's own limits stand:

BoardRecommended per pinAbsolute max per pinTotal GPIO combined5V rail supply limit
Arduino Uno R320mA40mA200mA~450mA
Raspberry Pi 40-pin16mA16mA50mA~1000mA
ESP32 DevKit v112mA40mA120mA~500mA

In this table, the only row that permits driving anything directly from GPIO is the first one.

Now let's move to the physics. Connect a motor demanding 200mA to a pin that can only supply 20mA — what exactly happens?

The pin's output stage is a tiny pair of MOSFETs. Write HIGH and the upper MOSFET turns on, connecting the pin to 5V — but this MOSFET isn't a perfect switch, it has resistance. For the ATmega328P, that's roughly 25 ohms.

Say the motor's coil resistance is 5 ohms; the total circuit resistance is 30 ohms.

Current flowing = 5V / 30 ohm = 0.167A = 167mA

167mA passes through that tiny MOSFET. The power dissipated in the MOSFET is:

P = I² × R = 0.167² × 25 = 0.028 × 25 = 0.70W

0.7W. This MOSFET was designed around 20mA, where the power dissipated is:

P = 0.02² × 25 = 0.00001 W = 0.01mW

Seventy thousand times the design value. Put 0.7W into a sliver of silicon and the junction temperature climbs to hundreds of degrees on a millisecond timescale. The outcome is one of two things. Either the gate oxide loses its insulating property and the pin gets permanently stuck at HIGH or LOW, or the metal trace melts and the pin breaks off entirely.

And the reboot has a slightly different cause. When 167mA suddenly drains away, the 5V rail momentarily collapses. We'll cover that in detail in the last section.

Let's establish one principle here. A GPIO pin is a place that issues commands, not a place that supplies power. Power should always come directly from the supply, and the pin's only job is to open and close a switch that lets that power through.

External Power and Common Ground — What Happens If You Don't Tie the Grounds Together

Say you've decided to give the motor its own separate power supply. You get a 6V battery pack, connect the motor to it, and have the Arduino control a switching transistor.

There's one piece of wiring beginners almost always forget: the wire connecting the battery's minus terminal to the Arduino's GND.

Why it's needed becomes clear if you go back to the definition of voltage from the earlier post. Voltage is a difference between two points. When the Arduino says "I output 5V," that 5V is relative to the Arduino's own GND. The battery-side circuit sees its voltage relative to the battery's own minus terminal. If the two reference points aren't connected, there's no shared scale between the two circuits.

Take the MOSFET's gate as an example. The condition for a MOSFET to turn on is that the voltage between gate and source exceeds the threshold voltage. The gate comes from the Arduino, and the source sits on the battery-side GND. With the two GNDs floating apart, the voltage between gate and source is undefined. With an undefined value opening and closing the switch, the symptom becomes "it works sometimes and doesn't other times."

What you actually observe is stranger still. The two circuits aren't fully isolated — they're weakly coupled through stray capacitance. So the electrical noise generated as the motor spins shakes the Arduino side's reference potential through that coupling. Touch it with your hand and the behavior changes; connect an oscilloscope probe and it suddenly goes normal. The probe's ground lead tied the two circuits together.

The rule is simple: the GNDs of circuits running on separate power supplies must meet at one point. You can split up the positive rails, but the negatives are shared.

One more practical tip here: it's better to keep the wire that ties the GNDs together separate from the thick wire carrying the motor's current. The GND wire carrying motor current has resistance too, and that creates a voltage drop. A thin 20-centimeter jumper wire has roughly 0.05 ohms, and if 1A flows through it:

0.05 ohm × 1A = 0.05V

50 millivolts appears between the two circuits' reference points. That's not a big deal for a logic signal, but if you're also reading an analog sensor at the same time, the reading will wobble by that much. The rule is to route the motor's GND back to the supply with a short, thick wire, and route the logic's GND separately, meeting the supply at that same point.

Switching with Transistors and MOSFETs

To have the pin only issue commands while the current comes from the supply, you need a switch. There are two kinds of semiconductor switches, and the criteria for picking one are clear.

BJT — Controlled by Current

A bipolar transistor passes a collector current proportional to the current fed into its base. To use it as a switch, you need to drive it into saturation, meaning fully on — which means you have to supply generous base current.

Say you're switching a single relay module. The coil current is 70mA. Using a small-signal transistor like the 2N3904, and being conservative rather than trusting the datasheet's current gain figure, estimate the gain at 10.

Base current needed = 70mA / 10 = 7mA

The base resistor is the pin voltage minus the base-emitter voltage drop of 0.7V, divided by that current.

Base resistor = (5V - 0.7V) / 0.007A = 614 ohm

Here's an important point: the rounding direction is the opposite of the LED resistor. With an LED, insufficient current is safe, so you round up. A base resistor needs to round down — if base current is insufficient, the transistor only half-turns-on, dissipating power in itself and getting hot. Below 614 ohms on the E24 series is 560 ohms.

Actual base current = (5V - 0.7V) / 560 ohm = 0.0077A = 7.7mA

7.7mA, inside the 20mA pin limit. Safe.

Even fully on, a BJT still has about 0.2V left between collector and emitter. That's the saturation voltage, and at 70mA the loss is:

0.2V × 0.07A = 0.014W = 14mW

Negligible.

MOSFET — Controlled by Voltage

As current climbs, the BJT becomes a bad choice. Switching 200mA needs 20mA of base current, which is the Arduino pin's entire limit. At 500mA you'd need 50mA, which is impossible outright.

A MOSFET turns on with just a gate voltage. The gate is insulated, so essentially no current flows once it's in a steady state — meaning a small pin can control a large current.

Here's the decisive detail: you must pick a logic-level MOSFET. An ordinary MOSFET is designed to fully turn on only with 10V on the gate — the well-known IRF540N is like this. Apply just 5V and it only half turns on, leaving significant resistance, and that resistance generates heat. Push 1A through it with a resistance of 0.5 ohm:

P = 1² × 0.5 = 0.5W

0.5W turns to heat in the MOSFET. Without a heatsink, it gets hot.

A logic-level MOSFET is designed to fully turn on with just 4.5V on the gate. The IRLZ44N is a classic example; this part's on-resistance at 5V gate drive is 0.028 ohm.

P = 1² × 0.028 = 0.028W = 28mW

An 18x difference. That's the difference between IRF and IRLZ in a part's name.

But on a 3.3V board, you need one more level of caution. Even the IRLZ44N's specs aren't guaranteed at a 3.3V gate. On a Raspberry Pi or ESP32, you need to pick a part with a gate threshold explicitly specified at 2.5V or below. The AO3400 and IRLML2502 are commonly used for exactly this purpose.

Gate Resistor and Pull-Down Resistor

A MOSFET circuit needs two resistors added.

The gate resistor sits in series between the pin and the gate. A MOSFET's gate is a capacitor, so the instant it turns on, a large surge current flows to charge that capacitor. With no resistor, the only thing limiting that current is the pin's own internal resistance. Put in 220 ohms and:

Peak instantaneous gate current = 5V / 220 ohm = 0.0227A = 22.7mA

22.7mA. The duration is tens of nanoseconds, so an Arduino tolerates it, but a Pi has no margin to spare. At 3.3V with 470 ohms:

3.3V / 470 ohm = 0.007A = 7mA

7mA, safe. Make the gate resistor too large and switching gets slow, leaving the MOSFET stuck in a middle state for longer and generating heat during that stretch, so a practical range is 100 to 470 ohms.

A pull-down resistor goes between the gate and GND, roughly 10 kilohms. The reason is the same as the floating input from the earlier post. While the board is booting, and during a reset, GPIO pins sit at high-impedance input state. During that stretch, the gate is connected to nothing, and if ambient noise pushes the voltage up, the MOSFET turns on. In other words, the motor twitches for an instant the moment power is applied. The pull-down resistor holds the gate at 0V during that window.

Skip this one resistor and you get the symptom "the motor jerks once every time you power it on" — and on a robot, that single jerk can be enough to break an arm.

Flyback Diodes — The Physics of Inductive Kickback

Get this far and the switching circuit looks complete. And yet after flipping a relay on and off a few times, the MOSFET dies. Current and voltage both have plenty of margin on paper, and it still dies.

The cause is the coil.

Why Thousands of Volts Show Up

An inductor's fundamental nature is that it opposes a change in current. In equation form:

V = L × (di / dt)

L is inductance, and di/dt is the rate of change of current over time. What this equation says is that the faster you try to change the current, the larger a voltage the inductor generates to resist you.

Say the relay coil's inductance is 100 millihenries and 70mA is flowing. The MOSFET takes roughly 1 microsecond to turn off.

V = 0.1H × (0.07A / 0.000001 second)
  = 0.1 × 70000
  = 7000V

7000 volts. That's the calculated value, and in reality it stops at a lower value due to air-gap breakdown or component failure, but it's real — anywhere from hundreds to thousands of volts.

The direction of this voltage matters. The coil wants to keep pushing the current it had flowing, so it pushes up the potential of whichever side just got cut off. In other words, the MOSFET's drain voltage spikes far above the supply voltage. The IRLZ44N's maximum drain-to-source rating is 55V. Hit it with hundreds of volts and breakdown occurs, and repeatedly absorbing that breakdown energy eventually kills the part.

It's worth calculating the size of the energy too, to get a feel for it.

E = 0.5 × L × I² = 0.5 × 0.1 × 0.07² = 0.000245J = 245 microjoules

245 microjoules doesn't look like much, but release it within 1 microsecond and the instantaneous power is:

0.000245J / 0.000001 second = 245W

245 watts. Very brief, but it repeats every single time.

What the Diode Does

The fix is to give that energy somewhere to go. Add a diode in parallel with the coil. Point it in the direction that doesn't conduct under normal conditions — that is, connect the cathode (the banded end) to the positive supply, and the anode to the MOSFET's drain side.

Under normal conditions, the diode is reverse-biased and does nothing. The moment the MOSFET turns off and the coil pushes the voltage up, once the drain voltage rises above the supply voltage by the diode's forward voltage, the diode starts conducting. Then the coil's current circulates back to the coil itself through the diode. With somewhere to go, there's no longer any reason for the voltage to keep climbing.

The drain's maximum voltage at that point is:

Supply voltage + diode forward voltage = 5V + 0.7V = 5.7V

7000V becomes 5.7V. For what a single component does, that's a dramatic difference.

The circulating current gets consumed as heat in the coil's own resistance and gradually dies down. That 245 microjoules quietly disappears over a few milliseconds.

Choosing a Diode, and the Side Effects

There are criteria for which diode to use.

The current rating needs to be at or above the coil current. At 70mA, a 1N4148's 200mA would work, but people often go with a 1A 1N4007 to leave margin.

The reverse-voltage rating needs generous margin above the supply voltage. The 1N4007 is rated 1000V, plenty for any low-voltage circuit.

Recovery speed matters in some cases. When you use PWM to control motor speed, you're switching thousands of times per second, and a general-purpose rectifier diode like the 1N4007 takes several microseconds to switch back to reverse-blocking, causing losses during that stretch. In that case, use a Schottky diode like the 1N5819 instead. Its forward voltage is also lower, at 0.3V, giving a lower clamp voltage too.

The side effects are worth knowing too. Adding the diode lengthens how long it takes the relay to release, because the coil current now dies down slowly. It's usually a few milliseconds, but if the contacts release later, the arc lasts longer, shortening contact life. In circuits where this matters, the diode gets a resistor or a zener diode added in series to raise the clamp voltage a bit, as a compromise.

And finally, when you buy a relay module or motor driver board as a finished product, this diode is often already built into the board. You only need to remember it when you're switching a coil with your own transistor directly. Still, it's safer to check by eye whether it's on the board or not.

Motor Driver ICs and the H-Bridge

Everything so far can only turn a motor on and off. To reverse direction, you have to flip the direction of current, and that takes four switches. This structure is called an H-bridge, because its shape resembles the letter H.

      +V                +V
       │                 │
     [S1]              [S2]
       │                 │
       ├──── motor ───────┤
       │                 │
     [S3]              [S4]
       │                 │
      GND               GND

  Turn on S1 and S4 and current flows left to right,
  turn on S2 and S3 and it flows right to left.
  Turn on S1 and S3 at the same time and the supply shorts to GND.

That last line is exactly why you don't build an H-bridge yourself. If the top and bottom switch on the same side turn on at once, the supply shorts out — this is called shoot-through current. MOSFETs turn on and off at different speeds, so in the gap between turning one off and turning the other on, both can end up briefly on at the same time. Real designs handle this by inserting dead time, and getting that exactly right in software is risky.

So in practice, you use a driver IC.

PartChannelsCurrent per channelTypeNotes
L293D2600mABJTOld standard, large ~2V voltage drop
L298N22ABJTCommon module, ~2V voltage drop, needs a heatsink
DRV883321.5AMOSFETSmall voltage drop, good for compact robots
TB6612FNG21.2AMOSFETReplacement for the L298N, efficient
A4988 / DRV88251 stepper axis1–2AMOSFETStepper-dedicated, adjustable current

The L298N module is the most common, but there's something worth knowing. Because it's BJT-based internally, it drops roughly 1V per direction, nearly 2V combined. Off a 6V supply, what actually reaches the motor is 4V — a third gets lost as heat inside the driver. When using small motors in the 3V class, that loss is deadly, making the DRV8833 or TB6612FNG the better choice.

Relay Modules and Optocoupler Isolation

For loads that need to be fully electrically isolated from the microcontroller — household AC appliances, 12V lighting — a relay is the tool.

A relay works by running current through a coil to make an electromagnet, and using that force to move a mechanical contact. There's physical space between the contact and the coil, so the two are completely electrically separated. Even with 220V on the contact side, the coil side stays entirely within its own 5V world.

Off-the-shelf relay modules usually also include an optocoupler. This adds one more layer of isolation — inside is an LED facing a phototransistor. The signal is converted to light and carried across, so there's no electrical connection whatsoever between the two circuits.

There's something practically important here: a jumper on the module. Most relay modules have pins labeled VCC, GND, and JD-VCC, with a jumper bridging between them. With that jumper installed, the relay coil also draws its power from the microcontroller's 5V. Even with the optocoupler present, sharing the power supply erases the point of the isolation.

There's a practical problem too. The relay coil draws 70mA. On a 4-channel module, if all four turn on at once:

70mA × 4 = 280mA

280mA. That's a significant chunk of an Arduino 5V rail's 450mA limit, and the current swing as the relays turn on shakes the 5V rail, destabilizing the board.

Doing it right means pulling the jumper and connecting a separate 5V supply to JD-VCC. Then coil current comes from the separate supply, and the microcontroller only supplies a few milliamps to the optocoupler's LED. And in this case, the two supplies' GNDs must NOT be tied together, or isolation is lost. This is the one exception to the rule from earlier that GND must always be tied together — the reason being that the optocoupler transfers a signal without ever sharing a reference point.

One more thing: many relay modules are active-low. You have to give the IN pin a LOW for the relay to engage. So while the board is booting, if the pin is floating, the relay can briefly engage and then release. For a light, that just flickers; for a heater or motor, it's a real problem. The pull-up resistor from the earlier post comes back into play here.

Decoupling Capacitors and Brownout — This Isn't a Code Problem

Let's finally return to this post's opening paragraph: the board rebooting every time the motor turns on.

Even after building the switching circuit correctly and adding a separate power supply, this symptom often lingers. The cause is the resistance in the power wiring.

Every wire has resistance. A 1-meter USB cable's power line is roughly 0.2 ohms, breadboard contact resistance is 0.01 to 0.05 ohms per contact, and a jumper wire is around 0.05 ohms. Add it all up and you get roughly 0.3 ohms.

Say the current flowing when the motor starts up is 1.5A:

Voltage drop = 1.5A × 0.3 ohm = 0.45V

A 5.1V incoming supply becomes 4.65V by the time it reaches the board.

A Raspberry Pi throws an undervoltage warning once its 5V rail drops below 4.63V, and falls further and SD card access fails or it reboots. The Arduino's ATmega328P has a brownout detection circuit that forces a reset if the voltage drops below 2.7V under default settings. Feed a 5V regulator 4.65V and its output drops even lower, and a bigger startup current pushes it past that threshold.

This is exactly why the symptom looks like code. The reset happens while the code is running, and the boot message shows up on serial. It looks like a completely software problem.

What a Capacitor Can and Can't Do

The response happens on two layers.

Put a 100 nanofarad ceramic capacitor right next to each IC's power pin. This supplies fast current fluctuations on a nanosecond-to-microsecond timescale. When transistors inside a chip switch, they need a burst of current instantly, and pulling that from the supply is too slow because of wiring inductance. A tiny capacitor sitting right there fills in that instant.

Put a 470 microfarad electrolytic capacitor near the motor's power input. This smooths out larger swings on a millisecond timescale. Let's calculate how much it actually helps. To supply 1A of extra current for 100 microseconds while holding the voltage drop to 0.2V, the capacitance needed is:

C = I × Δt / ΔV = 1A × 0.0001 second / 0.2V = 0.0005F = 500 microfarads

500 microfarads. 470 microfarads is close enough.

But a motor's startup time isn't 100 microseconds — it's several milliseconds. Recalculate for 5 milliseconds:

C = 1A × 0.005 second / 0.2V = 0.025F = 25000 microfarads

25,000 microfarads. That's not a component you're plugging into a breadboard.

What this calculation tells you is clear. A capacitor smooths short spikes — it isn't a substitute for insufficient power. If brownouts keep happening, the fix isn't a bigger capacitor, it's changing the power source itself.

The Actual Order of Troubleshooting

When this symptom shows up, here's the order to check things.

First, check whether the motor's power supply and the logic power supply are separated. If both are being pulled from the same USB source, that's the cause.

Second, switch to thick, short wires. The power path through a breadboard accumulates contact resistance, so for high-current paths, solder directly or connect with thick wire instead.

Third, add capacitors. Put 100 nanofarads across the motor's terminals on both sides, and 470 microfarads at the motor's power input. The ceramic capacitor at the motor terminals also suppresses high-frequency noise coming from the brushes.

Fourth, add a soft start. Ramping speed up gradually with PWM lowers the peak startup current. This is the only mitigation you can implement purely in code.

// Drives a MOSFET gate with PWM to start a motor gradually.
// Wiring: D9 -> 220 ohm -> MOSFET gate, 10k pull-down between gate and GND
//         Motor on separate power supply, a 1N5819 flyback diode in parallel with the coil
//         The two supplies' GNDs meet at a single point

const int MOTOR_PWM_PIN = 9;
const int RAMP_STEP_MS = 12;     // Wait time between each step
const int TARGET_DUTY = 200;     // 0 to 255. Final speed

void setup() {
  pinMode(MOTOR_PWM_PIN, OUTPUT);
  analogWrite(MOTOR_PWM_PIN, 0);
  delay(500);                    // Wait for the supply to stabilize
}

void softStart() {
  // Ramps from 0 to the target over roughly 2.4 seconds.
  // Jump straight to 255 and the full startup current flows at once, collapsing the rail.
  for (int duty = 0; duty <= TARGET_DUTY; duty++) {
    analogWrite(MOTOR_PWM_PIN, duty);
    delay(RAMP_STEP_MS);
  }
}

void softStop() {
  for (int duty = TARGET_DUTY; duty >= 0; duty--) {
    analogWrite(MOTOR_PWM_PIN, duty);
    delay(RAMP_STEP_MS);
  }
}

void loop() {
  softStart();
  delay(3000);
  softStop();
  delay(2000);
}

Don't mistake this code for the fundamental fix, though. Soft start only lowers the peak of the startup current, and once the motor hits a load and stalls, the stall current flows exactly as before. If the supply can't handle that current, the same symptom shows up again.

Once you've wired everything up and want to check whether your current budget adds up, drop your parts into this site's circuit wiring validator. For parts needing separate power, like servo motors or LED strips, it flags peak current and recommends a separate supply, and it also calculates whether the 5V rail total exceeds your board's supply limit.

Conclusion — The Pin Issues Commands, and Power Comes From the Supply

The accidents covered in this post look different on the surface: a pin burning up, a board rebooting, a MOSFET dying, a relay briefly engaging on boot.

But they all come from the same misunderstanding: treating a GPIO pin as if it were a power supply.

A pin is a signal line that opens and closes a switch. The switch that signal controls is what passes the large current from the supply to the load. Keep this structure intact and the magnitude of the current has nothing to do with the pin at all. Whether it's 1A or 10A, all the pin does is charge a gate with a few milliamps.

And an inductive load has one more thing added on top. A coil hates the instant its current gets cut off, and it expresses that displeasure with thousands of volts. Build that energy a path in advance with a diode, and it quiets down to 5.7V. The difference between forgetting one diode and including it is a factor of a thousand.

Everything covered across these five posts ultimately converges on three numbers: how many volts land on this component, how many milliamps flow through it, and what value can this pin actually handle. Nearly every mistake that quietly wrecks hardware in a circuit comes from not checking one of these three. Building the habit of writing these three numbers down on paper before connecting a component beats reading ten schematics.

현재 단락 (1/193)

Connect a small gear motor to Arduino D9 and its other lead to GND. Call `digitalWrite(9, HIGH)`.

작성 글자: 0원문 글자: 21,103작성 단락: 0/193