Test circuit for MD20A with feedback pot

lbenson

Senior Member
Where is the best place to insert it?
As in post 78, "Try this replacing ... ".

But if it's too course-grained (doesn't fix the problem), you should try AllyCat's proposal.

Depending on your timing (how fast the motor moves vs how fast the READADC performs), you could, for instance, have a loop which reads the ADC 10 times keeping track of high and low values and summing the READADC results in a word variable, subtracting the high and low values and dividing by 8. That should give you more stable ADC values for the feedback and desired pots.
 

Gramps

Senior Member
The limits are jittery in the terminal window but actual movement of the arm is steady.
I appreciate you guys refining the code but i;m just going to use it like it is!
Edit:
When we add:
INIT: pwmout MOTOR, 199, MAXPWMVALUE 'Energize Motor controller
The motor seems to respond a little more lively!
 
Last edited:

lbenson

Senior Member
When we add:
INIT: pwmout MOTOR, 199, MAXPWMVALUE 'Energize Motor controller
The motor seems to respond a little more lively!
There's no reason evident to me why that should make the motor any more lively than the identical PWMOUT statement towards the end of the program. Please post current code.

If "pwmout MOTOR, 199, 200" slows it down too much as you're approaching the STOP point, try 199,300

Also please post a snippet of the SERTXD output as you are approaching the STOP point.
 

lbenson

Senior Member
I'm not sure what we're seeing in the Serial Terminal window. Is the pot reading bouncing back and forth between 35 and 40? That's a big amount of regularly repeating jitter. I don't know what that would mean--but averaging might fix it.

What I was looking for was what the SERTXD output is as the STOP point is approached. So if you move the desired_pot far enough so that it's set to your limit, what happens from just before when the reading first hits 11 to when it stops? In the Serial Terminal window, if you click the <Copy> button, the text in the window will be copied to the paste buffer. If you then open a text editor like notepad, and then <Ctrl-V> to paste, you can select the output from just above a reading of 11 to where it stops, and then paste that into a forum edit window.

You might replace the two SERTXD statements with a single one (replacing the second) like this:

sertxd("Desired/Feedback: ",#desired_pot_value," ",#feedback_pot_value,13,10)
 

premelec

Senior Member
READADC is ratiometric so the V- & V+ that go to the pot should be identical to V- & V+ pins on PICAXE - then perhaps if there is noise on the power line from motor currents it might get washed out in the ADC reading... ;-0
 

Gramps

Senior Member
You might replace the two SERTXD statements
Okay. Hopefully we'll get to try that today.
What we are seeing is the motor controller is moving the arm at a steady rate up to the end limit and stopping perfectly in both directions.
We put an LED across the pwm output .
It's steady as the arm moves toward the limit then blinking as it approaches the end and then going out as the limit is reached.

We are delighted with the way it's operating!
 

Gramps

Senior Member
there is noise on the power line from motor currents
I was wondering if that was the case. Today we will test the system with the motor disconnected.
We do have caps across the motor Terminals and where the picaxe power supply connects to the chip
 

Gramps

Senior Member
You might replace the two SERTXD statements with a single one (replacing the second) like this:
sertxd("Desired/Feedback: ",#desired_pot_value," ",#feedback_pot_value,13,10)
DONE!
Here are the results copied from Notepad
"Feedback" never seems to catch up with "desired" beacause of the "diff" command.
Desired/Feedback: 210 201 is at the end of the range the motor can move.


Desired/Feedback: 210 191
Desired/Feedback: 210 192
Desired/Feedback: 210 192
Desired/Feedback: 210 192
Desired/Feedback: 210 192
Desired/Feedback: 210 192
Desired/Feedback: 210 192
Desired/Feedback: 210 193
Desired/Feedback: 210 193
Desired/Feedback: 210 194
Desired/Feedback: 210 194
Desired/Feedback: 210 194
Desired/Feedback: 210 194
Desired/Feedback: 210 194
Desired/Feedback: 210 194
Desired/Feedback: 210 194
Desired/Feedback: 210 195
Desired/Feedback: 210 195
Desired/Feedback: 210 195
Desired/Feedback: 210 195
Desired/Feedback: 210 195
Desired/Feedback: 210 195
Desired/Feedback: 210 195
Desired/Feedback: 210 195
Desired/Feedback: 210 196
Desired/Feedback: 210 196
Desired/Feedback: 210 196
Desired/Feedback: 210 196
Desired/Feedback: 210 196
Desired/Feedback: 210 196
Desired/Feedback: 210 197
Desired/Feedback: 210 197
Desired/Feedback: 210 197
Desired/Feedback: 210 197
Desired/Feedback: 210 197
Desired/Feedback: 210 197
Desired/Feedback: 210 197
Desired/Feedback: 210 198
Desired/Feedback: 210 198
Desired/Feedback: 210 198
Desired/Feedback: 210 198
Desired/Feedback: 210 198
Desired/Feedback: 210 198
Desired/Feedback: 210 199
Desired/Feedback: 210 199
Desired/Feedback: 210 200
Desired/Feedback: 210 199
Desired/Feedback: 210 199
Desired/Feedback: 210 200
Desired/Feedback: 210 200
Desired/Feedback: 210 201
 
Last edited:

lbenson

Senior Member
Post the current code (after suggested change). With the stepdown to half speed and new 2nd diff comparison you should be getting closer than 9.

Here's a little more discrimination for the SERTXD. First define new variables (making sure b5 and b6 aren't being used--change as needed:

Symbol old_feedback value=b5 ' assuming b5 isn't being used
Symbol old_desired value=b6 ' assuming b6 isn't being used

Then replace the SERTXD statement with
Code:
If old_feedback value<>feedback_pot_value or old_desired value<>desired_pot_value then
  old_feedback value=feedback_pot_value
  old_desired value=desired_pot_value
  sertxd("Desired/Feedback: ",#desired_pot_value," ",#feedback_pot_value,13,10) 
endif
(Indent properly to show blocks of code.)
Also post new SERTXD output. You have a bit of dithering with your desired_pot_value, but it either won't matter or we can fix it by averaging.
 

AllyCat

Senior Member
Hi,
"Feedback" never seems to catch up with "desired" beacause of the "diff" command.
Desired/Feedback: 210 201 is at the end of the range the motor can move.
Then it's not operating correctly as a "Servo". But I'm sorry, I can't explain any better/more than already in #31, #69 and #80 etc., which IMHO is far easier than bolting in more and more IF .. THENs (except for an IF . THEN to prevent the the SERTXD outputting data on every pass around the loop).

Cheers, Alan.
 

Gramps

Senior Member
Symbol old_feedback value=b5 ' assuming b5 isn't being used
Symbol old_desired value=b6 ' assuming b6 isn't being used
Code created syntax error:
Replaced with:
old_feedback_value
old_desired_value
Next inserted new code:
With symbol correction
post new SERTXD output.
We lowered the high end limit to 180 so we do not hit the limit of travel.
Looks PRETTY NICE!!!!

Desired/Feedback: 151 176
Desired/Feedback: 180 176
Desired/Feedback: 146 175
Desired/Feedback: 180 176
Desired/Feedback: 180 175
Desired/Feedback: 180 176
Desired/Feedback: 180 175
Desired/Feedback: 180 176
Desired/Feedback: 180 175
Desired/Feedback: 180 176
Desired/Feedback: 180 175
Desired/Feedback: 180 176
Desired/Feedback: 180 175
Desired/Feedback: 180 176
 

Gramps

Senior Member
Updated code.
Code:
'Shadow-Bot feedback control code with limits the best one!!!
#picaxe 28x2
#no_data
#no_table

symbol xb0 = b0 ' reserved for bit variables
symbol bReverseForward=bit1 ' 0=reverse,=forward
symbol bMotorState=bit0     ' 0=off,1=on
symbol REVERSE_=0
symbol FORWARD_=1
Symbol desired_pot_value = b1
Symbol feedback_pot_value = b3
Symbol diff=b4
Symbol  desired_pot = 13 'B.5
Symbol  feedback_pot = 11'B.4
Symbol MOTOR = B.0' Energize PWM
Symbol Direction = B.7
Symbol MAXPWMVALUE = 399
Symbol bSlowState=bit2
Symbol old_feedback_value= b5
Symbol old_desired_value= b6 
Symbol ENDSTOP_A  = 35 ; desired_pot MINimum value
Symbol ENDSTOP_C = 180 ; desired_pot MAXimum value
;Lower shoulder min=35 max=210
;Upper shoulder min=?? max=???

Main:
  Readadc Desired_pot, desired_pot_value
    Desired_pot_value = Desired_pot_value MIN ENDSTOP_A MAX ENDSTOP_C
    'sertxd (#desired_pot_value," ",#b1,13,10)
    Readadc feedback_pot, feedback_pot_value
   ' sertxd (#feedback_pot_value," ",#b3,13,10)
  'sertxd("Desired/Feedback: ",#desired_pot_value," ",#feedback_pot_value,13,10)
  If old_feedback_value<>feedback_pot_value or old_desired_value<> desired_pot_value then
  old_feedback_value=feedback_pot_value
  old_desired_value=desired_pot_value
  sertxd("Desired/Feedback: ",#desired_pot_value," ",#feedback_pot_value,13,10)
endif
if desired_pot_value > feedback_pot_value then
   diff=desired_pot_value - feedback_pot_value
   else
   diff=feedback_pot_value - desired_pot_value
endif
if diff < 12 then ' from 11 below a match to 11 above
  if bMotorState=1 then
    if diff > 4 then ' this value may need to be set experimentally
      if bSlowState = 0 then
        bSlowState = 1 ' note that we are in the "slow speed" state
        pwmout MOTOR, 199, 300 ' slow down to half speed (change to 100 if necessary)
      endif
    else
      pwmout MOTOR, OFF ' STOP
      bMotorState=0
      bSlowState = 0
    endif
  endif
else ' motor must be set for proper direction and then activated
  if  desired_pot_value > feedback_pot_value then
    if bReverseForward = REVERSE_ then
      high Direction ' go forward
      bReverseForward = FORWARD_
    endif
  elseif  desired_pot_value < feedback_pot_value then
    if bReverseForward = FORWARD_ then
      low Direction ' go in reverse
      bReverseForward = REVERSE_
  endif
  endif
  if bMotorState=0 then
    bMotorState=1
    pwmout MOTOR, 199, MAXPWMVALUE' rotate Reverse
  endif
endif

goto main
 
Last edited:

AllyCat

Senior Member
Hi,

The "Magic Numbers" are creeping back in, so first I'd formalise (and refine) the Symbols with:
Code:
symbol DEADZONE = 4   ; Switch motor off (Make as small as practical)
symbol SLOWZONE = 12  ; Slow motor down (NB: May depend on motor speed ! )
symbol MotorSpeed  = w4  ; (To replace the "300" in the present PWMOUT code)
symbol LOOPGAIN = 33      ;  i.e.  MAXPWMVALUE / SLOWZONE (= 399 / 12)
symbol PWMPERIOD = 199   ; Equivalent Max Duty Cycle is 799
Then try replacing ALL of the following:
Code:
if diff < 12 then ' from 11 below a match to 11 above
  if bMotorState=1 then
    if diff > 4 then ' this value may need to be set experimentally
      if bSlowState = 0 then
        bSlowState = 1 ' note that we are in the "slow speed" state
        pwmout MOTOR, 199, 300 ' slow down to half speed (change to 100 if necessary)
      endif
    else
      pwmout MOTOR, OFF ' STOP
      bMotorState=0
      bSlowState = 0
    endif
  endif
else ' motor must be set for proper direction and then activated
  if  desired_pot_value > feedback_pot_value then
    if bReverseForward = REVERSE_ then
      high Direction ' go forward
      bReverseForward = FORWARD_
    endif
  elseif  desired_pot_value < feedback_pot_value then
    if bReverseForward = FORWARD_ then
      low Direction ' go in reverse
      bReverseForward = REVERSE_
  endif
  endif
  if bMotorState=0 then
    bMotorState=1
    pwmout MOTOR, 199, MAXPWMVALUE' rotate Reverse
  endif
with (untested) :
Code:
  if diff > DEADZONE then
    MotorSpeed = diff * LOOPGAIN max MAXPWMVALUE  ; Limits speed outside of SLOWZONE
    if  desired_pot_value > feedback_pot_value then
      high Direction       ; Set forward direction
    else
      low Direction        ; Set reverse direction
    endif
    pwmout MOTOR , PWMPERIOD , MotorSpeed     ; Slows motor within SLOWZONE
  else
    pwmout MOTOR , OFF         ; STOP
    bMotorState=0      ; Not sure what these do (now)
    bSlowState = 0      ;
  endif
I'm not sure if that then needs another endif before the final goto main (because the indenting appears to have "slipped").

Cheers, Alan.
 
Last edited:

lbenson

Senior Member
Looking pretty good. Sometimes "close" is good enough. If it turns out not to be, there's Alan's method to look into.

If the dithering of feedback between 175 and 176 bothers you , I can suggest pot averaging code, or band detecting, but there appears to be no practical penalty.

I'd also suggest experimenting with the DEADZONE value--try moving it to 3 or maybe 2. It depends on how fast your main loop is executing compared to how fast the motor is moving towards the desired value.
symbol DEADZONE = 4 ; Switch motor off (Make as small as practical)
 

Gramps

Senior Member
Alan, we'll try to test the code this evening.
I really appreciate you guys perfecting the code but the customer was satisfied at post 96!
What a learning experience this has been since we wrote
The objective here was to get the motor to stop when b1 and b3 are equal.
 

Gramps

Senior Member
Test with Alan's new snippet.

Edit: Old copy and paste was not accurate!

Desired/Feedback: 196 200
Desired/Feedback: 197 200
Desired/Feedback: 198 200
Desired/Feedback: 199 200
Desired/Feedback: 198 200
Desired/Feedback: 199 200
Desired/Feedback: 199 201
Desired/Feedback: 199 200
 
Last edited:

AllyCat

Senior Member
Hi,

I'm not sure what that shows (as it's the Desired that's changing and not the Feedback), I would have expected to see a "step change" in the Desired (e.g. 196 changing to 150) and then the Feedback changing (more slowly) until it "catches up", perhaps after a slight overshoot. You should be able to control the degree of overshoot (sometimes a small amount is desirable) by changing the value of LOOPGAIN. I would expect the value of DEADZONE could be zero (or at most 1) because the comparison (for the motor to run) is diff > (greater than) DEADZONE, so the motor should still be OFF if the pot values are truly equal. 1 might be needed if the pot values are dithering (and can't be corrected by averaging, or by a small time delay).

There is one more addition that I'd make (excluding the PI control suggestion in #44) , to add another Magic Number e.g. called CREEP or CRAWL, which would be the lowest PWM value at which the motor continues to move (or perhaps is able to restart moving under load). Thus add an extra program line such as: Symbol CREEP = 100 ; PWM value for minimum speed (comment), and add a MINimum to the Motor Speed calculation, i.e.: MotorSpeed = diff * LOOPGAIN max MAXPWMVALUE min CREEP ; Limit range of motor speed (comment). That should ensure that the motor always gets to the "zero error" position, eventually.

Cheers, Alan.
 

Gramps

Senior Member
There is one more addition that I'd make
I will be glad to try the code but please write it as you want it implemented thanks!
The model is smoothly moving along, stopping, starting and reversing nicely on both 6 and 12 volts.
 

lbenson

Senior Member
If both pots are dithering by one, then I would expect that you would need a deadzone of 2, since a diff of 0 could become a diff of 2 if one pot dithered in on direction and the other in the opposite direction.

Agree with Alan that you should determine by testing the smallest pwm value which causes the motor to move, although you will likely find a difference between a value which will enable it to +continue+ moving and a value which will enable it to +start+ moving.
 
Top