BO Motor With Encoder Gives Precise Movement

To precisely control the BO motor or to make any low cost project using PID we can consider this types of encoder integration with motors.

 

BO Motor With Encoder Gives Precise Movement

 

 

Things used in this project

HARDWARE LIST
1 DFRobot BO motor
1 Arduino Nano R3

Software apps and online services

- Arduino IDE

- JLCPCB EasyEDA

 

Hand tools and fabrication machines

- Soldering iron (generic)
- Solder Wire, Lead Free

Story

Geared Dc motors are used in a lot of hobby projects like in making some kind of robot car and moving robotics. But for precise movement it is very important to use special kind of motors. For example for a balancing robot, we have to use stepper motors (proper stepping of wheel). Because in balancing the movement needed is very precise and normal motor can not complete the task. But there is one solution to these problems where we do not want to use stepper motors but want precise movement then encoder can be used with BO motors.

 

 

This encoder just record the rotation speed and direction and convert them into a pulses which can be paired with a microcontroller and driver to precisely change the voltage levels according to the desired pulses needed. These pulse control finally decide the movement speed of motor and using BO motors is very cost effective solution.

 

How magnetic encoder works:

An electronic magnetic rotary encoder utilizes magnetic fields to measure the rotation of an object. It consists of a magnetized rotor and a stationary sensor. As the rotor rotates, the sensor detects changes in the magnetic field and converts them into electrical signals.

 

 

These signals are processed to determine the rotational position, speed, and direction of the object. The sensor can be based on various technologies, such as Hall effect sensors or magneto resistive sensors, which detect the magnetic field variations. By analyzing these signals, the encoder provides accurate rotational data, making it useful for applications such as motor control, robotics, and industrial automation.

 

 

A simple encoder consists of 4 wires (2 for power and 1 for interrupt and other 1 for rotation direction). Microcontroller never checks for any motion recorded by encoder, but encoder by itself by generating an interrupt tells the microcontroller and the step is recorded.

 

 

Encoder A (labelled C1, PinA) of the motor connects to pin 2 of the Arduino. Pin 2 of the Arduino will record every time there is a rising digital signal from Encoder A.

Encoder B (labelled C2, PinB) of the motor connects to pin 3 of the Arduino. The signal that is read off pin 3 on the Arduino will determine if the motor is moving forward or in reverse.

Gear motor and Encoder Specs:

 

 

Here I have a BO motor from DF robot, It is a geared motor with 120:1 gear ratio (1 output shaft movement when motor rotates 120 times). It has an integrated quadrature encoder that provides a resolution of 8 pulse single per round giving a maximum output of 960 within one round.

 

 

· Gear ratio: 120:1

· No-load speed @ 6V: 160 rpm

· No-load speed @ 3V: 60 rpm

· No-load current @ 6V: 0.17A

· No-load current @ 3V: 0.14A

· Max Stall current: 2.8A

· Max Stall torque: 0.8kgf.cm

· Rated torque: 0.2kgf.cm

· Encoder operating voltage: 4.5 to 7.5V

 

 

Encoder value calculation: Encoder pulse per revolution = 8 One rotation of output shaft = Encoder pulse per revolution X Gear Ratio So pulse per one rotation = 8 X 120 = 960 Pulse per revolution.

 

Code for Pulse Calculation:

CODE
// Encoder output to Arduino Interrupt pin. Tracks the pulse count.
#define encoder0PinA 2
 
// Keep track of the number of right wheel pulses
volatile long right_wheel_pulse_count = 0;
 
void setup() {
 
  // Open the serial port at 9600 bps
  Serial.begin(9600); 
 
  // Set pin states of the encoder
  pinMode(encoder0PinA , INPUT_PULLUP);
 
  // Every time the pin goes high, this is a pulse
  attachInterrupt(digitalPinToInterrupt(encoder0PinA), right_wheel_pulse, RISING);
  // 2Nd method to use Interuppt pin (Either use PIN 0 or use funtion digitalPinToInterrupt
}
 
void loop() {
  
    Serial.print(" Pulses: ");
    Serial.println(right_wheel_pulse_count);  
}
 
// Increment the number of pulses by 1
void right_wheel_pulse() {
  right_wheel_pulse_count++;
}

Code for Velocity of motor:

This code reset the encoder counter after every rotation which gives the precise number of turns done by motor per unit time.

CODE
//The sample code for driving one way motor encoder
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_RESET 1
Adafruit_SSD1306 display(128, 64, &Wire, OLED_RESET);
const byte encoder0pinA = 2; //A pin -> the interrupt pin 0
const byte encoder0pinB = 3; //B pin -> the digital pin 3
byte encoder0PinALast;       //Store the previous state of pin

int duration;     //the number of the pulses
boolean Direction;//the rotation direction


void setup()
{
  Serial.begin(9600);//Initialize the serial port
  EncoderInit();     //Initialize function for encoder
  Wire.begin();
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
}

void loop()
{
  Serial.print("Pulse:");
  Serial.println(duration);

  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.print("Pulse:");
  display.display();

  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(50,30);
  display.print(duration/2);
  display.display();
  duration=0;
  delay(300);
  
}

void EncoderInit()
{
  Direction = true;   //default -> Forward
  pinMode(encoder0pinB,INPUT);
  attachInterrupt(0, wheelSpeed, CHANGE); // digitalPinToInterrupt(interruptPin) instead of 0
// syntax of interrupt will be = interrupt pin, function to be executed, Condition of Function HIGH, LOW, CHANGE, RISING AND FALLING
}

void wheelSpeed()
{
  int Nstate = digitalRead(encoder0pinA);
  if((encoder0PinALast == LOW) && Nstate==HIGH)
  {
    int val = digitalRead(encoder0pinB);
    if(val == LOW && Direction)
    {
      Direction = false; //Reverse
    }
    else if(val == HIGH && !Direction)
    {
      Direction = true;  //Forward
    }
  }
  encoder0PinALast = Nstate;

  if(!Direction)  duration++;
  else  duration--;
}

Circuit:

 

 

I found this compatible circuit for the encoder design which itself defines the practical approach. You can see two hall effect sensor for measuring the change in magnetic field according to the movement. The output is sensor is connected to the interrupt pin of the microcontroller. Resistors are used to match the transistor levels and to protect from overcurrent. Download all the codes and schematics from here.

 

 

Motor and encoder both can be supplied from same source but keep the maximum voltage readings in mind. Motor can be used without encoder also, just plug the motor wires into power supply and it work as normal one.

My Arduino:

Here is my own designed Arduino Board, I recently updated one more version. It is fully compatible DIY board. You may use my Gerber files from here to order same board or Upload your own designs directly to JLCPCB and get 5 PCS of 2-layer PCB in just $2.

 

 

JLCPCB is the China based PCB manufacturer deals in PCB, PCBA, Stencil, 3D-printing, SMT assembly and Metal CNC. You can assemble the PCB using simple soldering machine by placing all the components or may order Assembled PCB with all components from JLCPCB. Most of the components are available online if you are going to assemble on your own, please check the BOM file given in the download folder.

Testing:

 

 

I upload the velocity code and get the number of pulses as a function of speed of motor. The code is written in a manner it will auto reset the encoder value after every 0.3 second. Now keep one thing in mind that operating voltage decide the speed of motor and finally the pulses. I operated my Dc motor on 5volts and got the results displayed in image.

 

https://hackster.imgix.net/uploads/attachments/1611947/my_video_5B77xzqM2I.gif?auto=compress&gifq=35&w=740&h=555&fit=max&fm=mp4

 

Further from this encoder readings a PID controller or a motor controller can be paired. Which can be used to control the precise movement of motor. This will also solve a problem in robot cars, if we fixed the value of encoder pulses to a range both the motors rotate with same speed providing better control to robotics projects and cars.

Schematics

Reference Schematics of encoder

 

Velocity code

CODE
//The sample code for driving one way motor encoder
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_RESET 1
Adafruit_SSD1306 display(128, 64, &Wire, OLED_RESET);
const byte encoder0pinA = 2; //A pin -> the interrupt pin 0
const byte encoder0pinB = 3; //B pin -> the digital pin 3
byte encoder0PinALast;       //Store the previous state of pin

int duration;     //the number of the pulses
boolean Direction;//the rotation direction


void setup()
{
  Serial.begin(9600);//Initialize the serial port
  EncoderInit();     //Initialize function for encoder
  Wire.begin();
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
}

void loop()
{
  Serial.print("Pulse:");
  Serial.println(duration);
 
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.print("Pulse:");
  display.display();

  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(50,30);
  display.print(duration/2);
  display.display();
  duration=0;
  delay(300);
  
}

void EncoderInit()
{
  Direction = true;   //default -> Forward
  pinMode(encoder0pinB,INPUT);
  attachInterrupt(0, wheelSpeed, CHANGE); // digitalPinToInterrupt(interruptPin) instead of 0
// syntax of interrupt will be = interrupt pin, function to be executed, Condition of Function HIGH, LOW, CHNAGE, RISING AND FALLING
}

void wheelSpeed()
{
  int Nstate = digitalRead(encoder0pinA);
  if((encoder0PinALast == LOW) && Nstate==HIGH)
  {
    int val = digitalRead(encoder0pinB);
    if(val == LOW && Direction)
    {
      Direction = false; //Reverse
    }
    else if(val == HIGH && !Direction)
    {
      Direction = true;  //Forward
    }
  }
  encoder0PinALast = Nstate;

  if(!Direction)  duration++;
  else  duration--;
}
License
All Rights
Reserved
licensBg
0