Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 3 |
I ordered a motor with a hollow shaft because I wanted to use it with a slipring so I could drive a stepper motor, similar to that used in a commercial DSLR camera gimbal.
The motor turned out to be a BLDC motor with a 12N14P configuration. What did that even mean? Couldn't find any suitable Arduino code, so had to figure it out myself.
(Refer http://www.aerodesign.de/peter/2001/LRK350/index_eng.html and http://www.aerodesign.de/peter/2001/LRK350/Paper_from%20_Wroclaw.html) for how a BLDC motor works.
With regards to 12N14P: P denotes number of stator magnets, N denotes number of rotor poles. See https://en.wikipedia.org/wiki/Outrunner.
BLDC speed is controlled by a pot connected to A0.
The three wires from the BLDC can be connected to any of the four L298N output screw terminals labelled MOTOR A and MOTOR B. Unfortunately the LEDs on Jaycar's XC-4492 L298N stepper Motor Controller Module are reversed, so you'll need to test which screw terminal matches which LED.
The pot controls the speed of the BLDC motor by varying the length of the pulse to each coil; The higher the resistance of the pot the more time must pass before the next coil is energised.
The three wires of the BLDC can be held high or low. In binary this would be eight states:
000
001
010
011
100
101
110
111
In the first state (000) none of the coils are energised, so the BLDC is off.
In the last state (111) all of the coils are energised, which would lock the BLDC on with a wasteful drain of power. This state is not used.
The sequence of energising each coil was found through a process of elimination. The following sequence was found to work:
010 2
011 3
001 1
101 5
100 4
110 6
Not intuitive, but it works.
BLDC Brushless DC motor code V2
ArduinoV1 code pulsed once and then waited for interval before sending next pulse, whereas this improved code keeps pulsing the same phase until the interval is past. Also, input from pot connected to A5, now varies BLDC motor speed. Removed 'step' variable by reversing order in which time interval is tested. Serial.print is commented out to improve smoothness of motion.
/*
DC Brushless Motor (BLDC)
Appears to be internally wired as though 3-phase stepper motor
Tested with funtobuyonline GBM6324-180T
Parts required:
- Arduino (If using Chinese Nano then install CH340 driver and use ATmega328P (Old Bootloader)
- L298N Stepper Motor Controller Module (Jaycar XC-4492)(Nb. LEDs L3 and L3 are reversed with respect to Motor B output pins)
- 2 or 3 cell LiPO or NiMH battery
- Switch in series with battery
Michael Barr January 2019
*/
// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0;
unsigned long difference =0;
int potA5;
// Define pins numbers
const int tri1 = 3;
const int tri2 = 4;
const int tri3 = 6;
void setup() {
// initialize the serial port:
Serial.begin(9600);
// declare MOTOR A and MOTOR B pins as outputs
pinMode(tri1, OUTPUT);
pinMode(tri2, OUTPUT);
pinMode(tri3, OUTPUT);
}
void loop() {
potA5= analogRead(A5); //Read input from analog pin potA5 and store in potA5
potA5= map(potA5, 0, 1023,30,100); //map potA5 to minimum and maximum
// Serial.print("potA5:");
// Serial.print(potA5);
unsigned long currentMillis = millis();
difference = currentMillis - previousMillis;
// Serial.print(" difference = ");
// Serial.print(difference);
if (difference >= potA5 * 6) {
previousMillis = currentMillis;
// Serial.println(" 6");
}
else if (difference >= potA5 * 5) {
digitalWrite(tri1, HIGH);
digitalWrite(tri2, HIGH);
digitalWrite(tri3, LOW);
// Serial.println(" 5");
}
else if (difference >= potA5 * 4) {
digitalWrite(tri1, HIGH);
digitalWrite(tri2, LOW);
digitalWrite(tri3, LOW);
// Serial.println(" 4");
}
else if (difference >= potA5 * 3) {
digitalWrite(tri1, HIGH);
digitalWrite(tri2, LOW);
digitalWrite(tri3, HIGH);
// Serial.println(" 3");
}
else if (difference >= potA5 * 2) {
digitalWrite(tri1, LOW);
digitalWrite(tri2, LOW);
digitalWrite(tri3, HIGH);
// Serial.println(" 2");
}
else if (difference >= potA5) {
digitalWrite(tri1, LOW);
digitalWrite(tri2, HIGH);
digitalWrite(tri3, HIGH);
// Serial.println(" 1");
}
else {
digitalWrite(tri1, LOW);
digitalWrite(tri2, HIGH);
digitalWrite(tri3, LOW);
// Serial.println(" 0");
}
}
BLDC Brushless DC motor code V2 + stepper motor code
ArduinoA Protoneer Arduino CNC Shield V3 with Pololu A4988 Stepper Motor Driver Carrier fitted, to drive the stepper motor.
An L298N Stepper Motor Controller Module is used to drive BLDC.
/*
Derived from non-blocking mode Stepper Driver example by Laurentiu Badea
Parts required:
- Arduino Uno
- L298N Stepper Motor Controller Module, to drive BLDC. (Jaycar XC-4492)(Nb. LEDs L3 and L3 are reversed with respect to Motor B output pins)
- Protoneer Arduino CNC Shield V3 with Pololu A4988 Stepper Motor Driver Carrier fitted, to drive stepper motor.
- DC Brushless Motor (BLDC) (funtobuyonline GBM6324-180T appears to be internally wired as though 3-phase stepper motor).
(Refer http://www.aerodesign.de/peter/2001/LRK350/index_eng.html and http://www.aerodesign.de/peter/2001/LRK350/Paper_from%20_Wroclaw.html)
- 4 wire stepper motor (eg 12V NEMA 17).
- 2 or 3 cell LiPO or NiMH battery.
- Switch in series with battery.
- Pot delay on A5 because A0 is reserved by CNC Shield. Used for speed control of BLDC motor
- Pot delay on A4 connected to pot mounted on stepper motor to provide position feedback.
When the brush of the pot wipes past the extremes of the variable resistor the voltage will float, so values selected for this pot must be much higher than 0.
- Pot delay on A3 controls speed of rotation of the stepper motor
Michael Barr in January 2019
*/
#include <Arduino.h> // Required to drive stepper motor
// Motor steps per revolution. Most steppers are 200 steps or 1.8 degrees/step
#define MOTOR_STEPS 200
#define RPM 10
#define MICROSTEPS 1 // Microstepping mode. If you hardwired it to save pins, set to the same value here.
#define DIR 5
#define STEP 2
#define ENABLE 8 // optional (just delete ENABLE from everywhere if not used)
// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillisA3 = 0; // will store last time stepper motor was at extreme end of its arc
unsigned long previousMillisBLDC0 = 0; // stores when BLDC moved to phase 0
int potA5 = 50;
unsigned long difference =0;
const int highPotA5 = 100;
// Defines pins numbers. Wire BLDC to pins on CNC shield which are not used because not using Y and Z motors
const int BLDC1 = 3; // pin labelled Y STEP
const int BLDC2 = 4; // pin labelled Y DIR
const int BLDC3 = 6; // pin labelled Z STEP
int potA3; // Defines variables
int potA4,directionLinkage2; // Defines variables
/*
* Choose one of the sections below that match your board
#include "DRV8834.h"
#define M0 10
#define M1 11
DRV8834 stepper(MOTOR_STEPS, DIR, STEP, ENABLE, M0, M1);
*/
#include "A4988.h"
#define MS1 10
#define MS2 11
#define MS3 12
A4988 stepper(MOTOR_STEPS, DIR, STEP, ENABLE, MS1, MS2, MS3);
// #include "DRV8825.h"
// #define MODE0 10
// #define MODE1 11
// #define MODE2 12
// DRV8825 stepper(MOTOR_STEPS, DIR, STEP, ENABLE, MODE0, MODE1, MODE2);
// #include "DRV8880.h"
// #define M0 10
// #define M1 11
// #define TRQ0 6
// #define TRQ1 7
// DRV8880 stepper(MOTORS_STEPS, DIR, STEP, ENABLE, M0, M1, TRQ0, TRQ1);
void setup() {
Serial.begin(115200);
// declare the BLDC pins as outputs
pinMode(BLDC1, OUTPUT);
pinMode(BLDC2, OUTPUT);
pinMode(BLDC3, OUTPUT);
stepper.begin(RPM, MICROSTEPS);
stepper.enable();
// set current level (for DRV8880 only). Valid percent values are 25, 50, 75 or 100.
// stepper.setCurrent(100);
// Serial.println("START");
}
void loop() {
rotateStepper(); // Rotate 4 wire stepper motor
rotateBLDC(); // Rotate 3 wire BLDC motor
// Serial.println();
}
// Function for rotating stepper motor
void rotateStepper(){
// Linkage 2 stepper motor speed
int potA3 = analogRead(A3); // Reads the potentiometer
potA3 = map(potA3,0,1023,5,360); // Converts the read values of the potentiometer from 0 to 1023 into an angle (0 to 360 degrees )
unsigned long currentMillisA3 = millis(); // Get current time
// Rotate stepper motor until pot is rotated 70 degrees and then rotate back to 0 degrees
int potA4 = analogRead(A4); // Reads the potentiometer
potA4 = map(potA4,0,1023,0,360); // Converts the read values of the potentiometer from 0 to 1023 into an angle (0 to 360 degrees )
// The value selected here must be substantially above zero, as immediately less than zero is 360, which confuses the motor and me
if (potA4 <=80) {
// Serial.print(" potA4 <=80"); // Pot angled to side
directionLinkage2 = 0;
}
else if (potA4 >=185) { // Pot angled to other side
// Serial.print(" potA4 >=185");
directionLinkage2 = 1;
}
if (directionLinkage2 == 0 && currentMillisA3 - previousMillisA3 >= potA3) {
// Serial.print(" rotating out");
stepper.rotate(2);
previousMillisA3 = currentMillisA3;
}
else if (directionLinkage2 == 1 && currentMillisA3 - previousMillisA3 >= potA3) {
// Serial.print(" rotating back");
stepper.rotate(-2);
previousMillisA3 = currentMillisA3;
}
}
// Function for rotating BLDC motor
void rotateBLDC() {
potA5= analogRead(A5); //Read input from analog pin potA5 and store in potA5
potA5= map(potA5, 0, 1023,30,110); //map potA5 to minimum and maximum
// Serial.print("potA5:");
// Serial.print(potA5);
unsigned long currentMillis = millis();
difference = currentMillis - previousMillisBLDC0;
// Serial.print(" difference = ");
// Serial.print(difference);
if (potA5 >= highPotA5) { // Turn off BLDC when BLDC pot is near zero resistance
digitalWrite(BLDC1, LOW);
digitalWrite(BLDC2, LOW);
digitalWrite(BLDC3, LOW);
// Serial.println(" off");
}
else if (difference >= potA5 * 6) {
previousMillisBLDC0 = currentMillis;
// Serial.println(" 6");
}
else if (difference >= potA5 * 5) {
digitalWrite(BLDC1, HIGH);
digitalWrite(BLDC2, HIGH);
digitalWrite(BLDC3, LOW);
// Serial.println(" 5");
}
else if (difference >= potA5 * 4) {
digitalWrite(BLDC1, HIGH);
digitalWrite(BLDC2, LOW);
digitalWrite(BLDC3, LOW);
// Serial.println(" 4");
}
else if (difference >= potA5 * 3) {
digitalWrite(BLDC1, HIGH);
digitalWrite(BLDC2, LOW);
digitalWrite(BLDC3, HIGH);
// Serial.println(" 3");
}
else if (difference >= potA5 * 2) {
digitalWrite(BLDC1, LOW);
digitalWrite(BLDC2, LOW);
digitalWrite(BLDC3, HIGH);
// Serial.println(" 2");
}
else if (difference >= potA5) {
digitalWrite(BLDC1, LOW);
digitalWrite(BLDC2, HIGH);
digitalWrite(BLDC3, HIGH);
// Serial.println(" 1");
}
else {
digitalWrite(BLDC1, LOW);
digitalWrite(BLDC2, HIGH);
digitalWrite(BLDC3, LOW);
// Serial.println(" 0");
}
}
Comments