First of all You won’t find here any information on high speed BLDC motor driving. For that purpose You need to know rotor’s position, so You have to measure back-EMF or use Hall sensors (not needed here).
For basic info about driving BLDC motors here is best “classic” articles on internets:
Driving a three-phase brushless DC motor with Arduino – Part 1. Theory
Driving a three-phase brushless DC motor with Arduino – Part 2. Circuit and Software
http://www.instructables.com/id/BLDC-Motor-Control-with-Arduino-salvaged-HD-motor/
I used specialized triple half bridge IC L6234 (~ 8$). You can make the same spending less money (but more time) with MOSFET transistors or other IC.
But be careful, I found a lot of cases in various forums, where people burned their Arduinos or L6234 chips.
ATTENTION
If You connect L6234 INputs directly to Arduino and OUTputs to low impedance motor – current from Arduino pins will be driven directly through L6234 to the windings and to the ground (without external Vs power applied to L6234). This makes very good chance to burn Your lovely microprocessor.
Also in application note, one sentence is worth to mention – “To avoid overload of the logic INPUTS and ENABLES, voltage should be applied to Vs prior to the logic signal inputs.”
I also very recommend to study (or/and purchase) this open hardware driver board based on L6234 BLDC Motor Driver by Michael Anton. It has input protecting resistors, zeners, power supply/filtering components and even back-EMF sensing circuit with amplifier (not used here).
L6234 datasheet is surprisingly useless. Go straight to Application Note AN1088 instead.
My setup of Arduino and DIY driver-board:
I added current limiting resistors (1kΩ) to all INputs and ENable pins, a bunch of capacitors recommended in application note and current sensing shunt resistor 0.6Ω (big blue one).
There is main illustration, for basic BLDC driving using 6 step sequence(rectangular current):
It works very well on high speeds. But on slow RPM’s You will have choppy steps. So we need to smooth out driving current to sine waves:
To achieve this, You simply set ENable pins to HIGH (as except few zero moments, voltage is continously changing). And feed the sine-wave modulated PWM (SPWM) to INput pins:
I didn’t tried to force Arduino to make sine calculations. Lookup tables was used instead. Here is a link to OpenOffice spreadsheet:
BLDC_SPWM_Lookup_tables
You can generate traditional sine waves (SPWM) and Space-Vector PWMs (SVPWM). Try both and decide which to choose for Yourself.
And here is actual Arduino code, fused from different sources:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
// // Slow and precise BLDC motor driver using SPWM and SVPWM modulation // Part of code used from http://elabz.com/ // (c) 2015 Ignas Gramba www.berryjam.eu // const int EN1 = 5; const int EN2 = 6; const int EN3 = 7; const int IN1 = 9; const int IN2 = 10; const int IN3 = 11; // SPWM (Sine Wave) //const int pwmSin[] = {127, 138, 149, 160, 170, 181, 191, 200, 209, 217, 224, 231, 237, 242, 246, 250, 252, 254, 254, 254, 252, 250, 246, 242, 237, 231, 224, 217, 209, 200, 191, 181, 170, 160, 149, 138, 127, 116, 105, 94, 84, 73, 64, 54, 45, 37, 30, 23, 17, 12, 8, 4, 2, 0, 0, 0, 2, 4, 8, 12, 17, 23, 30, 37, 45, 54, 64, 73, 84, 94, 105, 116 }; /// SVPWM (Space Vector Wave) //const int pwmSin[] = {128, 147, 166, 185, 203, 221, 238, 243, 248, 251, 253, 255, 255, 255, 253, 251, 248, 243, 238, 243, 248, 251, 253, 255, 255, 255, 253, 251, 248, 243, 238, 221, 203, 185, 166, 147, 128, 109, 90, 71, 53, 35, 18, 13, 8, 5, 3, 1, 1, 1, 3, 5, 8, 13, 18, 13, 8, 5, 3, 1, 1, 1, 3, 5, 8, 13, 18, 35, 53, 71, 90, 109}; const int pwmSin[] = {128, 132, 136, 140, 143, 147, 151, 155, 159, 162, 166, 170, 174, 178, 181, 185, 189, 192, 196, 200, 203, 207, 211, 214, 218, 221, 225, 228, 232, 235, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 248, 249, 250, 250, 251, 252, 252, 253, 253, 253, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 254, 254, 253, 253, 253, 252, 252, 251, 250, 250, 249, 248, 248, 247, 246, 245, 244, 243, 242, 241, 240, 239, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 248, 249, 250, 250, 251, 252, 252, 253, 253, 253, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 254, 254, 253, 253, 253, 252, 252, 251, 250, 250, 249, 248, 248, 247, 246, 245, 244, 243, 242, 241, 240, 239, 238, 235, 232, 228, 225, 221, 218, 214, 211, 207, 203, 200, 196, 192, 189, 185, 181, 178, 174, 170, 166, 162, 159, 155, 151, 147, 143, 140, 136, 132, 128, 124, 120, 116, 113, 109, 105, 101, 97, 94, 90, 86, 82, 78, 75, 71, 67, 64, 60, 56, 53, 49, 45, 42, 38, 35, 31, 28, 24, 21, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 8, 7, 6, 6, 5, 4, 4, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 8, 7, 6, 6, 5, 4, 4, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 21, 24, 28, 31, 35, 38, 42, 45, 49, 53, 56, 60, 64, 67, 71, 75, 78, 82, 86, 90, 94, 97, 101, 105, 109, 113, 116, 120, 124}; int currentStepA; int currentStepB; int currentStepC; int sineArraySize; int increment = 0; boolean direct = 1; // direction true=forward, false=backward ////////////////////////////////////////////////////////////////////////////// void setup() { setPwmFrequency(IN1); // Increase PWM frequency to 32 kHz (make unaudible) setPwmFrequency(IN2); setPwmFrequency(IN3); pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT); pinMode(IN3, OUTPUT); pinMode(EN1, OUTPUT); pinMode(EN2, OUTPUT); pinMode(EN3, OUTPUT); digitalWrite(EN1, HIGH); digitalWrite(EN2, HIGH); digitalWrite(EN3, HIGH); sineArraySize = sizeof(pwmSin)/sizeof(int); // Find lookup table size int phaseShift = sineArraySize / 3; // Find phase shift and initial A, B C phase values currentStepA = 0; currentStepB = currentStepA + phaseShift; currentStepC = currentStepB + phaseShift; sineArraySize--; // Convert from array Size to last PWM array number } ////////////////////////////////////////////////////////////////////////////// void loop() { analogWrite(IN1, pwmSin[currentStepA]); analogWrite(IN2, pwmSin[currentStepB]); analogWrite(IN3, pwmSin[currentStepC]); if (direct==true) increment = 1; else increment = -1; currentStepA = currentStepA + increment; currentStepB = currentStepB + increment; currentStepC = currentStepC + increment; //Check for lookup table overflow and return to opposite end if necessary if(currentStepA > sineArraySize) currentStepA = 0; if(currentStepA < 0) currentStepA = sineArraySize; if(currentStepB > sineArraySize) currentStepB = 0; if(currentStepB < 0) currentStepB = sineArraySize; if(currentStepC > sineArraySize) currentStepC = 0; if(currentStepC < 0) currentStepC = sineArraySize; /// Control speed by this delay delay(10); } void setPwmFrequency(int pin) { if(pin == 5 || pin == 6 || pin == 9 || pin == 10) { if(pin == 5 || pin == 6) { TCCR0B = TCCR0B & 0b11111000 | 0x01; } else { TCCR1B = TCCR1B & 0b11111000 | 0x01; } } else if(pin == 3 || pin == 11) { TCCR2B = TCCR2B & 0b11111000 | 0x01; } } |
After compilation You will have info that there are still plenty of memory. Even after heavy 360 values sine array.
1 2 |
Sketch uses 2,418 bytes (7%) of program storage space. Maximum is 32,256 bytes. Global variables use 741 bytes (36%) of dynamic memory, leaving 1,307 bytes for local variables. Maximum is 2,048 bytes. |
So, there are 360 “steps” in one electrical revolution, and tested motor had 6 electrical revolutions, per one mechanical. This means 360×6 = 2160 “steps” per mechanical revolution or 0,16(7) degree of precision. If not enough, You can make even 3x more precise lookup table.
Here is some video illustrating results (You have to be very patient to notice movement on last one! )
SVPWM modulation is used in this video. Pot interactively changes delay(); value.
Support
If I helped You, please help me. Thank You!
Thanks a lot, great easy code and perfect explanation. Help me a lot with my robot project.
Your sketch go perfect with a ST-L298 motor driver and a Turnigy gimbal motor.
😉
I almost copied this program to generate SPWM using STM32,along with a DRV8313 in the hope for driving a 3-phase BLDC,would you please help me?
My e-mail address is 827366470@qq.com
Pingback: Driving A Brushless DC Motor Sloooooooowly | Ad Pub
Pingback: Driving A Brushless DC Motor Sloooooooowly - zeax blog (ze-ax.com)
Pingback: Driving A Brushless DC Motor Sloooooooowly | Hack The Planet
Pingback: Driving A Brushless DC Motor Sloooooooowly | MyWebspace
Nice work ! It has appeared also in Hackaday.com
http://hackaday.com/2015/04/20/driving-a-brushless-dc-motor-sloooooooowly/
Thanks !
Pretty cool job! Thanks for sharing!
Since I don’t have much of an electrical engineering background I wonder What exactly are the limitations of this compared to a “real” stepper motor. I imagine that the torque is probably pretty low…? Are there any other drawbacks?
Pingback: Spining BLDC motors at super Slow speeds with Arduino and L6234 - Arduino collector blog
Hallo! Great job!
Please tell us about motor torque!
Nice job
Can you publish or send a diagram of the circuit?
Thank you
I need the circuit diagram as well
Please share with us
I’ve got a motor that doesn’t have any hall sensors, so this looks perfect!
But does it matter which of the 2 switches the pwm is on? For example to adjust the speed, do you change the duty cycle on the high side phase switch, or on the switch connected to the low side? With respect to pwm, I’ve seen references to ‘unipolar’, ‘bipolar’, ‘complimentary’, ‘1-4 quadrant’, but I’m not sure if/how it’s related.
Does anyone know if assembled boards are available for purchase? I saw another bldc driver, but no assembled boards either (https://github.com/lgbeno/BLDC-Booster http://open-bldc.org/wiki/Open-BLDC)
I just recently sold a few of these boards, and I would consider doing another run if there was interest. Send me a message.
I often have assembled boards available on my Tindie store. I’m out of stock just now, but I have another assembly run in process, so they should be in stock soon.
Yes, I have some assembled boards available on Tindie for purchase. See my website at http://manton.ca for details.
Yes, I have assembled boards available in my webstore at: https://www.tindie.com/stores/manton/.
Good job
Can U post the circuit diagram???
I would love to see what your wiring diagram looks like
Hi there, thank you so much for info..but if there to make change if my motor is delta connection inside?
and mind to share the circuit diagram?or u directly use as shown in AN1088 datasheet?
thank you.
Thanks for perfect explanation.
I have some overheating problems while using this control technique. Is there anyone has same or any solition recommendation?
I recommend external cooler or blower.
Yes. One issue is you want to use a gimbal brushless motor. These motors are specifically designed for slow speeds – I believe the trick is they are wound with more wire so they have higher resistance and do not get as hot. The other thing is you can basically change the power delivered to the motor by reducing the PWM frequencies in berryjam’s sine wave array. I created an implementation of this here:
https://raw.githubusercontent.com/owhite/brushless_gimbal_motor/master/simple/simple.ino
Note, that code is used for a particular motor driver board so the pins are hardwired.
How much torque am i likely to get out of the motor when running at these low speeds. I have an application for such a drive system but I do need torque and was trying to avoid using a gearbox if I can.
Bill
This one is called open-loop v/f control. You apply sin voltage to generate sin current so that the motor can rotate at very low speed depending on the sin frequency. However, the problem of this method is that the applied current may not be at the correct phase. Torque = ea*ia + eb*ib + ec*ic. Suppose e and i are both sin with a phase difference of theta, Torque = 1.5EIcos(theta). You can easily see if theta is big, you need very high current to realize the torque to rotate. I think that’s where the heat problem would occur.
Thanks for linking to my reference design. I think that is a first. I linked back to your page, so that people can find a good reference on how to implement the software side of things.
Pingback: Hard Drive Wall Clock (first concepts) | modified.systems
Pingback: Spining BLDC motors at super Slow speeds with Arduino and L6234 -Use Arduino for Projects
Hi, quick question, by using the PWM, would that also mean that If I dont change the pwm value of the outputs the motor will stay at that angle right? Is this the way BLDC gimbals work?
Thanks!
Hi, I have a problem I can not get the minimum speed on video, I tried everything, if you can give a sketch of the video evlgenii@gmail.com
I have the same problem with motor overheating… ,
Thank you very much
HI,
HI,
please give schematic diagram for connection with components in arduino and BLDC and L6234 please give ,
I’ve tested this code with Arduino and adapted to to an STM32 and it works as expected. An issue that I’m running into though is that my motors are warming up considerably. I know that as the speed goes down, torque increases which is proportional to the current flowing through the coils but is there any way to reduce the current while still maintaining the low speeds?
Yes, reduce the amplitude of the sine wave that the motors are driven with. You can do this by dividing the table values by some number.
Good Job Patrick !!..
Can you share this code an schematic for STM32 for me ? (pablitosax@yahoo.com)
Hello Sir. I am also trying to the same thing with stm32f103… But i have some problems. Could you please contact with me?
cobanosman@yandex.com
I would love to buy you a beer but can we see the schematic?
Hello BerryJam. Im doing some tests with L6234 and Arduino. First test using L6234 Linear mode with HD disk motor.
Thanks for your tutorial.
Hello BerryJam. Im doing some tests with L6234 and Arduino. First test using L6234 Linear mode with HD disk motor.
Thanks for your tutorial.
http://labdegaragem.com/forum/topics/tutorial-motor-sem-escova-bldc-driver-l6234?commentId=6223006%3AComment%3A565317
Hello guys,
could you help me with code.. my motors arent working.. all connection to the motor driver are connected as mentioned in the datasheet.. but i get output voltage of 0.5V from all three OUT pins of the motor driver..
could you upload the circuit diagram?? Im not figuring whether its the problem of driver or of the code..
Can you tell me the exact model of motor you are using? I’ve duplicated your design using, but I get jerky motion at slow speeds. I’m using an LD-Power Model M2208-80T Gimbal Motor (at least that’s what it seems to be, although I got it on eBay, so perhaps it’s a fake.) I’m using your exact code, but driving the motor with a SN754410NE, Dual H-Bridge. I’ve published a video that shows the jerky motion I get, here:
https://www.youtube.com/watch?v=6KA20IaC94s
Looking at it, you might think it was binding on something, but it’s not. The shaft is free to rotate and spins feely when unpowered. Any thoughts?
Wayne
There is one note about delay() function when someone follow this thread. delay() function only receive an integer parameter. If you want delay(0.5 milisec) you should use the delayMicroseconds(500) instead.
– one period of sin (mentioned as electrical degree as in above pics) will just
– use ollioscopte to see the wave form of IN and OUTPUT pins. You can also compare how good is your DIY driver circuit with other. In my case, I see this link (http://manton.wikidot.com/open:bldc-motor-driver) is much better than in application note.
– With the 360 values sine reference table, the arduino passes 60 pwm values to IN pin to make it finish 1/6 of electrical revolution. mechanical revolution is rotor spinning one circle. One mechanical revolution in this thread contains 6 electrical revolution. One electrical revolution contains 6 control step.
In this link:
http://elabz.com/brushless-dc-motor-with-arduino/
electrical revolution is cycle.
– DIY circuit has better quality than one in application note
Hi Dears
I’ve faced with a new nice problem in my thesis.
please help me to solve it.
I have a system which has two parts spinning in opposite direction relative to each other. In other words it is a
dual spin system. Both of them has 4 canted fin that leads to rotate them about their longitudinal axis when the
system is subjected to the wind (like wind turbine). Their spin rate is approximately high and is closed to 50 HZ.
I want to control the position of part1 (roll angle) relative to the Earth horizon (not relative to part2).
I decided to use a BLDC motor as an alternator in this system which its stator is fixed in part1 and its rotor is fixed in part2.
Actually I want to do a brake by this alternator (bldc) for position control of rotor relative to the Earth horizon
Also I can save electricity energy by this configuration as a generator.
Question1 : Is this solution possible?
Qestion2 : What specification shoud this bldc motor have?
Question : Have you ever seen any application in this configuration by BLDC or electric motor?
Thank you so much
Hi …. great work … bought L6234 and connect to arduino mega and to ATmega644 too
…works great but when making it more complex and adding some flashing leds to the script everything goes good until motor is off [ in program I add switch to pull LOW EN1,2,3 ] but when on, motor works nice but leds flashes in random way totally out of control .. any idea why ?
Greetings people.
Be advised that there are wonderful boards out there that work really well for driving brushless motors.
Search on: “Martinez gimbal controller driver”.
These boards are open source and there are a number of adaptations of them, but the revolve around this circuit:
https://github.com/owhite/brushless_gimbal_motor/blob/master/docs/BGC.pdf
The boards are wonderfully designed, and stupidly cheap.
I adapted the berryjam code for this board, it is here:
https://raw.githubusercontent.com/owhite/brushless_gimbal_motor/master/simple/simple.ino
It’s just a variant of the original code shown on this blog, with some of the pins hardcoded in. Enjoy.
For thos who can’t make it run smoothly at low speeds, try implementing a trapezoidal waveform and a lookup table accordingly. Your motor is likely not to be a sinusoidal EMF motor but trapezoidal EMF motor. That was the case for me.
So, take this into account.
As for schematic. Check the application notes pdf provided in the beginning of the article. It shows all the connections you need.
hi.how to shift phase the pwm wave?
Hi
Works awesome, one problem though. I want to run two motors with two chips/circuits/etc.
This means that pins need to change. Now I have tried a good variety of pins in conjunction with changing the pin numbers in the “void setPwmFrequency(int pin)” function. But I have been unsuccessful.
What do I need to do to change pins so that I can run several circuits/motors on the same arduino?
See here for the answer:
https://stackoverflow.com/questions/46681847/l6234-and-arduino-pinout-problems/46687524#46687524
Hi, nice !
I appreciate your work. I have implemented a svpwm and the motor is chopping when speed reference is very very low. From your feedback, are the speed KP KI only the way to solve the problem ?
Best regards
Hi,
have you solved the chopping problem at low speed? I’m wondering to know if only changing the PI gains in speed or current loop can a normal BLDC motor with Hall spins at that low speed?
Best regards
Hey,Can I use your code for my project? .Im working with the Alexmos 3rd expansion board.It’s has the ATtiny261A and L6234 .I planned to dump the original FW,and replace with arduino core prebuilt .hex FW .
Thank you and Great Job Ignas,
Could you please share the circuit diagram? I just want to be sure.
I followed the datasheet of L6234
But I would like to be sure if everything’s okay.
Regards
Thanks for sharing this project. I’m trying to wrap my head around this before I start my project. I want to implement this kind of sine wave drive for a gimbal bldc motor with 14 poles. But I want to have the motor turn through its steps proportionally to the value of a potentiometer. My idea is to use use a look up table with the sine waves repeating 7 times (14 poles = 7 steps per mechanical rotation), and to sweep through the look up table with the pot, rather than have the look up table “play” in a certain direction. Does that make sense? could this allow me to control the position of my motor without feedback?
By the way: the intended application is to use the motor to rotate the zoom or focus ring on a camera lens: follow focus/zoom. So I actually will never need to rotate a full 360 degrees.
very good article !! .
I do not know the advantages and disadvantages of each code but I can provide this link with an application note of ATMEL and its code that may serve:
https://www.microchip.com/wwwAppNotes/AppNotes.aspx?appnote=en591508
Regards !
Thanks you sir. It works perfectly!
I want to integrate these codes to Stm32f103, but i have some trouble with pwm. Can anyone help me about it?
Pingback: [Tuto] Pilotage de moteur triphasé à faible vitesse
I made this circuid http://manton.ca/open:bldc-motor-driver but after run is IC overheating without motor load. Motor is rotate, but consumption is crazy 2 ampers at 9 voltage. Have you some idea where is the problem?
Hi,
have you solved the chopping problem at low speed? I’m wondering to know if only changing the PI gains in speed or current loop can a normal BLDC motor with Hall spins at that low speed?
Best regards
Thanks for the explanation! I wanted to know if I can get the same program working for a 22N24P gimbal motor?
Hi, Great !
But my project gets L6234 very hot, and Motor is shaking, I think due to ENB pins are always high
Does anyone know why not?