Professional Documents
Culture Documents
AboutMe
Photography
Projects
15
Not being happy with the ability to only move a minimum of 1 degree and only at a single speed for my time-lapse automaton project, decided to
hack up my pan servo and get a little more control over it via the arduino directly.
The basic idea is to remove the controller from a servo entirely, modify the gears for continuous movement by removing any stop pins, and attach
the potentiometer directly to the arduino. If we then attach the motor to a motor controller (in my case, an L298 Compact Motor Controller) we
can now control direction and speed. By using analogRead() with the wiper of the potentiometer, well have 1024 discreet positions we can read in a
single rotation. Or, about 0.35 degrees as a minimum movement.
Its possible to use this same code and wiring to turn any old DC motor and a potentiometer into a servo by attaching the nal drive-gear of your
motor or project to the shaft of the potentiometer in such a way that it rotates perfectly with the nal drive gear.
This code uses a basic method to avoid the jitter youll get with the analog potentiometer of averaging and canceling out repetition. A number of
readings are averaged, and if the same average occurs in either of the previous two readings, then the difference in position is not recorded.
Otherwise, we use the average reading to determine our current position, and the difference to determine how far we have moved since our last
valid reading.
For mine, I modied an HS-645MG motor that came with the SPG645S kit. I used the potentiometer with the kit, as it mounts in the shaft with a slipcollar to prevent damaging the pot if you attempt to go past its stop. If you were to use a continuous-rotation pot, you could, perceivably, rotate
innitely. For my purposes, one rotation is enough, and the point is to be able to rotate very slowly while still being aware of our position. I nd that
I am able to move exactly one reading value (1024 steps) between each delay in movement, and delay up to nine hours. Your mileage may vary
based on your hardware and other code running.
The code and a wiring diagram are behind the cut:
Heres a diagram of how everything is wired for this sketch. Youll need to click on it to see the entire image.
Edit: 7/25/08 It seems that WordPress had completely eaten my source code when posted. After some searching, I found a new way of doing it.
While it isnt perfect, code portions are no longer eaten up. For best results click on view plain below.
Addendum: there were two bugs preventing full READ_AVG resolution, one was in the division of the total ( tot / READ_AVG shouldve been tot /
READ_AVG + 1), and the other was when re-setting step counter upon reaching READ_AVG, it had to be re-set to -1 to account for the postincrement operation at the end of read_pot().
1
2
3
4
5
/*
DIYServo1.0
ControllerMotorSpeedandMovementwithAbsolutePositioning
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
AsketchforturningastandardDCgearmotorintoaservo
usingapotentiometer.Canalsobeusedtoaddfinergrained
controloverexistingservos.
Controlovermotor:
Speed(PWM)
Direction
Numberofdegreestomove(upto1024)permove
Howtolongtowaitbetweenmoves
Togetfinercontrol(1024degrees,insteadof360)ofanexisting
servo,removethecontrollerandanystoppins,disconnectthe
potentiometerwires.Connectpowerlinesfromservomotortoa
DCmotorcontroller,potentiometerwipertoaninputpinonthearduino,
andtheousidepotentiometerpinsto5v/GND.
Serialmonitor:
use'l'totelltheservotomoveleft
use'r'totelltheservotomoveright
use's'tostoptheservo
use'g'togo(runtheservo)
(c)2008C.A.Churchwww.dronecolony.com
7/24/08initialversion
*/
//USING_CONTROLLERsayswhetherwehavetobringan
//enablepinhigh(suchasfortheCompactL298controller)
//beforesendingPWMdowntheLT/RTpins
//setthisto0ifyoudon'tneedanenablepin
#defineUSING_CONTROLLER1
//enablepin
#defineMOTOR_EN_PIN8
//rightdirectionpin
#defineMOTOR_RT_PIN6
//leftdirectionpin
#defineMOTOR_LT_PIN9
//READ_AVGishowmanyreadingstoaverage
//setittoonelessthantheactual#
//e.g.:10readings=setto9
//
//themoreyouaverage,themoreaccurateyourreadingislikelyto
//betoomanythough,andyou'llstartmissingchangesifthemotor
//ismovingquickly
#defineREAD_AVG9
//motorspeedisfrom0255,testwithlowvalues
//asnotallwillmoveconsistentlyforyou
intmotor_speed=75;
//howmanymstopausebetweenallowedmovements
intmotor_pause_tm=1000;
//howmany'degrees'(absolutedifferencesbetween
//potentiometerreadings)tomovebeforepausing
intmotor_move_deg=5;
//acounterforhowmanydegreeswehavemoved
intmove_deg_cnt=0;
//settingtoadefaultvalue
intmotor_cur_pin=MOTOR_RT_PIN;
//controlindicators
boolmotor_started=false;
boolmotor_paused=false;
boolfirst_run=true;
boolmotor_run=false;
longpaused_tm;
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
//ourcurrentandpreviouspotentiometerreadings
intcur_reading=0;
intpre_reading=0;
intsteps=0;
//ourcurrentreadingsarray,andourpreviousaveragereadingsarray
intvals[READ_AVG+1];
intprev_posts[2]={0,0};
voidsetup(){
Serial.begin(19200);
Serial.println("Ready");
memset((char*)vals,0,sizeof(int)*(READ_AVG+1));
//setmotorcontrolpins
if(USING_CONTROLLER)
digitalWrite(MOTOR_EN_PIN,HIGH);
digitalWrite(MOTOR_LT_PIN,LOW);
digitalWrite(MOTOR_RT_PIN,LOW);
voidloop(){
//seeifanyinputhascomeintheserialport
check_input();
//figureouthowmanydegreeswe'vemoved(ifatall)
move_deg_cnt=move_deg_cnt+read_pot();
if(motor_run==true){
//ifthemotorissupposedtoberunning
//thefollowingcheckistopreventattemptingtorotateallthe
//wayaroundonapotentiometerthathasastop.Ifyoursdoesn't
//haveastopinit,oucanremovethischeck
if((motor_cur_pin==MOTOR_RT_PIN&&prev_posts[1]>=1020)||
(motor_cur_pin==MOTOR_LT_PIN&&prev_posts[1]<=3)){
//we'vereachedourmaximumpoint(don'twanttoharmour
//potentiometer
motor_run=false;
motor_started=false;
motor_paused=false;
//bringpinlow
digitalWrite(motor_cur_pin,LOW);
//printstatus
Serial.println("HaveReachedEdgeofMovement");
}
elseif(motor_started==false){
//themotorissupposedtoberunning,butwehaven'tstarted
//ityet
//PWMoutput
analogWrite(motor_cur_pin,motor_speed);
//setstatusvalues
motor_started=true;
motor_paused=false;
first_run=true;
}
elseif(move_deg_cnt>=motor_move_deg&&motor_paused==false&&first_run==false){
//we'vegoneourspecific#ofdegrees,pausebystoppingthe
//motor
Serial.println("Pausing");
digitalWrite(motor_cur_pin,LOW);
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
motor_paused=true;
//recordwhenwestartedourpause(soweknowwhentostop)
paused_tm=millis();
}
elseif(motor_paused==true&&(millis()paused_tm)>motor_pause_tm){
//ifenoughtimehaspassedtostoppausing
Serial.println("Unpausing");
motor_paused=false;
paused_tm=millis();
//setmove_deg_cnttozerowhenrestartingtoavoidany
//jitterwhilepaused
move_deg_cnt=0;
//generatePWM
analogWrite(motor_cur_pin,motor_speed);
}
}
intread_pot(){
//readthevoltageonthepotentiometer:
cur_reading=analogRead(0);
intdiff=0;
//we'regoingtoaveragethelastREAD_AVGreads
//putinavalueforourcurrentstep
vals[steps]=cur_reading;
//ifwe'vesavedenoughvaluestogoaheadandperformanaverage...
if(steps==READ_AVG){
//resetourreadcounter
steps=1;
//determinetheaveragevalueread
//thisismostlytodealwithbigjitter
inttot=0;
intavg=0;
//sumuptotals
for(inti=0;i<=READ_AVG;i++)
tot+=vals[i];
avg=tot/READ_AVG+1;
//ignorecurrentreadingifitwaseitherofourlasttworeadings
//avoidbouncingbackandforthbetweentworeadings(slightvoltage
//variationinthesamerange)
if(avg==prev_posts[0]||avg==prev_posts[1]){
return(0);
}
//determinetheabsolutedifferencebetweenthecurrentaverage
//andthepreviousaverage
diff=avg>prev_posts[1]?avgprev_posts[1]:prev_posts[1]avg;
//ifthere'sadifferencebetweentheaverages
if(diff>0){
//printournewreading
Serial.println(avg,DEC);
//moveourlastreadingback,andputourcurrentreadingin
//ourarraytotrackthelasttwopositions
prev_posts[0]=prev_posts[1];
prev_posts[1]=avg;
//updatethissothepausecheckknowsthatwehavechangedaposition
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
//(otherwise,startinginapositionoherthan0willmessupour
//pausecheck)
first_run=false;
}
//incrementoursavedvalue#forthenextloop
steps++;
//returnthedifferencerecorded
return(diff);
voidcheck_input(){
if(Serial.available()){
charch=Serial.read();
switch(ch){
case'g':
Serial.println("GoRunningMotor");
motor_run=true;
digitalWrite(13,HIGH);
break;
case's':
Serial.println("StoppingMotor");
motor_run=false;
motor_started=false;
analogWrite(motor_cur_pin,0);
digitalWrite(13,LOW);
break;
case'l':
motor_cur_pin=MOTOR_LT_PIN;
Serial.println("Direction=LEFT");
break;
case'r':
motor_cur_pin=MOTOR_RT_PIN;
Serial.println("Direction=RIGHT");
break;
}
}
}
Reply
Im kinda hoping that my project will also allow time lapse work with 8 microsteps, I get .8 resolution on the
stepper which is then geared to my drive wheel (not sure of ratio).
Im thinking of also doing multipass video shots and mixing them. We have a massive 10m tidal range (low to
high water). Id really like to shoot a moco shot of the tide coming in and out.
Reply
Marcel
A couple of points that may help you a good deal (Ill be posting this info up in much more detail later this
week, with photos and instructions when my new gears come in the mail.)
If you hook up your potentiometer to your nal drive gear, youll divide your measurable motion points by
1024 so, at 360 degrees / 1024 == 0.35 deg minimum movement. However, I can tell you with quite a bit of
authority (ran the test this weekend) @ 17mm F/L 0.35 deg is WAY too big of a movement to be smooth. In fact,
its quite jumpy.
However, if you gear down (slow down) the nal output gear relative to the motors shaft or input gear, you can
if(cur_value<last_value){
//calculatetheabsolutedifferenceinvaluesread
diff=(1024last_value)+cur_value;
//updatecountoftotalrotations
rotations++;
}
Does that help? I think my thoughts were a little rambling there, but it starts to make a lot of sense after a while.
By measuring the rotation with potentiometers, you get out of the realm of continuous motion, and into a
specied amount of motion between shots.
!c
Reply
Does the round-the-clock count work out accurate (precise) enough? Why not use a stepper or an encoder of
some sort? Cost?
Trying to get my buttons and LCD into a case of some description. Im using a VGA cable to communicate back
to the Arduino on the dolly. That way i can unplug once its programmed if needed or use a longer VGA cable if
needed. Ive been stripping a scanner to get some wires to hook up the LCD what fun!
[m]
Reply
Marcel, yes, it was all about cost and utilizing the equipment I had on-hand. Unfortunately, the tiny pots they
use inside servos cannot effectively be modied (without serious effort, at least!) due to the wire-arms they
use as wipers they end up shorting the +5v to GND when one goes all the way around.
There would denitely be some lack of accuracy in the 10-20 degrees between the left and right contacts, in a
best case scenario youd have a oating input leading to random reads, which could easily be compensated for
in software, if need be. (You would simply know Im in this region, heading for 0 or 1024 depending on
direction. )
Its funny that you should mention steppers, I found some attached to some cool pumps I picked up recently at
the electronics store, and I might use them for pan/tilt. Picked up a more powerful one as well for $9 used.
Went ahead and ordered that stepper controller you mentioned. Essentially, Ill be replacing all of the servos
and DC motors w/ steppers, as the rest of this stuff is too much work, and my September deadline is
approaching =) So, w/ 1.8 deg stepper, 8 microstepping and 3-1 gearing (what Ill have available for this setup),
that gets me 1.8 / 8 / 3 = 0.075 degrees/movement. Which should be acceptable. With a few more bucks and a
little more fabricating, I can go to 9:1 gearing, giving 0.025 deg/move.
The VGA cable is a good idea I have a second arduino coming in, therell be one driving the motors / camera,
and one driving the UI. Im having the UI part in a separate hand-held case, and was considering using a USB
cable to connect the two. I dont need many wires between, as I intend to use i2c to communicate between the
arduinos. But the UI needs to be connected as stop/start is handled by it, and status (position of each motor)
will be displayed on the UI.
The motor controllers, all power distribution, etc. will be housed inside of the case holding the truck motor on
one end of the track.
Its funny you mention cables, as I spent some time making a few last night for the LCD, keypad, and power on
the
UI
board.
I
used
the
straight,
friction-lock
male
PCB
ends
like
these
:
http://www.jameco.com/webapp/wcs/stores/servlet/ProductDisplay?
langId=-1&storeId=10001&catalogId=10001&productId=687885
Just soldered the wires onto the PCB end, and then used some shrink-wrap to tidy them up. They look very
good and only cost me a few cents a piece. The connectors stay in pretty tight as well, as the friction-lock
plates press on the arduinos female headers. For the arduino side, I just got 1 six pins, 2 8 pins, and 2 2 pins (for
vin/gnd and 5v/gnd).
!c
Reply
Im glad things are moving forward for you c. (is that Chris, Cecil, Cuthbert??)
I spent a while yesterday rewiring my LCD. I had it all sorted originally but when I came to think about casing
my display and controls I found I was about an inch short. Damn! It took me ages to unsolder and re-solder it
all. Im not very fast. Next job is to put the pair in a case of some sort. Its going to be rough!
You may nd that with the steppers you will be able to run them fast during your setup so you can preview
your start and end points which could be handy, then ip it over to your super slow mode at runtime.
This is the rst time Ive used steppers and Ive been blown away by them. The EasyDriver board (glad thats
been of use to you) makes it SO easy(!) to use them.
I had a couple of old Lexmark Optra C laser printers a little while back. Printers are a great source of steppers! I
just dont have a lot of options for swapping gears in and out the motor has a cog xed to the shaft.
Ive not got much of a budget for this so like you Im trying to use whats to hand!
All the best.
May all your solder joints be good ones!
[m]
Reply
Reply
c.a. church - March 4, 2010
Maria, sorry for the slow response, your comment got locked up in my spam folder (dunno why thats a
rst!).
Anyhow, you have numerous options, you could have a supported shaft, with one end going beyond the
support, and then either couple your potentiometer to the shaft, or use a hollow shaft with an ID larger
than the OD of your POT shaft and use a small amount of rubber material to create a tight t.
Alternatively, you can use a shaft with one end drilled and tapped, and then match it to a POT with a
threaded shaft, using a little low-strength thread-sealer to prevent it from working loose.
Of course, theres yet another option of the shaft being the actual POT shaft, if it can handle the load.
!c
Reply
hello,
does your self made servo motor have brake function? I mean when certain angle is achieved, the shaft stops
and freezes at that particular angle in rm way; which cannot be affected if someone tries to push using nger?
Reply
Reply
Hi guys,
My apologies, I know this is an old post. I am working on a project in which I turn small mirrors to face the sun
using sensors. I was using servos, but I needed more than the usual voltage to drive them to move the heavy
mirrors, so I burnt out the internal control chip.
I used an L298N chip to drive the motor + gear box directly and then use the external solar sensors to tell the
motor to go clockwise/anti-clockwise, stop, etc. What I cant make it do is resist a change in the desired
position of the motor shaft once the position has been attained (like a normal Servo does if you try to force it by
hand to change position once an angle is set). This is important for me, since the mirrors try to fall down
because of their own weight and I need the modied Servo to stay and resist this change unless I give it a
command to change position.
Thanks so much,
Kind regards,
Nooman
Reply
Church - September 2, 2013
Nooman,
Are you using the braking mode of the L298N when stopped? If not, try enabling it nearly all H-Bridge
drivers, AFAIK, have a braking mode. If your payload is still too heavy to prevent movement when braking,
you can always do like a normal servo controller, and constantly check the position of the motor via a PID
loop (its possible to not use a PID loop, but you may end up with jitter and lots of back-and-forth
movement). There is a PID library for Arduino here: Arduino PID Library
Reply
Nooman Mufti - September 2, 2013
Dear Church,
Thanks so much for your super prompt advise. I really appreciate it. The brake function is what I
initially thought would work,essentially I set the Enable pin as high and both inputs to the motor as
High, but it doesnt freeze the motor, which essentially just freely moves. I see some other people on
the net have had issues with L293D as well, so it may be a similar problem. Some people suggest
using L6202 (MOSFET based) which denitely does a brake to address this issue
(http://www.avrfreaks.net/index.php?name=PNphpBB2&le=printview&t=22646&start=0)
I was thinking I could just get away with the motor doing an innite oscillation (clock, anticlockwise
motion) once it reaches the desired position (using the solar angle sensors I have). But I think at the
entire setups tipping point, the thing would fall then come back and so forthlots of big jitters, unless
of course, I can do a full brake somehow.maybe I can keep a very low tolerance (super small error)
in my solar angle sensors, so that it can do these innite clockwise/anticlocks at the desired
position/angle (sounds terrible, I know)..maybe I need to try another motor controller chip ?
I will try your other suggestion about the PID as well. I have also ordered another continuous rotation
servo, but from past experience, I need more torque than they can provide at 7 V, so I would need to
overvolt them, thereby burning the control chip againso an external motor control chip with a heat
sink is perhaps the only way to go.
Thanks so much again,
Kind regards,
Nooman
Reply
Leave A Reply
Name (required)
Mail (will not be published) (required)
Website
SubmitComment