I have a DC motor connected to a L298N driver. The motor is spinning what I call a large plate. In the center of this plate I have a pot.
I'm trying to get the plate to rotate in one direction until the pot reads 750, then reverse it's direction until the pot reads 300, then reverse again. Basically turning back & forth or Ping-Pong, but I'm having a hard time getting my head around the code.
Can anyone give me some suggestions?
I've tried stuff like this, but of course it's not working....:
#define POT_PIN A8
#define MAX_LEFT 750
#define MAX_RIGHT 300
//Motor A
int dir1PinA = 32;
int dir2PinA = 34;
int speedPinA = 36;
int motor_speed;
int dir = 0;
void setup() {
pinMode (dir1PinA, OUTPUT);
pinMode (dir2PinA, OUTPUT);
pinMode (speedPinA, OUTPUT);
motor_speed = 250;
}
void loop() {
int headRot = analogRead(POT_PIN);
analogWrite (speedPinA, motor_speed); //Turn motor on
if (headRot < MAX_LEFT && dir == 0) // 750
{
flipMotorDirection(1);
dir = 1;
Serial.println("dir = 1");
}
if (headRot > MAX_RIGHT && dir == 1) // 300
{
flipMotorDirection(0);
dir = 0;
Serial.println("dir = 0");
}
}
void flipMotorDirection(int dir)
{
if (1 == dir)
{
digitalWrite (dir1PinA , LOW);
digitalWrite (dir2PinA, HIGH);
}
else
{
digitalWrite (dir1PinA, HIGH);
digitalWrite (dir2PinA, LOW);
}
}
That code looks as if it is trying to power the motor in the target direction until it reaches the target, then reverses the motor direction and waits until the motor slows down, stops, accelerates in the reverse direction and reaches the other limit.
You don't say what it actually does, but this design is a recipe for a massively overshooting system which would be liable to be unstable and just overshoot further and further until it hits a mechanical limit somewhere.
I would have thought that a system with significant inertia as you're describing would benefit from using a PID algorithm to control the motor direction and speed. That way you could easily get it to move to the required position and stop.
Thanks for the replays.
Currently, when it's between 300 & 750 it alternates between 0 & 1 on every loop.
dir = 1
dir = 0
dir = 1
dir = 0
dir = 1
dir = 0
dir = 1
dir = 0
e.g. Runs the motor at 1/2 speed.
When the pot goes over 750, it runs at full speed, but doesn't reverse direction.
When the pot goes under 300, it runs at full speed, and reverses direction.
I'm not sure what a PID algorithm is or how to use it....?
BazzaCAD:
It's just the logic with the pot code that I can't figure out.
Initially I assumed that MAX_LEFT was less than MAX_RIGHT, and with that assumption your code seemed to make sense. But in fact MAX_LEFT is greater than MAX_RIGHT. That means that the comparisons you're applying to your pot values are back to front.
PaulS:
You never actually do anything with dir or motors...
If the potentiometer values represent limits, names like MIN_something and MAX_something make more sense than two MAX_somethings.
Yes I was just testing to make sure I got the logic correct before connecting to the motor. Here it is with the motor code. Thanks for the tip on the MIN/MAX..
#define POT_PIN A8
#define MAX_LEFT 750
#define MIN_RIGHT 300
//Motor A
int dir1PinA = 32;
int dir2PinA = 34;
int speedPinA = 36;
int motor_speed = 250;
int dir = 0; // 0 = Left, 1 = Right
void setup() {
Serial.begin(9600);
}
void loop() {
int headRot = analogRead(POT_PIN);
// Serial.println(headRot); // read-print pot
analogWrite (speedPinA, motor_speed); //Turn motor on
if (headRot < MAX_LEFT)
{
if (headRot > MIN_RIGHT)
{
// Serial.println("Center");
} else {
// Serial.println("Min Right");
dir = 0;
}
} else {
// Serial.println("Max Left");
dir = 1;
}
flipMotorDirection(dir);
}
void flipMotorDirection(int dir)
{
if (0 == dir)
{
digitalWrite (dir1PinA , LOW);
digitalWrite (dir2PinA, HIGH);
}
else
{
digitalWrite (dir1PinA, HIGH);
digitalWrite (dir2PinA, LOW);
}
}
analogWrite (speedPinA, motor_speed); //Turn motor on
Varying the motor speed as you get closer to the limit would be a good thing. That's what the PID idea is all about. Sneak up on the limits to avoid overshooting.
You only need to flip the motor direction if it changes, not on every pass through loop.
Your commented out Serial.print() information does not reflect reality.
PaulS:
Varying the motor speed as you get closer to the limit would be a good thing. That's what the PID idea is all about. Sneak up on the limits to avoid overshooting.
You only need to flip the motor direction if it changes, not on every pass through loop.
Your commented out Serial.print() information does not reflect reality.
Thanks for the info. So I should slow down the motor as I get closer to the limit?
So I should slow down the motor as I get closer to the limit?
Yes. Make the speed depend on the absolute value of the difference between the headRot value and the middle of the range. As the difference gets larger, slow down. As it gets smaller, speed up. The maximum speed, then, would be right in the center of the range.
PaulS:
Yes. Make the speed depend on the absolute value of the difference between the headRot value and the middle of the range. As the difference gets larger, slow down. As it gets smaller, speed up. The maximum speed, then, would be right in the center of the range.
You compute the absolute value of the difference between the current position and the middle of the range:
int midPoint = (MAX_RIGHT + MIN_LEFT)/2; // 525
int delta = abs(headRot - midPoint);
Then, map that difference to the desired speed value:
int maxVal = MAX_RIGHT - midPoint; // 750 - 525 = 225
int speed = map(delta, maxVal, 0, minSpeed, maxSpeed);
The minSpeed and maxSpeed variables need to be declared and valued before this code. The minimum will, presumably, be 0 and the maximum will be whatever you think appropriate based on you hardware.
When the value in delta is largest (the actual position is at the left or right limit), the mapping will result in the smallest value in the to range (minSpeed). When the value in delta is smallest (the actual position is at the midpoint), the mapping will result in the largest value in the to range (maxSpeed). So, you will be going fastest in the middle and slowest on the ends.
It might be necessary to constrain headRot to be in the range MIN_LEFT to MAX_RIGHT, and set the minimum speed to be something other than 0, so that if an overshoot occurs, the device will slowly rotate back to the correct position, rather than just stopping.
I was just wondering, instead of only having the maxSpeed at the exact midpoint, how could I get it to stay at the maxSpeed for the center 1/3 of the rotation?
So the 1/3's would look something like this: minSpeed -> maxSpeed | maxSpeed -- maxSpeed | maxSpeed -> minSpeed
I was just wondering, instead of only having the maxSpeed at the exact midpoint, how could I get it to stay at the maxSpeed for the center 1/3 of the rotation?
Use a larger value for maxSpeed, then constrain the result of the map to be between lower (reasonable) limits.
What is it you are turning? What values have you picked for minSpeed and maxSpeed? How fast does that result in whatever you are actually turning moving?
With a valid range of only about half the potentiometer's actual range, it looks like you will only accomplish a 180 degree (approximately) rotation of whatever you are moving. I don't see how running full speed for more than a little of that range will make much difference in how long it takes to rotate that 180 degrees.
You won't believe what I'm building.
It's a giant R2-D2 sculpture built out of canned food.
It's for a charity event called CANstruction. http://www.sfcanstruction.org
R2 will be 7' tall with a 3' dia. body.
All this coding is to get his head to turn.
I know R2's head should turn 360 deg. but my pot. only turns 270 deg. & I don't want to deal with winding/unwinding the wires.
Unfortunately my current motor is under sized & can't turn the head with much load on it, so I can't answer your questions about have long it's taking to turn it.
I have 2 larger motors on order now. Maybe you'll be right & I can put it back to only have the maxSpeed at the midPoint...