Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

wobbling polygon motor

BraveWart

Member
I am working on a project where I have to pulse a laser against a spinning, six sided polygon mirror motor.
https://www.precisionroller.com/motors-for-sharp-mx-3640n/products.html
(worth noting that i have them from china)
I am pulsing at the motor frequency x6 to get a single laser dot reflected of the mirrors.
The motor is receiving a PWM signal from an Arduino. The laser is receiving a 6x that frequency signal with a very small duty cycle.

For this I am using code that generates very precise pwn signals using ticks of the internal PWM clock. The signals are verified on my scope and are constant and in sync.

So far so good. I am getting my desired laser dot in the target area.
The problem is that the dot is wobbling back and forth.
I am on this project with a colleague who helped with all of this and made this video for him.
laser wobble

We cant figure out why that wobble happens.
These motors are used in laser printers and scanners and must spin with high precision.
We tried all kinds of things to make it steady. Hence the custom code for the PWM signals.

I have tried:
  • using different signal sources in case there is a problem with aligning both signals
  • hardware and software PWM's
  • i hooked up an led to the laser signal and illuminated the spinning motor in a dark room. I could clearly see the edge of the mirror wobble in the same pattern as on the laser dot
  • I blew air on the motor while doing the led test. That made the mirror wobble even more
  • I own 3 different polygon motors of different brands. they all show the same behaviour
What could it be?
Is the motor broken? But all three of them?
Is it air turbulence? But that is also hard to believe since these motors sit in open spaces inside printers. If anything, then air turbulence would be worse in there.

Any tips on what that could be are well appreciated


This is the code we are using to create both PWM signals:

C++:
#include <TimerHelpers.h>


const byte intcheck = 8;
const byte timer1OutputA = 9;
const byte timer1OutputB = 10;
volatile uint8_t pulse_count = 0;


bool LED_STATE = true;


void setup() {


   pinMode (timer1OutputA, OUTPUT);
   pinMode (timer1OutputB, OUTPUT);
   pinMode (intcheck, OUTPUT);
    cli();
  TCCR1A = 0;                 // Reset entire TCCR1A to 0
  TCCR1B = 0;                 // Reset entire TCCR1B to 0
     /*3. We enable compare match mode on register B*/
  TIMSK1 |= B00000100;        //Set OCIE1B to 1 so we enable compare match B

   Timer1::setMode (15, Timer1:RESCALE_8, Timer1::CLEAR_A_ON_COMPARE | Timer1::CLEAR_B_ON_COMPARE);
   OCR1A = 4000;
   OCR1B = 5;
  sei();                     //Enable back the interrupts
}  // end of setup

void loop() {}

ISR(TIMER1_COMPB_vect){

    if (pulse_count < 2) {

        pulse_count++;
    } else {
        pulse_count = 0;
        PORTB ^= (1 << PB0); // toggle pin 8 (PB0)
     
    }
}

and this is temerhelpers.h:
C++:
/*
 Timer Helpers library.

Devised and written by Nick Gammon.
Date: 21 March 2012
Version: 1.0

Licence: Released for public use.
 
See: http://www.gammon.com.au/forum/?id=11504
 
 Example:
 
 // set up Timer 1
 TCNT1 = 0;         // reset counter
 OCR1A =  999;       // compare A register value (1000 * clock speed)
 
 // Mode 4: CTC, top = OCR1A
 Timer1::setMode (4, Timer1::PRESCALE_1, Timer1::CLEAR_A_ON_COMPARE);
 
 TIFR1 |= bit (OCF1A);    // clear interrupt flag
 TIMSK1 = bit (OCIE1A);   // interrupt on Compare A Match 
 
*/

#ifndef _TimerHelpers_h
#define _TimerHelpers_h

#if defined(ARDUINO) && ARDUINO >= 100
  #include "Arduino.h"
#else
  #include "WProgram.h"
#endif

/* ---------------------------------------------------------------
 Timer 0 setup
 --------------------------------------------------------------- */

namespace Timer0
{
  // TCCR0A, TCCR0B
  const byte Modes [8] [2] =
  {
 
  { 0,                         0 },            // 0: Normal, top = 0xFF
  { bit (WGM00),               0 },            // 1: PWM, Phase-correct, top = 0xFF
  {               bit (WGM01), 0 },            // 2: CTC, top = OCR0A
  { bit (WGM00) | bit (WGM01), 0 },            // 3: Fast PWM, top = 0xFF
  { 0,                         bit (WGM02) },  // 4: Reserved
  { bit (WGM00),               bit (WGM02) },  // 5: PWM, Phase-correct, top = OCR0A
  {               bit (WGM01), bit (WGM02) },  // 6: Reserved
  { bit (WGM00) | bit (WGM01), bit (WGM02) },  // 7: Fast PWM, top = OCR0A
 
  };  // end of Timer0::Modes
 
  // Activation
  // Note: T0 is pin 6, Arduino port: D4
  enum { NO_CLOCK, PRESCALE_1, PRESCALE_8, PRESCALE_64, PRESCALE_256, PRESCALE_1024, T0_FALLING, T0_RISING };
 
  // what ports to toggle on timer fire
  enum { NO_PORT = 0,
    
    // pin 12, Arduino port: D6
    TOGGLE_A_ON_COMPARE  = bit (COM0A0),
    CLEAR_A_ON_COMPARE   = bit (COM0A1),
    SET_A_ON_COMPARE     = bit (COM0A0) | bit (COM0A1),
    
    // pin 11, Arduino port: D5
    TOGGLE_B_ON_COMPARE  = bit (COM0B0),
    CLEAR_B_ON_COMPARE   = bit (COM0B1),
    SET_B_ON_COMPARE     = bit (COM0B0) | bit (COM0B1),
  };
 
 
  // choose a timer mode, set which clock speed, and which port to toggle
  void setMode (const byte mode, const byte clock, const byte port)
  {
  if (mode < 0 || mode > 7)  // sanity check
    return;
 
  // reset existing flags
  TCCR0A = 0;
  TCCR0B = 0;
 
  TCCR0A |= (Modes [mode] [0]) | port; 
  TCCR0B |= (Modes [mode] [1]) | clock;
  }  // end of Timer0::setMode
 
}  // end of namespace Timer0

/* ---------------------------------------------------------------
 Timer 1 setup
 --------------------------------------------------------------- */

namespace Timer1
{
  // TCCR1A, TCCR1B
  const byte Modes [16] [2] =
  {
 
  { 0,                         0 },            // 0: Normal, top = 0xFFFF
  { bit (WGM10),               0 },            // 1: PWM, Phase-correct, 8 bit, top = 0xFF
  {               bit (WGM11), 0 },            // 2: PWM, Phase-correct, 9 bit, top = 0x1FF
  { bit (WGM10) | bit (WGM11), 0 },            // 3: PWM, Phase-correct, 10 bit, top = 0x3FF
  { 0,                         bit (WGM12) },  // 4: CTC, top = OCR1A
  { bit (WGM10),               bit (WGM12) },  // 5: Fast PWM, 8 bit, top = 0xFF
  {               bit (WGM11), bit (WGM12) },  // 6: Fast PWM, 9 bit, top = 0x1FF
  { bit (WGM10) | bit (WGM11), bit (WGM12) },  // 7: Fast PWM, 10 bit, top = 0x3FF
  { 0,                                       bit (WGM13) },  // 8: PWM, phase and frequency correct, top = ICR1   
  { bit (WGM10),                             bit (WGM13) },  // 9: PWM, phase and frequency correct, top = OCR1A   
  {               bit (WGM11),               bit (WGM13) },  // 10: PWM, phase correct, top = ICR1A   
  { bit (WGM10) | bit (WGM11),               bit (WGM13) },  // 11: PWM, phase correct, top = OCR1A
  { 0,                         bit (WGM12) | bit (WGM13) },  // 12: CTC, top = ICR1   
  { bit (WGM10),               bit (WGM12) | bit (WGM13) },  // 13: reserved
  {               bit (WGM11), bit (WGM12) | bit (WGM13) },  // 14: Fast PWM, TOP = ICR1
  { bit (WGM10) | bit (WGM11), bit (WGM12) | bit (WGM13) },  // 15: Fast PWM, TOP = OCR1A
 
  };  // end of Timer1::Modes
 
  // Activation
  // Note: T1 is pin 11, Arduino port: D5
  enum { NO_CLOCK, PRESCALE_1, PRESCALE_8, PRESCALE_64, PRESCALE_256, PRESCALE_1024, T1_FALLING, T1_RISING };
 
  // what ports to toggle on timer fire
  enum { NO_PORT = 0,
    
    // pin 15, Arduino port: D9
    TOGGLE_A_ON_COMPARE  = bit (COM1A0),
    CLEAR_A_ON_COMPARE   = bit (COM1A1),
    SET_A_ON_COMPARE     = bit (COM1A0) | bit (COM1A1),
    
    // pin 16, Arduino port: D10
    TOGGLE_B_ON_COMPARE  = bit (COM1B0),
    CLEAR_B_ON_COMPARE   = bit (COM1B1),
    SET_B_ON_COMPARE     = bit (COM1B0) | bit (COM1B1),
  };
 
  // choose a timer mode, set which clock speed, and which port to toggle
  void setMode (const byte mode, const byte clock, const byte port)
  {
  if (mode < 0 || mode > 15)  // sanity check
    return;
 
  // reset existing flags
  TCCR1A = 0;
  TCCR1B = 0;
 
  TCCR1A |= (Modes [mode] [0]) | port; 
  TCCR1B |= (Modes [mode] [1]) | clock;
  }  // end of Timer1::setMode
 
}  // end of namespace Timer1

/* ---------------------------------------------------------------
 Timer 2 setup
 --------------------------------------------------------------- */

namespace Timer2
{
  // TCCR2A, TCCR2B
  const byte Modes [8] [2] =
  {
 
  { 0,                         0 },            // 0: Normal, top = 0xFF
  { bit (WGM20),               0 },            // 1: PWM, Phase-correct, top = 0xFF
  {               bit (WGM21), 0 },            // 2: CTC, top = OCR2A
  { bit (WGM20) | bit (WGM21), 0 },            // 3: Fast PWM, top = 0xFF
  { 0,                         bit (WGM22) },  // 4: Reserved
  { bit (WGM20),               bit (WGM22) },  // 5: PWM, Phase-correct, top = OCR2A
  {               bit (WGM21), bit (WGM22) },  // 6: Reserved
  { bit (WGM20) | bit (WGM21), bit (WGM22) },  // 7: Fast PWM, top = OCR2A
 
  };  // end of Timer2::Modes
 
  // Activation
  enum { NO_CLOCK, PRESCALE_1, PRESCALE_8, PRESCALE_32, PRESCALE_64, PRESCALE_128, PRESCALE_256, PRESCALE_1024 };
 
  // what ports to toggle on timer fire
  enum { NO_PORT = 0,
    
    // pin 17, Arduino port: D11
    TOGGLE_A_ON_COMPARE  = bit (COM2A0),
    CLEAR_A_ON_COMPARE   = bit (COM2A1),
    SET_A_ON_COMPARE     = bit (COM2A0) | bit (COM2A1),
    
    // pin 5, Arduino port: D3
    TOGGLE_B_ON_COMPARE  = bit (COM2B0),
    CLEAR_B_ON_COMPARE   = bit (COM2B1),
    SET_B_ON_COMPARE     = bit (COM2B0) | bit (COM2B1),
  };
 
 
  // choose a timer mode, set which clock speed, and which port to toggle
  void setMode (const byte mode, const byte clock, const byte port)
  {
  if (mode < 0 || mode > 7)  // sanity check
    return;
 
  // reset existing flags
  TCCR2A = 0;
  TCCR2B = 0;
 
  TCCR2A |= (Modes [mode] [0]) | port; 
  TCCR2B |= (Modes [mode] [1]) | clock;
  }  // end of Timer2::setMode
 
}  // end of namespace Timer2

#endif
 
Last edited:
How are you synchronising to the motor?

Some Arduino library functions are "blocking", as in your program stops until the function finishes, so you need to be very careful with the overall arrangements to avoid undue pauses, and use internal peripherals directly, as far as possible.

It would be useful to see the whole program?
 
How are you synchronising to the motor?

Some Arduino library functions are "blocking", as in your program stops until the function finishes, so you need to be very careful with the overall arrangements to avoid undue pauses, and use internal peripherals directly, as far as possible.

It would be useful to see the whole program?
I just updated my question with the code.
I haven't written it myself, but my colleague provided it. So I am afraid I can't anwser too many questions about it.
I had actually already kind of ruled out the code as the source of the problem as we have identical results with signals coming of two different PWM modules (not really high end devices) and also from a raspberry pi 4 using softeare and hardware PWM signals
 
The problem may be with the rotor symmetry.
If it's a scanner-mirror, the six faces will be at slightly different angles to the center-axis.
I never considered that. But I am spinning at 200Hz. The wobble would be at 200Hz also, no? What I observe is in the seconds range and has a very irregular pattern to it. and blow air on it, it intensifies the effect.
One thought was that since its a "china" ordered motor thats likely refurbished, it could be that it is at its natural end of its lifespan and the air bearing just doesn't allow for consistent spin any longer. But as I mentioned in the post, I have three of these motors and I get the same result. I dont know what are the chances that they are all busted?
 
I have three of these motors and I get the same result. I dont know what are the chances that they are all busted?
One thing you haven't mentioned is how these motors are mounted. If they are just sitting on a bench top and not solidly mounted like they would be in a printer (I say printer because a quick Google search says that's what they're used in) any vibration from the bench top will get into the laser reflections.
 
I just updated my question with the code.
I don't see anything in there that looks like a decent motor speed controller or reference, to either hold the speed or track rotational position as speed varies?

If the motor speed is jittering or hunting and you are relying purely on a reflection at one angle of a facet for sync and delaying the output a fixed amount from that, slight speed variations are going to result in angular variations of the output.
 
One thing you haven't mentioned is how these motors are mounted. If they are just sitting on a bench top and not solidly mounted like they would be in a printer (I say printer because a quick Google search says that's what they're used in) any vibration from the bench top will get into the laser reflections.
The motor is screwed to a 3D printed mount that is screwed on a wooden workbench. I am using this one motor because it gives off almost no vibrations, where as the other two do send off significant vibrations.
There is a video in my original post
 
Last edited:
I don't see anything in there that looks like a decent motor speed controller or reference, to either hold the speed or track rotational position as speed varies?

If the motor speed is jittering or hunting and you are relying purely on a reflection at one angle of a facet for sync and delaying the output a fixed amount from that, slight speed variations are going to result in angular variations of the output.
That is correct. There is no feedback from the motor and our assumption was that it runs precise. (just my own assumption actually)
We never found any datasheets of these devices. There is one pin that provides a signal out, but the acquired signal was very very noisy and it also seemed to be directly linked to the input signal. If it were a feedback signal, I would have expected to ramp up as the motor spins up and ramp down as the motor spins down. But it was art a constant towards the input signal even during spin up and down phases. The assumption then was that it must be a stray signal and not a feedback signal on the actual rotation speed.
So you are saying, the wobble is likely an expected behaviour and must normally be compensated through a feedback signal of the actual speed?
 
Last edited:
That is correct. There is no feedback from the motor and our assumption is that it runs precise.
We never found any datasheets of these devices. There is one pin that provides a signal out, but the acquired signal was very very noisy and it also seemed to be directly linked to the input signal. If it were a feedback signal, I would have expected to ramp up as the motor spins up and ramp down as the motor spins down. But it was art a constant towards the input signal even during spin up and down phases. The assumption then was that it must be a stray signal and not a feedback signal on the actual rotation speed.
So you are saying, the wobble is likely an expected behaviour and must normally be compensated through a feedback signal of the actual speed?

Unless you have feedback, then motors don't run at an accurate speed - I wouldn't expect it to work unless the speed is accurately controlled - particularly as the length of the beam means that any tiny variation is multiplied massively.
 
Unless you have feedback, then motors don't run at an accurate speed - I wouldn't expect it to work unless the speed is accurately controlled - particularly as the length of the beam means that any tiny variation is multiplied massively.
Thank you. I will be looking again into that signal from the motor to see if we can get anything more useful out of it.
 
What is the IC that's visible on the motor module?

The approach I was thinking of for a free-running motor was to capture each "sync" reflection from the mirror and track the time intervals between them with a timer+software phase locked loop, so the angle was continuously tracked and speed variations could be compensated for, as a fraction of the interval.

Regardless, the more stable the motor speed, the better accuracy the system should have.
 
What is the IC that's visible on the motor module?

The approach I was thinking of for a free-running motor was to capture each "sync" reflection from the mirror and track the time intervals between them with a timer+software phase locked loop, so the angle was continuously tracked and speed variations could be compensated for, as a fraction of the interval.

Regardless, the more stable the motor speed, the better accuracy the system should have.
Soory, only got around to this today. I didnt find datasheets on two of the motors driver ics, but on the third one it has this:
https://datasheetspdf.com/pdf-file/1426875/ONSemiconductor/LB11876/1
It has multiple inputs for HAL sensors and one FG input. But if i understand this correctly, then the IC should self correct the motor speed, based on this closed feedback loop from exisiting sensors, no?
As for your idea - that sounds like an excellent idea. We are currently building a TIA for a PD and should be able to test this soon. The initial plan was to capture the beam cycles from one facet of the mirror as a "landscape" of the reflected light. Were the motor speed constant, this frame would scan at motor frequency x6. If the motor speed wobbles as observed, so will the landscape, which can be measured and then compensated
 
For that IC, the stability is controlled by the signal in to the CLK pin, and FGS is a timing pulse out that is synchronised to the actual rotation.

LD shows the motor is up to speed and synchronised with the CLK signal.

SS is the motor enable, when pulled low.

Are those pins all brought out to external connections?
 
For that IC, the stability is controlled by the signal in to the CLK pin, and FGS is a timing pulse out that is synchronised to the actual rotation.

LD shows the motor is up to speed and synchronised with the CLK signal.

SS is the motor enable, when pulled low.

Are those pins all brought out to external connections?

I am bad at tracing these. Here is some photos. Clock, LD and SS are connected. But I cant follow them as this is not my field of expertise. We identifies pins 3=CLK, 4 = GND and 5 = V. I think 1 was low and 2 was a very noisy signal , roughly square shaped, but definitely in sync with CLK.

PXL_20230522_093745735.jpg
PXL_20230522_093755916.jpg


very important to understand though that this is not the motor in use! It's the only one I could find a datasheet on the driver IC for.

The motor in use is this one:
PXL_20230522_093855186.jpg

I cannot find a Panasonic AN44003A datasheet on it.
 
Could that be the problem? Those are usually spun at much higher speeds in their normal use. I'm thinking that centripetal force may help to keep them stable, slowing them way down like you are may cause instability.
aha. didnt know that. we were planning to spin higher when we actually get to do what we want to do, but for testing i never went above 250hz. Mostly its freaking fast and i didnt trust this just yet and didnt wat to end up with something in my face if we overdid it.
So these get quite noisy when spinning at higher speeds which makes me also think how that would be in a practical environment of a laser printer.

Do you have any more information of frequencies used on printers/scanners? Where did you get this from?
 
I am bad at tracing these. Here is some photos. Clock, LD and SS are connected. But I cant follow them as this is not my field of expertise. We identifies pins 3=CLK, 4 = GND and 5 = V. I think 1 was low and 2 was a very noisy signal , roughly square shaped, but definitely in sync with CLK.
It looks to me as if CLK, LD and S/S go to testpoints 13, 14 & 15 respectively, though it's not easy to trace them.

From there they go to pins 1 - 3 in some order; it looks like CLK is pin 1, not sure about the others.

If you are using pin 3 to control it, then that's S/S, the motor enable pin.

If I'm right, it is only ever free-running without a clock signal going to pin 1 to synchronise it. That ties in with the noisy signal from LD, it's never able to lock up in sync with anything.

ps. 250 Hz (Facet speed) is 2500 RPM, that's not all that slow, though I have no idea what the full working speed should be.

The lack of clock and having the power enable switched all the time could explain some of the noise you mention, as the torque will be increasing and decreasing with every enable pulse, causing vibration.
 
Do you have any more information of frequencies used on printers/scanners? Where did you get this from?
Just from Google.



 
It looks to me as if CLK, LD and S/S go to testpoints 13, 14 & 15 respectively, though it's not easy to trace them.

From there they go to pins 1 - 3 in some order; it looks like CLK is pin 1, not sure about the others.

If you are using pin 3 to control it, then that's S/S, the motor enable pin.

If I'm right, it is only ever free-running without a clock signal going to pin 1 to synchronise it. That ties in with the noisy signal from LD, it's never able to lock up in sync with anything.

ps. 250 Hz (Facet speed) is 2500 RPM, that's not all that slow, though I have no idea what the full working speed should be.

The lack of clock and having the power enable switched all the time could explain some of the noise you mention, as the torque will be increasing and decreasing with every enable pulse, causing vibration.
This could really be the answer to all of it. It never occurred to me that you would need to start/stop the motor with a signal :facepalm:. We just always powered it on by giving power, which of course wouldn't be that way in a printer application. I am not 100% certain, but I think while testing we just tried giving V, GND and then tried CLK on the rest of the pins, finding pin 3 the only one to respond. I always wondered why pin 1 is marked with a black triangle or red paint in all three motors. It's because it's CLK

I'll definitely try this tonight.

Pin 1=CLK
2= ? Lock Signal ?
3=HIGH [5V]
4=GND
5=V
 

Latest threads

New Articles From Microcontroller Tips

Back
Top