I'm using an Uno and Ladyada's Motor Shield to control a small Solarbotics GM-3 gearmotor. I have the motor supplied through the external power connection to a 6.5v power supply (actually is 6.5v through an LM317, not a guess), so that I get a max of about 6v to the motor. The motor functions in a range of roughly 3 to 6v, so anything less than that and it stalls. I'm reading a 10Kohm pot and mapping the value to between 0 and 255. Since anything less than 3v is useless to me, is it possible to somehow map the PWM range so that it goes from 3v to 6v, thereby allowing me a more precise range of speed control through the pot? I checked out the AREF page, but my understanding is that this references an upper voltage limit, whereas I need a lower voltage limit. Any of you have any ideas? Thanks so much.
It would probably be simpler if you just test the analog reading and if below the analog count value equal to 3volt, just assign the 3volt value in a if statement. Now if you don't like having the dead zone in the pot's lower movement then you would have to utilize some external opamp circuit that would convert a 0-5 input voltage from the pot to a 3-5 volt output wire to the analog input pin, probably not worth the effort. Again I would just clamp the lower value in software and see if I could live with it.
I considered testing for 3v and dropping it in software, but I don't believe that would give me an increased control in the pot, as it would not actually be controlling a 3v-6v range to the motor, just testing the full 0-5v range from the pot and dropping anything below 3v at the motor, so it would essentially have the same mapping and movement on the pot, right? I wanted a better resolution, i.e. tighter control, on the movement of the gear motor based on the movement of the pot.
So if i understand correctly, this essentially can't be done in software and would need a hardware method such as the one you suggested to increased the precision of the motor's speed, right? I'll look into how op-amps work and how to use them.
Also, are there any other notable methods on how to do this? Thanks!
Well the PWM output is limited to 256 counts of resolution and the analog input range of 3-5 volts generates a count range of around 614 to 1023 counts using analogRead() function, which is around 400 counts of resolution. So I see no loss of output control resolution because your restricted to 3-5volts on the pot? Your limit to resolution is really the 8 bit PWM resolution limit. That's why I suggested software clamping and proper mapping should lead to no loss of resolution, just losing 40% travel on the pot. There are multiturn pots avalible if you really require better mechanical input control resolution.
Am I missing something?
so that I get a max of about 6v to the motor
Actually, you don't: the Adafruit shield uses an L293D (or equivalent), which has Darlington transistors on both the high and low sides of the bridge. Darlingtons "waste" about 1.2-1.8V in voltage drop (depending on load, which batch the chip came from, etc.). So the motor is actually getting more like 3.5-4V at "full on".
You're not really controlling voltage with the PWM input, although the net result is similar (but not identical) to varying the voltage. A google search should turn up some tutorials that explain the differences, but you probably don't really need to worry about them right now.
One thing you may need to worry about: iirc, the GM-3 motor draws a hefty amount of current under full load. I'm pretty sure (but not positive: I might be confusing it with another Solarbotics model) that I've read complaints from people about it overloading the L293D. You should check into that. Especially if your driver chip is soldered, instead of socketed. The Adafruit shield doesn't have the huge heatsink area on the PCB recommended by the chip maker. Given the number of "I blew up my chip" posts out there, it's worth looking into putting heatsinks directly on the chips if you'll be running them near their limits.
Ron, what I meant by getting 6v at the motor was that I put alligator clips onto the motor connections and turned the pot on the power supply so that after going through the driver and array I ended up with 6v max as I turned the pot on the analog input all the way. I couldn't remember exactly what the input voltage was into the driver when I adjusted it that way, so I just said 6.5v. But I am actually getting 6v. The current draw at 3v is 389mA at full load and 45mA unloaded, and at 6v loaded is 733mA and unloaded is 62mA. I believe the L293D can handle 600mA, so I should be okay. The load is very light and I'll be driving it around 3v as I need really slow rotation. Based on your advice, though, I'll make sure and keep an eye on the temperature.
Also, I realize that the PWM is not exactly the same as voltage control, but I believe for my purposes it should be okay. My understanding is that adding a cap close to the motor would also help smooth things out, but Im not sure what capacitance and material to use. Any thoughts?
Thanks a bunch for you help.
Lefty, you're not missing anything, but apparently I am. If I understand correctly, you're saying it would be possible to drop anything below 3v and then map the full 1024 input values across the 3-6v range, and then use that to control the 256 values of the PWM control. How exactly would that be done? How does one clamp the 3v down and map the remaining 1024 points of resolution to the 3-5v range?
Or are you saying I should use a known 3v input to determine what that reads as, such as 614, and use an if test to assign a value of 0 to anything below that, and then use the map function to change the reading in the 614 to 1023 range to 0 to 255 and use that as the PWM output value?
Would that just be something like:
if (potVal < 614)
{
PWM = 0;
}
else
{
PWM = map(potVal, 614, 1023, 0, 255);
}
I'm a complete noob when it comes to arduino and microcontrollers, so I appreciate any help you can offer. Thanks!
I would just change:
if (potVal < 614)
{
PWM = 0;
}
else
{
PWM = map(potVal, 614, 1023, 0, 255);
}
To:
if (potVal < 614)
{
potVal = 614;
}
PWM = map(potVal, 614, 1023, 0, 255);
That way the potVal can only assume a value between 614 to 1023 regardless of it's shaft position. You may want or have to adjust that 614 value to the value where the motor is indeed not moving even under no load. Don't worry about filtering of the motor, the motor winding is indeed a big inductor and provide all the filtering required. Direct PWM waveform to a motor works quite well as implemented in the Arduino platform. Does that code fragment make sense?
Lefty
Thanks, Lefty. It makes perfect sense to me now. I thought that this is what you meant in your first post, but I didn't really get the gist of it until your next post and wrote up some quick code. Now, I see what you mean. I'm going to modify the whole script so that I can see what the pot value is at no load, no rotation and use that as the base value in the mapping the pot to the PWM.
My original question was to find out if it was possible to spread the entire 1024 counts of resolution across just the 3-5v range, and eliminate mapping anything less than 3v at all, but it seems that this is only doable with the op amp, like you suggested, so I'll just stick with the code and see if it fulfills my needs.
Thanks so much for all your help! With 4800+ posts under your belt I can't even imagine how many people you've helped!!
Your very welcome, and I do enjoy helping others, even when I'm wrong.
Just in case anyone searches and reads this later for reference, I also found that adjusting the power supply's output to a lower value gives greater control over the slower speeds I needed. I set the maximum voltage (as read at the motor itself), to be 4v, corresponding to the full 1023 on the pot reading, instead of the rated 6v. This gave me a finer control over the lower speeds, which is what I needed, because the PWM's 256 counts of resolution are spread over a lower amount. Just FYI.
Lefty, for reasons I don't understand, this doesn't seem to work. Checking the potVal, I found that the value of 215 (out of the full 1023) corresponded to stall on no load. So I used the code we discussed and found something odd. The potVal simply returns a 0 up until the rotation point on the pot that normally corresponded to 215 in the unmodified code (without the remapping based on 215). Then, the motor doesn't start running until it reaches 70 in the potVal (meaning I had to turn it even farther past the normal point where it stalled without the remapping). Hence, it actually gave me less control, because the potVal count didn't begin until the pot had been turned almost 1/4 of the way. Any idea what's going on? The code is below:
#include <AFMotor.h>
AF_DCMotor motor(1, MOTOR12_64KHZ);
int potVal = 0;
int PWM = 0;
void setup()
{
Serial.begin(9600);
}
void loop()
{
potVal = analogRead(A0);
if (potVal < 216)
{
potVal = 215;
}
PWM = map(potVal, 215, 1023, 0, 255);
motor.setSpeed(PWM);
Serial.print("Speed Value: ");
Serial.println(PWM);
motor.run(FORWARD);
}
Not sure I completely understand the symptom, but I first have a suggestion to add a couple of print statements to better track the mapping range.
The more I think about it, I think that I may have been backwards in where the 'clamping value' should be applied and that is to the pwm side of the mapping statement, rather then the pot side, that needs to account for the dead zone, if that makes sense.
Why don't you give the below code a try. You may have to adjust the 150 pwm starting value in the mapping statement as before. Note that this way gives full pot travel control also. And as you already found out, the motor voltage you apply sets the max rpm of the motor, so between playing with the motor voltage and the starting pwm value in the mapping statement you should be able to set the speed range you want. TO summarize, the motor voltage applied and the PMW = 255 sets the upper rpm, and pmw minimum value is value where the motor just comes to a stop determines the minimum PMW value to use. Control resolution is the difference between those two values. There will probably be some interaction between the motor voltage applied and the minimum pwm value to use, so first set the motor voltage with pwm at max 255 count, and then adjust the pwm low value. If you should set these values with the motor under load or unloaded is something you may have to play with, as you may want the best resolution control under loaded conditions rather the unloaded. Only you can make that call as you better understand the mechanical part of your project.
There is no software magic that can increase the resolution, or rather discrete rpm values attainable. Only a PWM with more then 8 bits could improve that. Looks like you will be in the ball park of 100 discrete steps of speed control ( 255-150 = 105 steps) which maybe fine (that's 1% resolution) depending on what the heck you are doing with the motors.
#include <AFMotor.h>
AF_DCMotor motor(1, MOTOR12_64KHZ);
int potVal = 0;
int PWM = 0;
void setup()
{
Serial.begin(9600);
}
void loop()
{
potVal = analogRead(A0);
PWM = map(potVal, [glow]0, 1023, 150, 255[/glow]); //0-150 pwm dead to motor
motor.setSpeed(PWM);
Serial.print("Pot Value: "); [glow]// print pot position[/glow]
Serial.println(potVal);
Serial.print("Speed Value: "); // print motor voltage (pwm)
Serial.println(PWM);
motor.run(FORWARD);
}
Lefty
Lefty, you are the man! I was racking my brain for an hour trying to figure out why this didn't work and finally decided to go to bed and sleep on it. Lo and behold, this morning you already had the answer!
What you wrote makes perfect sense. I was thinking about the clamping incorrectly and applied it to the input rather than the output. I did like you said and found the voltage and PWM settings that worked best and applied the potVal mapping to this range, which in my case was .6v at PWM of 40 and 4v at PWM of 255. The pot travels the entire distance and gives very fine control over the low-end speed. So, in the end, I got 215 steps of PWM resolution controlled over 1024 steps of analog resolution, which gave me excellent control. I realize I'll have to adjust these once the load is applied but I at least now have a working model.
I'm sorry if I've been sketchy or silent on the mechanical details, but I'm an independent inventor/product developer and the legal issues as such that it could be very risky for me give any details here. I'm not really afraid of someone stealing the idea, as there's a lot that has to be worked out, but more so afraid of the US Patent Office's strict rules regarding disclosure. Posting any details in a public area could constitute a public showing, offering, or disclosure and thus negate my ability to patent the invention or even any parts I describe. Their guidelines on what constitutes "public" are very vague, but from the books I've read it's best not to disclose anything other than to individuals for feedback, work-product, or assistance until I have filed my provisional patent application, which would then give me patent-pending rights.
I really can't thank you enough for all your help. If I manage to make any money off this invention (or any of the others in the pipeline) I'll put a big fat "Courtesy of Lefty!" sign on the packaging and cut you a check. Until then, you have my gratitude.
BTW, did I mention that you're the man?!
Glad you got it resolved and again your very welcome. You are giving me much too much credit as I'm still learning the C programming language, as electronics hardware is where my experience lies.
Any credit due is to the Arduino community that allows people needing help to be coupled with people possibley just a little ahead of them on the grand Arduino learning curve.
Good luck on this project and your other endeavors.
Lefty