# Angular velocity of a dc motor controlled by a potentiometer

I created a setup in which a potentiometer controls a dc motor, with current flow through the dc motor controlled by an H-bridge. The principle is as follows: With the potentiometer dial set to the mid-point, the motor is off. Rotating the potentiometer clockwise would cause the motor to rotate in one direction, with speed dictated by the displacement of the potentiometer from the mid-point: the greater the displacement from mid-point, the greater the speed of rotation of the motor. If the potentiometer is rotated anti-clockwise, away from mid-point, the motor would rotate in the opposite direction from before; again, with speed dictated by the extent of displacement of the potentiometer from mid-point.

The loop has three functions, where HB_12EN is to enable the drivers, HB_1A is the first driver input, and HB_2A is the second driver input (H-Bridge pins 1, 2 and 7, respectively) as per this datasheet: http://www.ti.com/lit/ds/symlink/sn754410.pdf

To summarise their functions: HB_12EN allows voltage to be applied to the the device controlled by the H-Bridge (in this case a motor), and is pulse-wave-modulated. HB_1A and HB_2A control the flow of current through the motor, setting its angular velocity. HB_1A set HIGH and HB_2A set LOW directs current one way through the motor, and HB1A set LOW and HB_2A set HIGH directs current the other way through the motor.

The loop is:

``````//OUTPUTS
int const HB_12EN = 9; //pwm pin
int const HB_1A = 2;
int const HB_2A = 3;

//INPUTS
int const POT_MOT = 0; //A0, analog 0

//GLOBAL VARIABLES
unsigned int pot_val = 0; //ADC value from potentiometer
unsigned int grp_num = 1;

grp_num = setMotSwitch(HB_12EN, HB_1A, HB_2A, pot_val, grp_num);
setMotSpeed(HB_12EN, pot_val, grp_num);
``````

The two (non-library) functions are:

``````unsigned int setMotSwitch(int const motor_reg, int const first_motor, int const sec_motor, unsigned int pot_value, unsigned int group_num) //grp 0: 0-383; grp 1: 384-639; grp 2: 640-1023
{
if (pot_value >= 0 && pot_value < 384)
{
if (group_num != 0)
{
digitalWrite(motor_reg, LOW);
digitalWrite(first_motor, HIGH);
digitalWrite(sec_motor, LOW);
group_num = 0;
}
}
else if (pot_value > 383 && pot_value < 640)
{
if (group_num != 1)
{
digitalWrite(motor_reg, LOW);
digitalWrite(first_motor, LOW);
digitalWrite(sec_motor, LOW);
group_num = 1;
}
}
else if (pot_value > 639 && pot_value <= 1023)
{
if (group_num != 2)
{
digitalWrite(motor_reg, LOW);
digitalWrite(first_motor, LOW);
digitalWrite(sec_motor, HIGH);
group_num = 2;
}
}
else
{
digitalWrite(motor_reg, LOW);
digitalWrite(first_motor, LOW);
digitalWrite(sec_motor, LOW);
group_num = 0;
}
return group_num;
}

void setMotSpeed(int const motor_reg, unsigned int pot_value, unsigned int group_num)
{
unsigned int mot_speed = 0;
if (group_num == 0)
{
mot_speed = map(pot_value, 0, 383, 255, 0);
mot_speed = constrain(mot_speed, 0, 255);
analogWrite(motor_reg, mot_speed);
}
else if (group_num == 1)
{
if (pot_value > 500 && pot_value < 523)
{
digitalWrite(motor_reg, HIGH); //braking
}
else
{
digitalWrite(motor_reg, LOW);
}
}
else if (group_num == 2)
{
mot_speed = map(pot_value, 640, 1023, 0, 255);
mot_speed = constrain(mot_speed, 0, 255);
analogWrite(motor_reg, mot_speed);
}
}
``````

I tried to proceed as follows: As the potentiometer would produce an ADC input with 1024 states, I divided those 1024 states in to 8 groups, the first three groups, covering the first 384 states (0-383) correspond to a dc motor direction (let's say anticlockwise), representing different speeds of rotation (ignoring issues of many-to-one mapping). The middle 2 groups, 256 states (384-639), correspond to a stationary motor. The last three groups, 384 states (640-1023), correspond to motor rotation in the other direction (in this example, clockwise). The ADC inputs have to be translated in to analog outputs with 256 possible states (0-255), so I map each range as appropriate; for 0-383, the mapping has to be reversed, so an input of 383 corresponds to an input of 0. The middle range (384-639) is stationary, but I tried to make a small "sub"-range in the middle a "braking range", I believed this is achieved by setting both H-bridge inputs to LOW. The 640-1023 range mapping is 640 to 0 and 1023 to 255.

Hopefully that makes sense. It seems to work, the issue I am having is that the motor seems to achieve a greater speed in one direction compared to the other: the maximum rotation speed produced in the motor is greater when the potentiometer is at its maximum in one direction compared to the other. I am pretty sure the code above gives an "even" mapping from the potentiometer to the motor for both directions. Is this, then, something to do with hardware?, and is it something to be anticipated in these kinds of setups?

Any help would be appreciated. If anyone has any advice on the best way to combine a potentiometer -or similar- input with a motor output let me know. The "braking" functionality is also a little confusing.

• I appreciate all the feedback so far. I would like to add that the code itself is a product of a number of factors. It is partly constrained by a textbook: I am trying to limit the code to what has been covered in a textbook I am working through. The other factors include: I) I wanted to use a number of functions, and II) I wanted to write a programme that would bypass setting the H-Bridge pins through every iteration. My main motivation for posting is that I would like to know if the issue I am having with motor speed is a coding issue or possibly a hardware issue. – Jay Lin Aug 26 '17 at 22:46

Personally I wouldn't bother with "groups". Just do simple maths:

``````int velocity = analogRead(POT_MOT) - 512;
``````

`velocity` now gives you a value from -512 to +511.

``````bool dir = (velocity >= 0);
``````

`dir` is now `true` for a positive value (0 is considered positive) or `false` for negative.

``````velocity = abs(velocity);
``````

`velocity` is now made positive if it is negative.

So you now have two variables: `dir` which sets the direction, and `velocity` which sets the speed.

Now you can "offset" it:

``````velocity = map(velocity, 0, 512, -128, 255);
``````

`velocity` is now changed to fit into the range -128 to 255. Anything above 0 is a valid speed, anything below is the "dead zone" and stops the motor.

``````if (velocity <= 0) {
// If it's negative or zero stop
digitalWrite(motor_reg, LOW);
digitalWrite(first_motor, LOW);
digitalWrite(sec_motor, LOW);
} else {
if (dir) { // Pot was positive
analogWrite(motor_reg, velocity);
digitalWrite(first_motor, LOW);
digitalWrite(sec_motor, HIGH);
} else { // Pot was negative
analogWrite(motor_reg, velocity);
digitalWrite(first_motor, HIGH);
digitalWrite(sec_motor, LOW);
}
}
``````

Adjust the negative value in the map to change the size of the "dead zone".

i would break out this into three or at least two parts:

1) a call to change the speed of the motor; 2) a call to read the potential meter setting; 3) a call to convert the potential meter setting into motor speed, optional.

the code would look like this:

``````  pot_setting = potsetting_read(); //read pot setting
speed_setting = pot2spd(pot_setting); //convert pot setting to motor speed
motor_setspeed(speed_setting); //set motor speed
``````

it is not difficult to figure out each of the three functions.

the more challenging of the three, to a newbie, is the one that sets the motor speed. there are many ways to do it, and I personally prefer to use timer interrupts.

the basic construct is to sequentially go through a set of pin states, where the duration of each state transition is controlled by a timer interrupt. by changing how fast that timer interrupt takes place, you change the speed in which the pins transition their states, thus motor speed.