Fixing the Nidec 24H055M020 Gritters & Achieving Precise Measurement

by NewsonsElectronics in Circuits > Arduino

559 Views, 1 Favorites, 0 Comments

Fixing the Nidec 24H055M020 Gritters & Achieving Precise Measurement

NO Charger!!! (10).png
I Won a Box of Brushless Motors… Here’s Why
Motor Wiring.png

Does your Nidec 24H055M020 have the jitters? Or are you missing the wiring diagram? I reverse-engineered how these motors work and ended up winning a prize for it. The company that sells them gifted me a box of motors after I figured out the correct wire diagram.


Link to the full video explanation

https://youtu.be/kLB62EAp83k

https://youtu.be/TdrySOXRl-Y

Supplies

Nidec 24H055M020 BLDC motor→ Amazon.ca , Amazon.com , Taobao

Arduino UNO→ Amazon.ca , Amazon.com

Fixing the Gitters

The motor’s “gitters” were caused by improper timing of the PFM (Pulse Frequency Modulation). Initially, I was manually bit-banging the frequency to reach a high 16 kHz, but it wasn’t very clean. Later, I discovered that using the tone() function native to the Arduino Uno produces a much cleaner signal.

The key takeaway: avoid any delays in the main loop of your code.

Previous approach (bit-banging Timer1 PFM):


// ===== Timer1 PFM =====
TCCR1A = 0;
TCCR1B = 0;
TCCR1A |= (1 << COM1A1);
TCCR1A |= (1 << WGM11);
TCCR1B |= (1 << WGM12) | (1 << WGM13);
TCCR1B |= (1 << CS10);
setPWMFrequency(pfmFrequency);

Simpler, cleaner approach:


tone(9, frequency);





Wire Diagram

Motor Wiring.png
arudnio pinout.jpg

Nidec 24H055M020 Wiring with Arduino Uno

Motor Pins and Connections:

  1. Pin 1 – PFM (Speed): Connect to Arduino PWM pin (e.g., pin 9). Use tone(pin, frequency) to control speed (250 Hz – 26 kHz). +1 kHz ≈ 150 RPM.
  2. Pin 2 – Enable: Connect to 12V to enable motor. GND = standby.
  3. Pin 3 – Brake: GND = brake ON, VCC = brake OFF. Connect to Arduino pin if you want software brake control.
  4. Pin 4 – Direction: VCC = CCW, GND = CW. Connect to Arduino digital pin for direction control.
  5. Pins 5, 6, 7 – N/A: Not connected.
  6. Pins 8, 9, 10 – GND: Connect to Arduino GND and power supply GND.
  7. Pins 11, 12 – VCC: 12V motor supply (10–13V).

Base Code Using Tone()

// Motor Pins
const int breakPin = 10; // Break pin: GND = Break on, HIGH = Break off.
const int pfmPin = 9; // Speed control pin (PWM)
const int dirPin = 8; // Direction control pin (HIGH for CCW, LOW for CW)
const int fgPin = 2; // Feedback pin (using interrupt to count pulses)

const int potentiometerPin = A0; // Potentiometer connected to analog pin A0

void setup() {
Serial.begin(9600);
// Initialize motor pins
pinMode(pfmPin, OUTPUT); // PWM pin for speed
pinMode(dirPin, OUTPUT); // Direction pin
pinMode(breakPin, OUTPUT); // Break pin
pinMode(fgPin, INPUT_PULLUP); // Feedback pin (using interrupt)

// Set initial motor state
digitalWrite(dirPin, HIGH); // Set default direction (CCW)
digitalWrite(breakPin, HIGH); // Set default direction (CCW)
}

void loop() {
// Read the potentiometer value
int potValue = analogRead(potentiometerPin);
//digitalWrite(dirPin, HIGH); // Set default direction (CCW)

// Map the potentiometer value to the desired frequency range
int frequency = map(potValue, 0, 1023, 250, 25000);
//int frequency=1000;
// Generate tone on pin 8
tone(9, frequency);
Serial.print(frequency);
Serial.println(" Hz");

}

Percise Distance Measurement

vlcsnap-2026-04-05-22h22m02s446.jpg
vlcsnap-2026-04-05-22h22m20s037.jpg

Since we know that a 1 kHz increase in PFM corresponds to roughly 150 RPM, we can use this to calculate the linear distance a belt moves. By placing a pulley on the motor shaft, if we know the diameter of the pulley, we can multiply it by the circumference of the gear and the RPM to determine the linear displacement of the belt


// Compute RPM & linear speed
rpm = (currentPFM / 1000.0) * 150; // 150 RPM per kHz
speed = (rpm * circumference) / 60.0; // cm/sec
distance += speed * dt; // integrate over time.



Full code

// ===== Pin Definitions =====
const int homingPin = A1;
const int fgPin = 2;
const int brakePin = 10;
const int pfmPin = 9;
const int dirPin = 8;

// ===== Motor / Motion Constants =====
const double PI_VAL = 3.14159265;
const double gearDiameter = 3.9; // cm
const double circumference = PI_VAL * gearDiameter;


float distanceTable[] = {10,20,30,40,50,60,70,80,90,95};
float pfmTable[] = {2000,4000,6000,6500,6000,6800,8600,8800,9000,9500};
const int tableSize = 10;

double getPFM(double distance) {
if(distance <= distanceTable[0]) return pfmTable[0];
if(distance >= distanceTable[tableSize-1]) return pfmTable[tableSize-1];

// find the table segment
for(int i = 0; i < tableSize-1; i++) {
if(distance >= distanceTable[i] && distance <= distanceTable[i+1]) {
double x0 = distanceTable[i];
double x1 = distanceTable[i+1];
double y0 = pfmTable[i];
double y1 = pfmTable[i+1];
double factor = (distance - x0) / (x1 - x0);
return y0 + factor * (y1 - y0);
}
}
return pfmTable[tableSize-1]; // fallback
}
// ===== Motion Planner Globals =====
double minPFM = 300; // Hz
//double maxSpeedNear = 2000; // Hz for short moves < threshold ,, 10cm 2000,20=4000,30=6000,40=6500,50=6000,60=6800,70=8200,80=9000,90=9000,95=9500


float targetDistance = 50; // cm
double pfmFrequency = getPFM(targetDistance);

float offsetDistance = 1.8; // cm after homing


float accelPercent = 30; // % of move used for acceleration
float decelPercent = 25; // % of move used for deceleration

// ===== Motion Variables =====

double rpm = 0;
double speed = 0; // cm/sec
double distance = 0;

float accelerationDistance = 0;
float decelerationDistance = 0;

unsigned long lastTime = 0;
unsigned long startTime = 0;
bool motorRunning = true;

const double rpmPerKHz = 150.0;

// ===== Setup =====
void setup() {
Serial.begin(115200);

pinMode(homingPin, INPUT_PULLUP);
pinMode(fgPin, INPUT);
pinMode(pfmPin, OUTPUT);
pinMode(dirPin, OUTPUT);
pinMode(brakePin, OUTPUT);

homing();

digitalWrite(dirPin, 1);
tone(pfmPin, pfmFrequency);

lastTime = micros();
startTime = millis();
}

// ===== Homing =====
void homing() {
digitalWrite(dirPin, 0);
digitalWrite(brakePin, 1);

tone(pfmPin, 400);
while(digitalRead(homingPin) == HIGH) {}

noTone(pfmPin);
delay(1000);

distance = offsetDistance;
digitalWrite(dirPin, 1);



// Compute acceleration/deceleration distances
float moveDist = targetDistance - offsetDistance;
accelerationDistance = moveDist * (accelPercent / 100.0);
decelerationDistance = moveDist * (decelPercent / 100.0);
}

// ===== Motion Planner Function =====
double motionPlannerPFM() {
double remaining = targetDistance - distance;
if(remaining <= 0) return minPFM;

// Ramp-up
if(distance - offsetDistance < accelerationDistance) {
double factor = (distance - offsetDistance) / accelerationDistance;
if(factor > 1) factor = 1;
return minPFM + factor * (pfmFrequency - minPFM);
}

// Ramp-down
if(remaining < decelerationDistance) {
double factor = remaining / decelerationDistance;
if(factor > 1) factor = 1;
return minPFM + factor * (pfmFrequency - minPFM);
}

// Cruise
return pfmFrequency;
}

// ===== Main Loop =====
void loop() {
// Compute current PFM using motion planner
double currentPFM = motionPlannerPFM();
tone(pfmPin, currentPFM);

// Compute RPM & linear speed
rpm = (currentPFM / 1000.0) * rpmPerKHz;
speed = (rpm * circumference) / 60.0; // cm/sec

// Time integration
unsigned long now = micros();
double dt = (now - lastTime) / 1000000.0;
lastTime = now;
distance += speed * dt;

// Stop motor at target
if(distance >= targetDistance && motorRunning) {
unsigned long travelTime = millis() - startTime;
Serial.print("Time to target (s): ");
Serial.println(travelTime / 1000.0);

noTone(pfmPin);
digitalWrite(pfmPin, HIGH);
delay(3000);

homing();
motorRunning = true;
lastTime = micros();
startTime = millis();
}

// Serial output for plotting
Serial.print(currentPFM);
Serial.print(" ");
Serial.println(distance);
}


Stay tuned for more projects using these motors! A major build is currently in the works. In the mean time you can subscribe to my channel. Newsons Electronics - YouTube