Motor drivers

DC gear motors with encoders

JGB37-520

JGB37-520 geared DC motor with magnetic quadrature encoder.

This is a 6-wire motor: two power leads (into an H-bridge, typically L298N), Vcc and GND for the hall sensors, and two encoder channels A and B.

Typical spec sheet values (varies by gear ratio variant):
  • Encoder CPR at motor shaft: 11

  • Gear ratio (example): 1:30 -> output shaft CPR = 11 * 30 * 4 = 1320 edges (multiply by 4 because we count both edges on both channels)

This class is a thin Python wrapper over the C Servo type in _openbricks_native (see native/user_c_modules/openbricks/servo.c). The wrapper’s job is to build the hardware handles (Pin / PWM / encoder) from pin numbers and pass them to the native servo — the closed-loop control tick runs in C at the motor_process tick rate (1 kHz default).

class openbricks.drivers.jgb37_520.JGB37Motor(in1, in2, pwm, encoder_a, encoder_b, counts_per_output_rev=1320, invert=False, encoder_invert=False, kp=_DEFAULT_KP)[source]

Bases: Motor

run(power)[source]

Run at the given power (-100..100). Non-blocking.

brake()[source]

Stop with active braking (both terminals shorted).

coast()[source]

Stop by cutting drive power (motor free-wheels).

angle()[source]

Return the current shaft angle in degrees.

reset_angle(angle=0)[source]

Set the current angle to angle degrees.

run_speed(deg_per_s)[source]

Enter closed-loop speed control with the given target (deg/s).

run_angle(deg_per_s, target_angle, wait=True, accel_dps2=720.0)[source]

Rotate by target_angle degrees, following a trapezoidal profile at up to deg_per_s.

The native servo builds the profile once and the scheduler samples it at 1 kHz, so acceleration / cruise / deceleration phases are smooth and the move stops cleanly at the target without overshoot (apart from small integration error).

With wait=False the scheduler keeps running the profile; the caller can poll self._servo.is_done() or eventually call brake() / coast().

MG370

MG370 geared DC motor with GMR (giant magnetoresistance) quadrature encoder.

The GMR variant has a 500-PPR encoder on the motor shaft, giving massively more resolution than a standard Hall-effect encoder — at a 1:34 gearbox the output shaft sees 500 * 4 * 34.014 68028 CPR. That edge rate is too fast for the software QuadratureEncoder (Pin.irq() tops out around 5-10 kHz), so this driver uses the native PCNTEncoder — a C wrapper over the ESP32 PCNT peripheral — baked into the firmware image.

Every MG370Motor instance needs its own PCNT unit — ESP32 has 8, ESP32-S3 has 4. Pick unit=0 for the first motor, unit=1 for the second, etc.

Apart from the encoder layer, MG370Motor is identical to JGB37Motor: same native Servo underneath, same control tick, same closed-loop API.

class openbricks.drivers.mg370.MG370Motor(in1, in2, pwm, encoder_a, encoder_b, pcnt_unit=0, pcnt_filter=1023, counts_per_output_rev=_DEFAULT_CPR, invert=False, encoder_invert=False, kp=_DEFAULT_KP)[source]

Bases: Motor

run(power)[source]

Run at the given power (-100..100). Non-blocking.

brake()[source]

Stop with active braking (both terminals shorted).

coast()[source]

Stop by cutting drive power (motor free-wheels).

angle()[source]

Return the current shaft angle in degrees.

reset_angle(angle=0)[source]

Set the current angle to angle degrees.

run_speed(deg_per_s)[source]

Hold a target speed (closed loop).

run_angle(deg_per_s, target_angle, wait=True, accel_dps2=720.0)[source]

Rotate by target_angle degrees at deg_per_s. Blocks if wait; otherwise returns immediately and the caller polls done() to advance the move and detect completion.

H-bridge drivers (open loop)

L298N

L298N H-bridge motor driver.

The L298N drives a brushed DC motor via two direction pins (IN1/IN2) and one PWM pin (EN-A or EN-B). It’s open-loop: the class knows nothing about the physical motor speed or position. For closed-loop use, wrap one of these in jgb37_520.JGB37Motor (which adds an encoder).

Pinout recap for one channel:

IN1  = direction bit A
IN2  = direction bit B
PWM  = enable / speed (tie to VCC for 100%, PWM for speed control)

IN1  IN2  result
---  ---  ----------
 0    0   coast
 0    1   reverse
 1    0   forward
 1    1   brake
class openbricks.drivers.l298n.L298NMotor(in1, in2, pwm, invert=False, pwm_freq=_PWM_FREQ_HZ)[source]

Bases: Motor

run(power)[source]

Power is -100..100.

brake()[source]

Short both terminals — active brake.

coast()[source]

Cut drive entirely — motor spins freely.

TB6612FNG

TB6612FNG dual MOSFET H-bridge — re-exposes L298NMotor under the TB6612 name.

Both chips drive each motor channel with the same three signals:

IN1 — direction bit 1 IN2 — direction bit 2 PWM — speed (PWM duty cycle)

…so the openbricks driver is identical. TB6612 is generally the better commodity choice — MOSFETs instead of Darlingtons, ~0.3 V drop instead of ~1.8 V, 3.3 V-logic compatible directly from an ESP32 GPIO, and 3.2 A peak per channel vs L298N’s 2 A.

Wiring difference to be aware of: TB6612 has a chip-level STBY pin that must be held high for either channel to operate. Tie it to 3.3 V on your breakout, or drive a spare GPIO high at boot — openbricks doesn’t model STBY because most breakout modules already pull it up.