Gear motor calibration without PWM

I am working on a gear motor and I have some issue while controlling it. I can’t use the PWM in the project because of the PCB Design. I have some mechanical tolerance, to adjust the mechanical tolerance I have to come up with something that can calibrate the motor after every rotation. If the calibration is not done for the rotation, the inaccuracy degree increase for every single rotation.

What can I get better accuracy for the gear motor?

I have attached the code I am currently using.

[
//Define pin setup
#define motor_in1 7
#define motor_in2 8
#define motor_enA 9
#define sensorPin 2

volatile unsigned int half_revolutions = 0;
// const
unsigned int revolutions_per_pos;
const int REED_PIN = 2; // Pin connected to reed switch
const int LED_PIN = 13; // LED pin - active-high

int pos = 0;

void magnet_detect() {
  half_revolutions++;
}

void setup() {
  // Set pin mode
  pinMode(motor_enA, OUTPUT);
  pinMode(motor_in1, OUTPUT);
  pinMode(motor_in2, OUTPUT);
  
    Serial.begin(115200);

  // Since the other end of the reed switch is connected to ground, we need
  // to pull-up the reed switch pin internally.
  pinMode(REED_PIN, INPUT_PULLUP);
  pinMode(LED_PIN, OUTPUT);
}





void loop() {

  // Hallsensor connected to the interrupt pin (Pin 2 on Arduino Uno)
  attachInterrupt(digitalPinToInterrupt(sensorPin), magnet_detect, RISING);// attachInterrupt(digitalPinToInterrupt(pin), ISR, mode);

  int proximity = digitalRead(REED_PIN); // Read the state of the switch
  if (proximity == LOW) // If the pin reads low, the switch is closed.
  {
    Serial.println("Switch closed");
    digitalWrite(LED_PIN, HIGH); // Turn the LED on
  }
  else
  {
    digitalWrite(LED_PIN, LOW); // Turn the LED off
  }

  // Run full cycle to each position and back to 07

  // Position 1
  revolutions_per_pos = 706;
  move_amount(3);
  pos = 1;
  Serial.println(1);
  delay(2000);

  // Position 0 to 1
  revolutions_per_pos = 706;
  move_amount(-3);
  pos = 1;
  Serial.println(0);
  delay(2000);


  // Calibtration



  revolutions_per_pos = 20;
  move_amount(-2);
  pos = 1;
  Serial.println(2);
  delay(2000);


  revolutions_per_pos = 15;
  move_amount(2);
  pos = 1;
  Serial.println(0);
  delay(2000);

  /*
    revolutions_per_pos = 706u;
    move_amount(3);
    pos = 1;
    Serial.println(3);
    delay(2000);
    //revolutions_per_pos = 706u;
    move_amount(-3);
    pos = 1;
    Serial.println(0);
    delay(2000);
    //revolutions_per_pos = 706u;
    move_amount(1);
    pos = 1;
    Serial.println(4);
    delay(2000);
    //revolutions_per_pos = 706u;
    move_amount(-1);
    pos = 1;
    Serial.println(0);
    delay(2000);
    //revolutions_per_pos = 706u;
    move_amount(2);
    pos = 1;
    Serial.println(5);
    delay(2000);
    //revolutions_per_pos = 706u;
    move_amount(-2);
    pos = 1;
    Serial.println(0);
    delay(2000);
    //revolutions_per_pos = 706u;
    move_amount(-3);
    pos = 1;
    Serial.println(6);
    delay(2000);
    //revolutions_per_pos = 706u;
    move_amount(3);
    pos = 1;
    Serial.println(0);
    delay(2000);

  */
}


void move_amount(int no_pos)
{
  unsigned int hr_local_copy;
  unsigned int count;
  unsigned int motor_speed;

  // Set rotation direction
  if (no_pos < 0) {
    digitalWrite(motor_in1, HIGH);
    digitalWrite(motor_in2, LOW);
    no_pos = -no_pos;
    motor_speed = 255;
  } else {
    // Set rotation direction
    digitalWrite(motor_in1, LOW);
    digitalWrite(motor_in2, HIGH);
    motor_speed = 255;
  }

  count = no_pos * 2 * revolutions_per_pos;

  noInterrupts();
  half_revolutions = 0;
  hr_local_copy = 0;
  interrupts();

  // start motor
  analogWrite(motor_enA, motor_speed);

  while (hr_local_copy < count) {
    Serial.println(hr_local_copy);
    noInterrupts();
    hr_local_copy = half_revolutions;
    interrupts();
  }

  // stop motor
  analogWrite(motor_enA, 0);

  noInterrupts();
  hr_local_copy = half_revolutions;
  Serial.println(hr_local_copy);
  interrupts();
}



/code]

You have a reed switch or a hall switch detecting each rotation of the gearbox output shaft? (If its a reed switch you'll need to debounce it.)

Are you trying to do position control or just count rotations?

Change this:

  noInterrupts();
  hr_local_copy = half_revolutions;
  Serial.println(hr_local_copy);
  interrupts();

to this:

  noInterrupts();
  hr_local_copy = half_revolutions;
  interrupts();
  Serial.println(hr_local_copy);

The critical section is well named, its critical not to spend any time in it! Serial.println can busy-wait for UART interrupts so it must never be used in a critical section or ISR.

The motor is using a hall sensor but I have attached the reed switch to the motor, The reed switch is to be used for the calibration, I can't use the hall sensor and reed switch for the rotation.

I will change the interrupt and place it before the serial print.

What will be the methods used for the calibration while updating the current code?

Awais-1: I am working on a gear motor and I have some issue while controlling it. I can't use the PWM in the project because of the PCB Design.

Why can't you use PWM, whats the PCB design? What is the application? Do you want speed accuracy or position accuracy? Tom... :)

PCB doesn’t have PWM driver.
I want position accuracy

Updated the code for the calibration but somehow it’s not working while returning back

//Define pin setup
#define motor_in1 7
#define motor_in2 8
#define motor_enA 9
#define sensorPin 2
#define reedPin 3
#define ledPin 13

int half_revolutions = 0;
int revolutions_per_pos;
int pos = 0;

void setup() {
// Set pin mode
pinMode(motor_enA, OUTPUT);
pinMode(motor_in1, OUTPUT);
pinMode(motor_in2, OUTPUT);
pinMode(reedPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);

Serial.begin(115200);
// Since the other end of the reed switch is connected to ground, we need
// to pull-up the reed switch pin internally.
}
void loop() {
// Hallsensor connected to the interrupt pin (Pin 2 on Arduino Uno)
attachInterrupt(digitalPinToInterrupt(sensorPin), magnet_detect, RISING);
// Run full cycle to each position and back to 07
// Position 1
revolutions_per_pos = 706;
move_amount(3);
delay (2000);
return_to_zero(true);
}

void reed_detect()
{
analogWrite(motor_enA, 0);
}

void magnet_detect() {
half_revolutions++;
}

void move_amount(int no_pos)
{
unsigned int hr_local_copy;
unsigned int count;
unsigned int motor_speed;
// Set rotation direction
if (no_pos < 0) {
  digitalWrite(motor_in1, HIGH);
  digitalWrite(motor_in2, LOW);
  no_pos = -no_pos;
  motor_speed = 255;
} else {
  // Set rotation direction
  digitalWrite(motor_in1, LOW);
  digitalWrite(motor_in2, HIGH);
  motor_speed = 255;
}
count = no_pos * 2 * revolutions_per_pos;
noInterrupts();
half_revolutions = 0;
hr_local_copy = 0;
interrupts();
// start motor
analogWrite(motor_enA, motor_speed);
while (hr_local_copy < count) {
 noInterrupts();
  Serial.println(hr_local_copy);
  
  hr_local_copy = half_revolutions;
  interrupts();
}
// stop motor
analogWrite(motor_enA, 0);
noInterrupts();
hr_local_copy = half_revolutions;
interrupts();
Serial.println(hr_local_copy);

}

void return_to_zero(boolean clockwise)
{
if(clockwise){
  digitalWrite(motor_in1, HIGH);
  digitalWrite(motor_in2, LOW);
}
else {
  digitalWrite(motor_in1, LOW);
  digitalWrite(motor_in2, HIGH);
}
int motor_speed = 255;

analogWrite(motor_enA, motor_speed);
Serial.println("Turning back...");
boolean detected = false;

while(!detected){
  half_revolutions = 0;
  while(digitalRead(reedPin) == HIGH){// low instead of high 
   interrupts();
    Serial.println("Reed Detected");
    detected = false;
  }
}

Serial.println("Half revolutions: " + half_revolutions);
int return_half_revolutions = half_revolutions / 2;

analogWrite(motor_enA, 0);
if(clockwise){
  digitalWrite(motor_in1, LOW);
  digitalWrite(motor_in2, HIGH);
}
else {
  digitalWrite(motor_in1, HIGH);
  digitalWrite(motor_in2, LOW);
}
analogWrite(motor_enA, motor_speed);

while(return_half_revolutions < half_revolutions){}

analogWrite(motor_enA, 0);
}
[code]

Hi,

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Why cant you PWM the the motor driver? What Arduino controller are you using?

How do you aim to get position accuracy?

Thanks.. Tom... :)

Awais-1: The motor is using a hall sensor but I have attached the reed switch to the motor, The reed switch is to be used for the calibration, I can't use the hall sensor and reed switch for the rotation.

So you'll need an encoder?