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:
very interesting. as per calculation above, 50000 RPM would make up for 833 Hz.
If the above solution works, we will gradually go higher. The datasheet of the IC also indicates that the motor will cut out if it goes above a set base frequency, so i guess it should be safe.
 
I ran some tests on all motors.
giving pin4 GND and pin5 24V
Pin 1 = 23V
Pin 2 = 5V
Pin 3= 24V
then I applied CLK to pin 1 (measured the square wave from the socked pin on pin1, looking ok)
nothing happens as expected.

put pin 3 to GND
this had the same result on all motors with slightly different effects.

the first motor started to spin but the the power supply cut out. I had it set to 0.9A. Raised it to 1A. Still cut out.
But: when it started spinning I could already tell it had a smoother ring to it.

The second motor doesnt cut out the power supply, but it starts and stops kind of jittery. Same for the third motor.
I made this video: https://photos.app.goo.gl/CxMgmhaMySkPsBJN8

I also tried pin2 to 5V or GND and that didnt do anything.

In the end I tried to replicate the power cut issue on motor 1 and I couldn't replicate it. It now also stutters.
 
OK, it may be in needs either a higher or lower clock frequency?

Or, at full power the motors just need more than the PSU can give?
 
OK, it may be in needs either a higher or lower clock frequency?

Or, at full power the motors just need more than the PSU can give?
I can give more amps. I think up to 5, or 10. I dont remember. Will have to check. But when we did our initial tests with the motors, my colleague didnt want to go above 1A if we didnt have to. Can I theoretically blow it?
I didnt even think about the CLK speed. Will try that too.
 
How did you look at the feedback signal?

It sounds like you were using a voltmeter to see a ~dc voltage with some noise on it. It is probably either a pulse string or even a sine wave, that may be riding on top of a DC voltage.

To see the true nature of the signal, you'll need an oscilloscope.
 
I use an oscilloscope. I just went through my photo library and found these:
https://photos.app.goo.gl/RB6wDteort4ioDf89
unfortunately I didnt label the photos, so I am not 100% sure which one was that signal.
I will try to think of making another video when I try again tonight.
 
A bit frustrating. I tried it again and was kind of positive this should work as with all the above comments this is what makes the most sense. Unfortunately it keeps fizzing out when I pull pin3 to LOW. I made this video:
video
I also tried it on the other unused motor. It's a different chip and I think pin 2 is CLK on that one as pin1 & 3 are 5V. pulling pin3 LOW has the exact same effect as on the motor in the video.
I also tried pin2 on the motor in the video and it seems to give or do nothing. Might be the lock signal once its spinning?
 
Try about 130Hz; it may be that 200 - 250 is just to high for it to run at.

I found some outline specs for a Mitsumi version; it says 50,000 but no mention of "RPM" - I think that may be scans per minute, so 6x motor RPM.

If that's the case, the top RPM sync would be around 138 Hz.
For a 40,000 one it would be around 110 Hz.
 
forgot to mention that i tried a variety of frequencies from 50Hz, 100, 160 and 400 too. It reacted all the same
 
Quick update. I could attend to this for a while, but tried it again today.
I got it working on the one motor that we have the datasheet.
pin1: CLK
pin2: ?
pin3: SS -> pull low
pin4: GND
pin5: V
For CLK I needed to apply 2kHz for it to work. It runs smooth and steady. I dont quite understand why the high frequency is required. I can't possibly spin this fast. So it must be some sort of control signal and not the actual spin frequency?

I havent tried so synchronise it with the laser yet as I am not sure a what actual speed the motor now spins. But I expect the wobble to be gone now.

Thank you everyone @rjenkinsgb, @shortbus= for helpinmg with this.
 
I havent tried so synchronise it with the laser yet as I am not sure a what actual speed the motor now spins.

Just a dumb thought. Would the laser need to be synchronized? I always thought that was the reason for the polygon rotating mirrors, to get rid of the synchronization. Flashing a laser fast seems like it would be harder than pointing a steady beam at a rotating mirror array, to get a flashing signal.
 
Good question. For our project we want to sample a photodiode with the laser scanning the full angle of a facet of the mirror and then detect an object within that scan field. one step on the way to this was to try to pulse the laser to a specific spot in the target area. That pulse would need to be motor_frequency x 6. Ultimately this test is what showed us there is a problem with the spin consistency.
But you are right. We might not need to do this in the final setup. My colleague is the one who comes up with the test parameters. I think next is to setup the PD and see what we get back in terms of reflected light from the laser
 
The "FGS" pin on the IC is the sync signal out.

In the original laser printer use, the print controller must know when each scan starts to synchronise the dot pattern timing for that scan line, so it should be there somewhere - possibly connector pin 2??
 
Cookies are required to use this site. You must accept them to continue using the site. Learn more…