Fun with Arduino 35 Turn Table Control with Stepper Motor

With the ingredients of previous two videos, find zero and rotate an exact amount of steps, we’re able to control a turn table that has multiple stop positions. We need to find out how many steps it takes, counting from the zero point, to reach every position. We’ll use a separate ‘Tuning’ sketch for this. We will use digital inputs to send the turn table to any position we like. These inputs can be manually activated, by say push buttons’ or they can be connected to a DCC accessory decoder for automated operation.

For the tuning we will use two push buttons, one to rotate CW, one to rotate CCW. The serial interface shows the number of steps to the current position. We can write down these numbers to later enter them into the Turntable sketch. The two sketches can be combined into one, storing the numbers into EEPROM. But we haven’t talked about EEPROM yet, the next video we will. For the sake of simplicity, right now the Tuning sketch is separate.

Read on below the video …

The code for the stepper motor Tuning to find the stop positions:

#define MOTOR_PIN_1      A1
#define MOTOR_PIN_2      A2
#define MOTOR_PIN_3      A3
#define MOTOR_PIN_4      A4
#define POTM_PIN         A5
#define RUN_CW_PIN        6 // LOW = run CW
#define RUN_CCW_PIN       7 // LOW = run CCW
#define ZERO_PIN          9 // Start the zero find routine
#define ZERO_FOUND_PIN   12 // Switch or sensor of zero position
#define ONOFF_LED_PIN     5 // Motor running LED
#define DIR_LED_PIN       4 // Motor direction LED
#define PULSES_PER_REV 2048 // Pulses per revolution of blue/metal toy motor

byte dir, rpm, rpm_old, stepnr, state;
unsigned long pos, pos_old, timeoflaststep;

void find_zero() {
  Serial.println("Finding zero sensor");
  dir = 1;
  while(digitalRead(ZERO_FOUND_PIN) == HIGH) {
    if ((micros() - timeoflaststep) > stepinterval()) {
    timeoflaststep = micros();
    do_one_step();
    }
  }
  motor_idle();
  pos = 0;
  pos_old = 0;
  Serial.println("Zero sensor found");
  Serial.println(pos);
}

unsigned long stepinterval() { // calculates step timing based on potmeter input
  rpm = map(analogRead(POTM_PIN), 0, 1024, 1, 13); // max 12 rpm, else pulses get lost
  if(rpm != rpm_old) {
    Serial.print("RPM: ");
    Serial.println(rpm);
    rpm_old = rpm;
  }
  return 60000000UL / PULSES_PER_REV / rpm;
}

void motor_idle() {
  digitalWrite(MOTOR_PIN_1,   LOW);
  digitalWrite(MOTOR_PIN_2,   LOW);
  digitalWrite(MOTOR_PIN_3,   LOW);
  digitalWrite(MOTOR_PIN_4,   LOW);
  digitalWrite(ONOFF_LED_PIN, LOW);
}

void rotate() {
  if ((micros() - timeoflaststep) > stepinterval()) {
    timeoflaststep = micros();
    do_one_step();
    if(dir == 1) pos--;
    else pos++;
  }
}

void do_one_step() { 
  if(dir == 0) stepnr--;
  else stepnr++;
  stepnr = stepnr%4;

  switch (stepnr) { // remembers in which of the 4 phases the motor is
    case 0:
      digitalWrite(MOTOR_PIN_1, HIGH);
      digitalWrite(MOTOR_PIN_2, LOW);
      digitalWrite(MOTOR_PIN_3, LOW);
      digitalWrite(MOTOR_PIN_4, LOW);
    break;
    case 1:
      digitalWrite(MOTOR_PIN_1, LOW);
      digitalWrite(MOTOR_PIN_2, HIGH);
      digitalWrite(MOTOR_PIN_3, LOW);
      digitalWrite(MOTOR_PIN_4, LOW);
    break;
    case 2:
      digitalWrite(MOTOR_PIN_1, LOW);
      digitalWrite(MOTOR_PIN_2, LOW);
      digitalWrite(MOTOR_PIN_3, HIGH);
      digitalWrite(MOTOR_PIN_4, LOW);
    break;
    case 3:
      digitalWrite(MOTOR_PIN_1, LOW);
      digitalWrite(MOTOR_PIN_2, LOW);
      digitalWrite(MOTOR_PIN_3, LOW);
      digitalWrite(MOTOR_PIN_4, HIGH);
    break;
  }
}

void setup() {
  pinMode(RUN_CW_PIN,    INPUT_PULLUP);
  pinMode(RUN_CCW_PIN,   INPUT_PULLUP);
  pinMode(ZERO_PIN,      INPUT_PULLUP);
  pinMode(ZERO_FOUND_PIN,INPUT_PULLUP);
  pinMode(MOTOR_PIN_1,   OUTPUT);
  pinMode(MOTOR_PIN_2,   OUTPUT);
  pinMode(MOTOR_PIN_3,   OUTPUT);
  pinMode(MOTOR_PIN_4,   OUTPUT);
  pinMode(ONOFF_LED_PIN, OUTPUT);
  Serial.begin(9600);
  Serial.println("Don't forget to find zero before tuning");
  Serial.println();
}

void loop() {
  motor_idle();
  stepinterval(); // read speed and show RPM on serial monitor

  if(digitalRead(ZERO_PIN) == 0) find_zero();
  
  while(!digitalRead(RUN_CW_PIN)) {
    dir = 1;
    rotate();
  }

  while(!digitalRead(RUN_CCW_PIN)) {
    dir = 0;
    rotate();
  }
  
  if(pos != pos_old) {
    Serial.println(pos);
    pos_old = pos;
  }
}

Lets use this code, find zero and then record 3 turn table positions. Let’s say the positions found are 0 (for the zero sensor), 100, 612 and 1124. These now are the numbers that we need to fill in for the stop positions in the code for our turntable:

unsigned long tt_position[4] = {0,100,612,1124};

The functions used are similar to the previous stepper motor videos. The loop() now takes care of reading the digital inputs that tell us the target turntable position. We then calculate the number of pulses and the direction to the new position, based on the position where we currently are.

#define MOTOR_PIN_1      A1
#define MOTOR_PIN_2      A2
#define MOTOR_PIN_3      A3
#define MOTOR_PIN_4      A4
#define POTM_PIN         A5
#define POS_1_PIN         9 // LOW = go to pos 1
#define POS_2_PIN         8 // LOW = go to pos 2
#define POS_3_PIN        12 // LOW = go to pos 3
#define ZERO_PIN          6 // Start zero find routine
#define ZERO_FOUND_PIN    7 // End switch to find zero position
#define ONOFF_LED_PIN     5 // Motor running LED
#define PULSES_PER_REV 2048 // Pulses per revolution of blue/metal toy motor

// Define number of positions, and steps from zero to each position
unsigned long tt_position[4] = {0,100,612,1124};

byte dir, current_pos, new_pos, rpm, rpm_old, stepnr, state;
unsigned long timeoflaststep;

void find_zero() {
  Serial.println("Finding zero sensor");
  dir = 0;
  while(digitalRead(ZERO_FOUND_PIN) == HIGH) {
    if ((micros() - timeoflaststep) > 60000000UL / PULSES_PER_REV) {
    timeoflaststep = micros();
    do_one_step();
    }
  }
  motor_idle();
  current_pos = 0;
  new_pos = 1; // move to pos 1 after finding zero
  Serial.println("Zero sensor found");
  Serial.println();
}

unsigned long stepinterval() { // calculates step timing based on potmeter input
  rpm = map(analogRead(POTM_PIN), 0, 1024, 1, 13); // max 12 rpm, else pulses get lost
  if(rpm != rpm_old) {
    Serial.print("RPM: ");
    Serial.println(rpm);
    rpm_old = rpm;
  }
  return 60000000UL / PULSES_PER_REV / rpm;
}

void rotate(unsigned long numsteps) {
  digitalWrite(ONOFF_LED_PIN, HIGH);
  Serial.print("To pos ");
  Serial.print(new_pos);
  Serial.print(", ");
  Serial.print(numsteps);
  Serial.print(" steps, dir = ");
  Serial.println(dir);
  while(numsteps > 0) {
    if ((micros() - timeoflaststep) > stepinterval()) {
      timeoflaststep = micros();
      do_one_step();
      numsteps--;
    }
  }
  motor_idle();
}

void motor_idle() {
  digitalWrite(MOTOR_PIN_1,   LOW);
  digitalWrite(MOTOR_PIN_2,   LOW);
  digitalWrite(MOTOR_PIN_3,   LOW);
  digitalWrite(MOTOR_PIN_4,   LOW);
  digitalWrite(ONOFF_LED_PIN, LOW);
}

void do_one_step() { 
  if(dir == 0) stepnr--;
  else stepnr++;
  stepnr = stepnr%4;

  switch (stepnr) { // remembers in which of the 4 phases the motor is
    case 0:
      digitalWrite(MOTOR_PIN_1, HIGH);
      digitalWrite(MOTOR_PIN_2, LOW);
      digitalWrite(MOTOR_PIN_3, LOW);
      digitalWrite(MOTOR_PIN_4, LOW);
    break;
    case 1:
      digitalWrite(MOTOR_PIN_1, LOW);
      digitalWrite(MOTOR_PIN_2, HIGH);
      digitalWrite(MOTOR_PIN_3, LOW);
      digitalWrite(MOTOR_PIN_4, LOW);
    break;
    case 2:
      digitalWrite(MOTOR_PIN_1, LOW);
      digitalWrite(MOTOR_PIN_2, LOW);
      digitalWrite(MOTOR_PIN_3, HIGH);
      digitalWrite(MOTOR_PIN_4, LOW);
    break;
    case 3:
      digitalWrite(MOTOR_PIN_1, LOW);
      digitalWrite(MOTOR_PIN_2, LOW);
      digitalWrite(MOTOR_PIN_3, LOW);
      digitalWrite(MOTOR_PIN_4, HIGH);
    break;
  }
}

void setup() {
  pinMode(POS_1_PIN,     INPUT_PULLUP);
  pinMode(POS_2_PIN,     INPUT_PULLUP);
  pinMode(POS_3_PIN,     INPUT_PULLUP);
  pinMode(ZERO_PIN,      INPUT_PULLUP);
  pinMode(ZERO_FOUND_PIN,INPUT_PULLUP);
  pinMode(MOTOR_PIN_1,   OUTPUT);
  pinMode(MOTOR_PIN_2,   OUTPUT);
  pinMode(MOTOR_PIN_3,   OUTPUT);
  pinMode(MOTOR_PIN_4,   OUTPUT);
  pinMode(ONOFF_LED_PIN, OUTPUT);
  Serial.begin(9600);
  Serial.println("Don't forget to find zero before operating");
  Serial.println();
}

void loop() {

  stepinterval(); // read speed and show RPM on serial monitor

  if(digitalRead(ZERO_PIN) == 0) find_zero();
  if(digitalRead(POS_1_PIN) == 0) new_pos = 1;
  if(digitalRead(POS_2_PIN) == 0) new_pos = 2;  
  if(digitalRead(POS_3_PIN) == 0) new_pos = 3;

  if(new_pos != current_pos) {
    if(new_pos > current_pos) {
      dir = 1;
      rotate(tt_position[new_pos] - tt_position[current_pos]);
    }
    else {
      dir = 0;
      rotate(tt_position[current_pos] - tt_position[new_pos]);
    }
    current_pos = new_pos;
  }
}

OK … time to test. Yes, this works fine. It’s only 3 positions in this case … but it could as well more. At some point we run out of digital inputs … what to do then? We could use an Arduino Mega, which has a lot more inputs available. Alternatively I2C could be used … a two wire communication protocol which will be the subject of a future video.

Next video we’ll have a look at using the built in EEPROM to store the latest turn table position. That way we do not need to do a zero find routine every time we start up … at startup we can read the memory and we know where we are. After every move we write the current position to memory.

— 0 —

16 thoughts on “Fun with Arduino 35 Turn Table Control with Stepper Motor

  1. Dear Sir,,
    My name is JACQUES and I am from MAURITIUS. I have this JOUEF turntable with 6 garage for 6 LOCO. The table turns with a 12V DC motor with a reduction gear. I want to know is I can use the above softwear to make my table work. I have ordered an ARDUINO but I have not received it yet or I must made some mods with the softwear.I can sent you pictures if needed.
    Awaiting your comments
    Red
    J PITOT

    Like

      • Hi RudyB
        Thanks for your reply. I want to send you one picture of my turntable, so that you can see the setup.
        Therefore can you give me your e mail address.Do you know how to do the programing of ARDUINO?? by any chance????
        Awating your reply soon
        Jacques

        Like

      • Hello Rudy,
        Can you sent me the schematic of how to connect the stepper motor ( 6 wire motor) to the arduino, do I need a driver for it??? if yes, which one I must order on e bay.As I mention last time I want to use a 6 position rotary switch.to turn the bridge.
        Red
        Jacques

        Like

    • Yes, you’ll neer a driver to power the motor. I can’t advise what driver without knowing what motor you have. You best Google for that. Drivers can be acquired via Aliexpress, that’s where I got mine. The Easydriver will handle most motors as long as they don’t ask more current than it van deliver. Although you said you have a 6 wire motor … most drivers are for 4 wire motors … you’ll just have to Google.

      Like

      • Hello,
        Thanks for your reply. I have a stepper motor from SANYO DANKI, 5.3 ohm and 1.8 deg per step. I can sent you a picture of the motor, please sent me you e mail address. Further more can you write the softwear for me?
        Awaiting your comments,
        Red
        Jacques

        Like

    • Jacques, I don’t know that motor, you’ll need to Google which driver you need for that motor. The software … all you have to do is copy and paste it from the blog and fill in the numbers you need for your application.

      Like

  2. Have a nice day, great plan , Thanks. To position 0 would need an IR sensor. Can be added to sketch ? If so, where is the entry point. Please help me if you can. My English speaking is bad , excuse me. Regards, Imre

    Like

  3. Hello Rudy

    Amazing all videos, but please, help me with the wire connections, inputs push buttons to GND or V+ connect, potentiometer, and I think what is some rotary Decoder the right silver controller, thanks for the diagram panel controller, saulrmtz@hotmail.com

    Like

    • Yes, I always connect switches and push buttons to GND. Potentiometer goes to one of the analog inputs A0-A5. Rotary encoder signals go to any digital input. In one of the later posts there is an electrical schematic of the switch panels used in the demos.

      Like

  4. Hi Rudy . I have folllowed all your posts on stepper motor control but am struggling to get it to work . The Ali express site take you to a 28BYJ-48 which I have . But the spec sheet for this say it drives 1,3,2,4 but your code seems to drive it 1,2,3,4 any help appreciated as to what I am doing wrong would be great. Thanks

    Like

    • Hard to tell from a distance. The only tip I can give is to change the code such that the output sequence is 1,3,2,4 and see if it works then?

      Like

Leave a comment