XIEGU G90 Collection

11 februarie 2023

DC motor speed controller for Proxxon

I have an old Proxxon tool and, like many old power tools, the built-in speed controller is not working anymore.

So, I was thinking to do a separate box to set the speed because the actual method is not so suitable (altering the output voltage from my SMPS). You know, there are other "things" connected to it and modifing the voltage can harm them...

A DC current regulator was out of question because the Proxxon (like Dremel) need big currents when is loaded and the next thought was to make a variable PWM controller. So I searched into my boxes for a NE555 circuit and found a NE556 which is, basically, two 555 in the same IC.

I started to sketch the schematic and put it on a breadboard but there was too much soldering... HI HI :-)

Searching for a suitable case, I found one from an old project, already cut to accomodate a 2x16 LCD so I start to contemplate the possibility to make a speed controller which will show me the percentage and the input voltage and, why not, enable me to control other DC power tools.

I also found a small PCB already made for Arduino Pro-Mini and parallel controlled LCD so, i already had a good start!

Using PWM to controll DC motors is pretty convenient because the DC motor will "convert" variable width DC pulses into speed due to mechanical inertia. The most important thing is to find a semiconductor to work as much as possible to a switch!

Regular bipolar transistors are not suitable because they have a relative big resistance when the "switch" is closed so I decided to use a MOS-FET transistor.

I searched for one with a small Drain-Source resistance and found in my spare parts a IRF3205 which is advertised as a low resistance MOS-FET:


datasheet here.


Of course, there are other suitable transistors but I wanted to have one that can handle some current without radiator...

Some words about the schematic

 click on the picture for greater resolution

The working principle is simple; the speed potentiometer value is read by ADC (by reading the voltage of the wiper) and the value is converted from 1024 values into 255.

Then, this value is used to draw a nice bargraph, to print the % value and to generate the corresponding PWM value on pin 10 which will drive the MOS-FET transistor.

After testing it, I thought it was nice to have the input voltage on display so a voltage divider was made to be able to measure up to 30V with some accuracy.

My Arduino Pro-Mini was the 5V version so I choose a 7805 LDO to get those 5V for the board and the LCD. The board was powered by the RAW input, after the on-board voltage regulator.

Some words about the voltage divider and voltage measurement calibration

Arduino ADC's can measure 0-5V. Actually, the maximum value that can be measured with the ADC is precisely that of the Vcc applied to Arduino! So, in our case where the 5V are externally regulated from a 7805, we must measure the voltage at the RAW pin where 5V is applied. Usually the voltage is in the 4.9-5.1 V range and 5V is pretty accurate but if you want to have a greater precision, just replace "5" with the measured voltage in the code.

The voltage divider was made with what I had in my spare box, you can replace R4 and R5 with your values but keep in mind you must have a ratio able to keep the voltage at ADC port under 5V for the maximum voltage you want to use the device!

In the code, there is a "divider ratio" variable. This is how I get it:

Using this online voltage divider calculator, I used the following values, you can replace them with yours:

        Input voltage: 12V

        R1: 68 KOhm

        R2: 5.1 KOhm

I got 0.837 V after the voltage divider.

The voltage ratio is therefore: 12/0.837 = 14.336917.

Of course, this is the theoretical result! 

In practice, the ADC have it's own impedance, a stray resistor in DC so the real value of the voltage ratio is not so precise. Also, some errors will be present due to the real values of those resistors!

Some tweaking is needed to have a proper voltage indication so I set the voltage input into the device at 13V and on the LCD I got about "13.9V".  I start to make some fine adjustments on that value (I did not calibrated the ADC reference too) and I ended with the

        float divider_ratio = 13.1386;

which gave me pretty precise readings from 10 - 24V.

I think you got the ideea on what to do to your voltage divider to get it work right!

This project on Github.

Here is the Arduino IDE code:


#include <LiquidCrystal.h>
#include <LcdBarGraph.h>
/* DC motor speed controller
based on Arduino
Autor: Adrian YO3HJV
februarie 2023
Versiunea 2.0
Bargraph library: https://github.com/prampec/LcdBarGraph
*/
/*
Speed potentiometer wiper to A2
PWM output for LCD backlight D3
PWM output to power transistor D10
*/
byte lcdNumCols = 16; // LCD display number of columns used to draw the bargraph
byte pot_pin = A2; // potentiometer wiper
byte volt_pin = A0; // input voltage through resistive divider
int pot_value = 0;
int pwm_factor = 0;
int percentage = 0;
int v_adc = 0;
float divider_ratio = 13.1386; // voltage ratio from the voltage divider
// this value is to be fine adjusted to have a precise reading of the voltage
#define lcd_led 3 // PWM output for LCD backlight ("A" pin on LCD)
#define motor_pin 10 // PWM output to MOS-FET
int lcd_led_intensity = 255; // LCD backlight brightness
// 4 bit LCD connections
const int rs = 9, en = 8, d4 = 4, d5 = 5, d6 = 6, d7 = 7;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
LcdBarGraph lbg(&lcd, lcdNumCols);
void setup(){
Serial.begin(9600);
analogWrite(lcd_led, lcd_led_intensity); // Set backlight
// -- initializing the LCD
lcd.begin(2, lcdNumCols);
lcd.clear();
delay(100);
// these are fixed on LCD. We set them here because the LCD will not be cleared
lcd.setCursor (3, 1);
lcd.print("%");
lcd.setCursor (15, 1);
lcd.print("V");
}
void loop()
{
int i;
int numReadings = 10; // the number of samples for the input voltage
for (i = 0; i < numReadings; i++){
v_adc = v_adc + analogRead(volt_pin);
// 10ms to stabilise the ADC readings
delay(10);
}
// ADC sampled values averaging
v_adc = v_adc / numReadings;
// we determine the voltage from the averaged adc readings after the voltage divider
// For greater precision, we can replace '5V' with the value measured at RAW pin on Arduino board
float voltage = v_adc * (5.0 / 1023.0);
// Apply voltage divider ratio to determine the input voltage BEFORE the voltage divider
float volt = voltage * divider_ratio;
Serial.println(volt); // debug and calibration. Comment this line after calibration
if (volt > 0 & volt < 10){
lcd.setCursor (11, 1);
lcd.print(" ");
lcd.print (volt,1);}
if (volt>= 10 & volt <100){
lcd.setCursor (11, 1);
lcd.print("");
lcd.print (volt,1);}
// read ADC from Speed potentiometer and transform the 1024 steps into 255 steps
pot_value = analogRead(pot_pin);
pwm_factor = map(pot_value, 0, 1023, 0, 255);
percentage = map(pot_value, 0, 1023, 0, 100); // maximum printed value is 100%
// Draw bargraph from 255 steps
lbg.drawValue(pwm_factor, 255);
delay(100);
// set PWM for DC motor speed
analogWrite(motor_pin, pwm_factor);
// print percentage on LCD
if (percentage > 0 & percentage< 10){
lcd.setCursor (0, 1);
lcd.print(" ");
lcd.print (percentage);}
if (percentage>= 10 & percentage <100){
lcd.setCursor (0, 1);
lcd.print(" ");
lcd.print (percentage);}
if (percentage >=100){
lcd.setCursor (0, 1);
lcd.print("");
lcd.print (percentage);}
delay(100);
}