Universal Motor Speed Control

From here, I think this code structure should do most of the job you need. You really have three variables/constants that you can use to use to improve speed regulation. These are the Pause value which you have used up until now, now added to that are DecVal and IncVal and the If/ElseIf/Else/EndIf structure branching. With the code you are using now, the "speed up" and "slow down" can be treated separately and you can ignore "speed up" (for example) while your are dealing with correcting the overreving "slow down" algorythm.

What stands out to me most, is the time it takes for the PWM to be cut to zero (or a very low number) when the load is removed. The final branch of the "slow down" algorythm is clearly inadequate at removing power %age quickly. It may be appropriate to add another branch or two to the IF structure to assign a larger range range of values to DecVal or IncVal. Alternatively, the final branch in that IF structure could be a much larger DecVal. The MIN operator will stop th PWM value from going negative. Initially, try changing the last branch of the structure (immediately after the "Else" statement) to DecVal = 50 or DecVal = 100 and see if that improves the response to overreving. Once you have improved the response to over reving, you can then deal with managing the speed when a load is applied.

Edit: The suggestion aboves introduces another problem. I'll work out a better solution shortly.

Once you can respond to over- and under-speed effectively, you can look at reducing the pause delay between the test-and-response cycles, speeding up the looping periods.
 
Last edited:
Overnight I realised that having such a large step without a number of ramping steps would introduce another problem. I suuggest you insert this following code to ramp the PWM level up and down, proportionate to the difference.
Rich (BB code):
         If tachovalue > setpointvalue then     'Faster than required
            Difference = tachovalue - setpointvalue
            'Vary the speed step-down value according to the amount of overshoot 
            If Difference < 5 Then              'Difference is between 1 and 4        
               DecVal = 1
            ElseIf Difference < 10 Then         'Difference is between 5 and 9 
               DecVal = 3 
            ElseIf Difference < 20 Then         'Difference is between 10 and 19 
               DecVal = 8 
            ElseIf Difference < 40 Then         'Difference is between 20 and 39
               DecVal = 17 
            ElseIf Difference < 80 Then         'Difference is between 40 and 79
               DecVal = 35
            Else                                'Difference is over 79
               DecVal = 50
            EndIf
            PWMVal = PWMVal MIN DecVal - DecVal 'PWM must not go lower than 0
         ElseIf tachovalue < setpointvalue then 'Slower then required
            'Vary the speed step-up value according to the undershoot amount
            Difference = setpointvalue - tachovalue
            If Difference < 5 Then              'Difference is between 1 and 4        
               IncVal = 1
            ElseIf Difference < 10 Then         'Difference is between 5 and 9 
               IncVal = 3 
            ElseIf Difference < 20 Then         'Difference is between 10 and 19 
               IncVal = 8 
            ElseIf Difference < 40 Then         'Difference is between 20 and 39
               IncVal = 17 
            ElseIf Difference < 80 Then         'Difference is between 40 and 79
               IncVal = 35
            Else                                'Difference is over 79
               IncVal = 50
            EndIf
            SerTxd ("-")                        'Minus: Show speed is slower than required
            PWMVal = PWMVal + IncVal MAX PWMMax 'PWM must not go higher than PWMMax
         EndIf
 
Been a bit of a delay while gathering data and making the graphs but I have them done. The first one is from the original code I started with and since it's only proportional control doesn't have any over shoot. No action is taken when the tachovalue exceeds the setpoint. Full load is removed at around the 560 mark.
The second graph has a differing format since I used the parameters you were tracking in the suggested code. I am happy to graph it in the same format as the original code if you want to compare. This graph begins as full load is removed.
I really like the way your code accelerates the motor towards setpoint under load and maybe it just needs no action to be taken when the tachovalue exceeds the setpointvalue.
 

Attachments

  • 20250319_095621.jpg
    20250319_095621.jpg
    848.6 KB · Views: 4
  • 20250319_095744.jpg
    20250319_095744.jpg
    778.4 KB · Views: 5
Chart 2 suggests to me that it is from the code that I posted in #37. I'm hoping that, when the IF/THEN/ELSEIF/ELSE/ENDIF structure is replaced with my revised version posted in #43, you get an improved result. I think we're on the right track. The idea is to substantually reduce that difference "flatline" (records 38 to 160), before we look at the sinewave-like hunting that occurs when the speed error settles.
 
Here is the result from code #43. I haven't made any changes to the code yet. Still lots of overshoot but for a shorter time.
 

Attachments

  • 20250319_210421.jpg
    20250319_210421.jpg
    777.2 KB · Views: 4
The longer the delay in responding, the greater the overshoot or undershoot will be. Try halving the value of the pause statement - that should speed up the response and therefore reduce the over-/under-shoot.
 
I purchased some UCC23513's as suggested and am now running into some problems with Mosfet failures. I had to change the Zener from the 12V one I was now using, to 14V to overcome the 13.5V uvlo in in the new opto and havn't had a proper run since due to the Mosfets dying. I now plan to return to my 4N35 and 12V zener until we have sorted the software and then I will relook at the Mosfet driver.
 
Last edited:
Yes it was a typo and should have been UCC23513. I have now reverted to the 4N25 and have been testing all day today with different delays and different steps of increase and decrease but with no real improvement except when there is no pause at all. Then the overshoot is reduced and the hunting reduced but very fast. In the morning I will look closer at the figures I recorded so I can present what I see. Because I struggle with the software and understanding I would have liked to have kept the part where you increase the pwm when the motor is slow and reduce the pwm to minimum as the motor reaches the setpoint with no steps at all above that point. That was my idea for today. So it can only rise up to but never exceed the setpoint. A bit like proportional. Because the motor takes a large inrush when starting to full speed I will also need a soft start or I will use have to use parts of some 3 phase bridges 100A 1600V mosfets that I have. I have also edited my #48 post
 
Having no delay statement could very well be part of the solution - you want a quick response.

The next part of the solution would be to change the parameters when Difference is small: like do nothing (make DecVal/IncVal = 0) for differences of just 1 or possibly 2. My selection of values were arbitrary, since your setup is not on my workbench.
 
Sorry for a long delay in giving feedback but I had to do other work. I have spent the last 4 days trying different values of Difference, DecVal and IncVal without any success in reducing the hunting or the problem of overspeed when the load is removed, to acceptable levels. In fact the more I reduce the pause value the worse the hunting becomes. If the delay is larger them so is the overshoot. I did once lessen the hunting but after changing the values so many times I sort of lost my place in the procedure I was following and haven't recovered the values.
So I have decided to stick with the simple proportional code which has no hunting or overshoot and try to improve it and reduce the fall off in speed under load.
Pete, thank you for your efforts and patience in trying to help me.
 
Here's where I'm at with my Universal Motor Controller project. The speed is now controlled with a soft start and the speed range is 2,900 to 10,000. At max speed and with full load the speed drops to 8,900 rpm which is acceptable to me and the best I have been able to achie with my simple program. At lower speeds the torque is reduced slightly because the setpoint is decreasing but I not found how to overcome this yet. The router that I was using previously also has the same speed range using preset R1 and R2 and a better performance since it's only 700W. I am also using a larger mosfet now together with a mosfet driver, which I have never used before. The earlier circuit using a 4N25 also works very well.
What have I learnt from this forum....... there's plenty of help and advise and I have really appreciated it, thank you.

Code:
'Universal Proportional Motor Controller
'Picaxe 0M2 29.03.23. Ver5

symbol setpointport=1
symbol setpointvalue=w0
symbol tachoport=4
symbol Tachovalue=w1
symbol pwmport=2
symbol sum=w2
#no_data
setfreq M32

    let w3=0
    sum=w3
   

init:    readadc10 setpointport, setpointvalue    'get setpoint
    setpointvalue=setpointvalue-4
    readadc10 tachoport, tachovalue        'read tacho
    pwmout pwmdiv16,pwmport,200,w3        'output softstart 
    if tachovalue=>setpointvalue then start    'upto speed yet?
    inc w3                        'next step
    pause 500                        'delay
    goto init                        'loop


   
start:readadc10 setpointport, setpointvalue    'get setpoint
    readadc10 tachoport, tachovalue        'read tacho
    sum=setpointvalue-tachovalue
    if w1>w0 then start                'overspeed
    sum=sum*5      
    pwmout pwmdiv16,pwmport,200,sum        'output pwm
    goto start
   
[code/]
 

Attachments

  • Washing machine motor.jpg
    Washing machine motor.jpg
    682 KB · Views: 8
  • Mosfet driveboard1.jpg
    Mosfet driveboard1.jpg
    775.8 KB · Views: 8
  • Protoboard.jpg
    Protoboard.jpg
    881.1 KB · Views: 9
  • MotorControllerSchematic.jpg
    MotorControllerSchematic.jpg
    753.7 KB · Views: 10
  • FullSpeedLoadTestL.JPG
    FullSpeedLoadTestL.JPG
    99.8 KB · Views: 7
Last edited:
I'm my limited experience, just when I think I have a program right, something pops up to show me, I haven't and today is that day. With my last bit of code I have a line "sum=sum*5. This works really well at full speed where the setpoint and tacho are large numbers but fails at low speed where multiplying the error x5 makes it bigger than the setpoint and control is lost. So I have a new program today which overcomes that problem.
Because I am keen to learn how to do things better I would like to ask inglewoodpete if he would please rewrite my piece of code in the format that he would use? Thank you.
Code:
'Universal Proportional Motor Controller
'Picaxe 0M2 30.03.23. Ver6

symbol setpointport=1
symbol setpointvalue=w0
symbol tachoport=4
symbol Tachovalue=w1
symbol pwmport=2
symbol sum=w2
symbol sw=3
#no_data
setfreq M32

    let w3=0
    sum=w3
    
init:    readadc10 setpointport, setpointvalue    'get setpoint
    setpointvalue=setpointvalue-10
    readadc10 tachoport, tachovalue        'read tacho
    pwmout pwmdiv16,pwmport,200,w3        'output softstart  
    if tachovalue=>setpointvalue then start    'upto speed yet?
    inc w3                        'next step
    pause 1000                        'delay
    'SerTxd (#w3, ", ", #setpointvalue,",", #tachovalue, CR, LF)
    goto init                        'loop

start:'SerTxd (#sum, ", ", #setpointvalue,",", #tachovalue, CR, LF)
    readadc10 setpointport, setpointvalue    'get setpoint
    readadc10 tachoport, tachovalue        'read tacho
    if tachovalue>setpointvalue then start    'do nowt, overspeed
    sum=setpointvalue-tachovalue
    if setpointvalue<380 then x1
    if setpointvalue<480 then x1
    if setpointvalue<580 then x2
    if setpointvalue<700 then x3
    if setpointvalue>700 then x4
    
x1:    sum=sum*1
    pwmout pwmdiv16,pwmport,200,sum        'output pwm
    goto start
x2:   sum=sum*2
    pwmout pwmdiv16,pwmport,200,sum        'output pwm
    goto start
x3:   sum=sum*3
    pwmout pwmdiv16,pwmport,200,sum        'output pwm
    goto start
x4:   sum=sum*4
    pwmout pwmdiv16,pwmport,200,sum        'output pwm
    goto start
x5:   sum=sum*5
    pwmout pwmdiv16,pwmport,200,sum        'output pwm
    goto start
[code\]
 
I'm my limited experience, just when I think I have a program right, something pops up to show me, I haven't and today is that day. With my last bit of code I have a line "sum=sum*5. This works really well at full speed where the setpoint and tacho are large numbers but fails at low speed where multiplying the error x5 makes it bigger than the setpoint and control is lost. So I have a new program today which overcomes that problem.
Because I am keen to learn how to do things better I would like to ask inglewoodpete if he would please rewrite my piece of code in the format that he would use? Thank you.
I have revised your code but can't guarantee that it creates a perfect replication of the original "spaghetti" code.

Rich (BB code):
'Universal Proportional Motor Controller
'Picaxe 0M2 30.03.23. Ver6 Revised

symbol setpointport  = C.1
symbol setpointvalue = w0
symbol tachoport     = C.4
symbol Tachovalue    = w1
symbol pwmport       = C.2
symbol sum           = w2
'symbol sw=3
#no_data

   setfreq M32
   w3 = 0
   sum = w3
   readadc10 setpointport, setpointvalue     'get setpoint
   setpointvalue = setpointvalue - 10

   Do                                        'Soft Start loop
      pause 1000                             'delay 250mS
      pwmout pwmdiv16, pwmport, 200, w3      'output softstart  
      inc w3                                 'next step
      readadc10 tachoport, Tachovalue        'read tacho
      'SerTxd (#w3, ", ", #setpointvalue,",", #tachovalue, CR, LF)
   Loop While Tachovalue < setpointvalue     'Conditional Loop
   
   Do
      'SerTxd (#sum, ", ", #setpointvalue,",", #tachovalue, CR, LF)
      readadc10 setpointport, setpointvalue  'get setpoint
      readadc10 tachoport, Tachovalue        'read tacho
      If Tachovalue <= setpointvalue then    'If underspeed
         sum = setpointvalue - Tachovalue    'Ramp up
         If setpointvalue < 380 then
            sum = sum * 1
         ElseIf setpointvalue < 480 then
            sum = sum * 1
         ElseIf setpointvalue < 580 then
            sum = sum * 2
         ElseIf setpointvalue < 700 then
            sum = sum * 3
         Else
            sum = sum * 4
         EndIf
      EndIf
      pwmout pwmdiv16, pwmport, 200, sum     'output pwm
   Loop                                      'Loop forever
 
Thank you for the new code, it works just as mine did but much better written. I have now discovered another problem, which so far I have not been able to solve. If I quickly change from high to low slow speed the program is sometimes caught in a loop at about 1/2 speed and stops reducing speed and would stay there for ever if I do not increase the speed again above what it's running at, to regain control, and then reduce it again. At the moment I am moving the 'SerTxd line around until I find where it's looping. I will come back with more when I find where the problem is. This started out as such a simple project but seems to be full of traps for new players. Never stop learning is my motto thankfully.
 
The reason I originally suggested my version of the code was that your statement, "sum = setpointvalue - Tachovalue", is flawed. Since you found your original algorythm worked better for you, I decided not to spend my time arguing against it.

If you reduce the setpointvalue to less than Tachovalue, sum goes into negative teritory and the PICAXE's unsigned integer limitation means it is treated as a very large value, beyond what will fit into PWMOut's Duty value's 10-bit limitation. For example 99 - 100 = 65535 which, when input into the PWM Duty register, becomes interpretted as the 10-bit value 1023 (100% PWM). The only reason your original code does not 'hunt' is that the PWM value is unlikely, if ever, to reduce the motor speed - it will depend on the (almost random) value of the lowest 10 bits of the 16-bit positive sum value. My algorythm used the MAX and MIN functions to eliminate these potential overflow/underflow errors, as did breaking the difference between setpointvalue and Tachovalue into two branches (IncVal and DecVal) and never becoming a negative value. To my mind, the solution is to continue with my algorythm but work at adjusting the branching and the applied IncVal and DecVal amounts.

I note that you are running an AC motor on DC, which changes its characteristics. At some point in the future it may be worth trialling it on AC by wiring it outside of the bridge rectifier (on one of the AC feed legs). The MOSFET would remain within the bridge rectifier, so only switch DC. I'm a bit cautious about discussing mains voltages issues on this forum due to the significant number of inexperienced members.
 
Thanks for your reply. I'm not sure about running this universal motor on AC with the mosfet after the bridge since I need the full DC voltage from the filter cap for the mosfet driver. I don't if the driver would work on AC as it would have to be before the bridge. I will give that possibility more thought. Most universal motors will run happily on DC just that the brushes don't last as long.

All I had to do to fix the problem was to turn off the PWM when the tacho was greater than the setpoint, Now it no longer hangs up when the setpoint value is rapidly reduced. It has something to do with the x2 multiplier in the 580 range because if I change the multipliers all to x1 it stopped hanging, however I want to keep the multipliers in to reduce the speed drop off. In fact I think I can increase them to improve. Now I will try to include it in your re write of my code.

I did spend a lot of time trying out your suggested program trying out many combinations of IncVal and DecVal and Difference values without success. If I reduced the hunting by increasing the pause the overshoot increases. I guess it's where integral would come in in a PID controller. But very happy to revisit your program from #43


Code:
'Universal Proportional Motor Controller
'Picaxe 0M2 02.04.23. Ver6.2

symbol setpointport=1
symbol setpointvalue=w0
symbol tachoport=4
symbol Tachovalue=w1
symbol pwmport=2
symbol sum=w2
symbol sw=3
#no_data
setfreq M32

    let w3=0
    sum=w3
    
init:    readadc10 setpointport, setpointvalue    'get setpoint
    setpointvalue=setpointvalue-10
    readadc10 tachoport, tachovalue        'read tacho
    pwmout pwmdiv16,pwmport,200,w3        'output softstart  
    if tachovalue=>setpointvalue then start    'upto speed yet?
    inc w3                        'next step
    pause 1000                        'delay
    'SerTxd (#w3, ", ", #setpointvalue,",", #tachovalue, CR, LF)
    goto init                        'loop

start:'SerTxd (#sum, ", ", #setpointvalue,",", #tachovalue, CR, LF)
    readadc10 setpointport, setpointvalue    'get setpoint
    readadc10 tachoport, tachovalue        'read tacho
    if tachovalue>setpointvalue then over    'do nowt, overspeed
    sum=setpointvalue-tachovalue
    if setpointvalue<380 then x1
    if setpointvalue<480 then x1
    if setpointvalue<580 then x2
    if setpointvalue<700 then x3
    if setpointvalue>700 then x4
    
x1:    sum=sum*1
    pwmout pwmdiv16,pwmport,200,sum        'output pwm
    goto start
x2:   sum=sum*2
    pwmout pwmdiv16,pwmport,200,sum        'output pwm
    goto start
x3:   sum=sum*3
    pwmout pwmdiv16,pwmport,200,sum        'output pwm
    goto start
x4:   sum=sum*4
    pwmout pwmdiv16,pwmport,200,sum        'output pwm
    goto start
x5:   sum=sum*5
    pwmout pwmdiv16,pwmport,200,sum        'output pwm
    goto start
    
over:pwmout c.2,OFF
    goto start
 
I was wondering if I used your #43 program together with "pwmout c.2,OFF" for anything over the setpoint. That might reduce the overshoot and yet still have the speed increase to setpoint under load. I did like the acceleration your program had.
 
Great minds think alike. I have been thinking along the the same lines over the last 2 or 3 days.

Rather than using "pwmout c.2,OFF", replace the algorythm. The following code is a cut-and-paste of posts #29, #43 and your latest suggested change of cutting power when over-speed. You could also add you soft start code before the "Do" statement if you want.
Rich (BB code):
'Universal Motor Controller'
#PICAXE 08M2                  '04-April-2025
#TERMINAL 38400               'For operation at 32MHz
symbol setpointport  = C.1
symbol tachoport     = C.4
symbol pwmport       = C.2
'symbol IncVal        = 1      'PWM step size: Up
'symbol DecVal        = 2      'PWM step size: Down
symbol PWMMax        = 803    'Upper limit of 100% PWM at 2490Hz for PWM period=200

symbol setpointvalue = w0     'setpoint
symbol tachovalue    = w1     'tacho
symbol PWMVal        = w2
symbol Difference    = w3     'Magnitude of error
symbol IncVal        = b8
#no_data

Init: setfreq M32
      readadc10 setpointport, setpointvalue     'read setpoint  
      PWMVal = setpointvalue                    'starting point for actual
      '
      Do
         ReadADC10 setpointport, w0             'read setpoint
         ReadADC10 tachoport, w1                'read tacho
         '
         If tachovalue > setpointvalue then     'Faster than required
            PWMVal = 0                          'Cut power whenever motor is too fast
         ElseIf tachovalue < setpointvalue then 'Slower then required
            'Vary the speed step-up value according to the undershoot amount
            Difference = setpointvalue - tachovalue
            If Difference < 5 Then              'Difference is between 1 and 4        
               IncVal = 1
            ElseIf Difference < 10 Then         'Difference is between 5 and 9 
               IncVal = 3 
            ElseIf Difference < 20 Then         'Difference is between 10 and 19 
               IncVal = 8 
            ElseIf Difference < 40 Then         'Difference is between 20 and 39
               IncVal = 17 
            ElseIf Difference < 80 Then         'Difference is between 40 and 79
               IncVal = 35
            Else                                'Difference is over 79
               IncVal = 50
            EndIf
            SerTxd ("-")                        'Minus: Show speed is slower than required
            PWMVal = PWMVal + IncVal MAX PWMMax 'PWM must not go higher than PWMMax
         EndIf
         '
         pwmout pwmdiv16, pwmport, 200, PWMVal  'Period of 200 sets freq. to 2490Hz @32MHz
         'pause 800                              '100mS @32MHz
         SerTxd (#Difference, ", ", #PWMVal, CR, LF)
      Loop      
 
I will try your code tomorrow. The soft start is important so I can keep the mosfets to a reasonable size, I'm using 12A 800V ones now, but as you probably know Universal motors have higher inrush currents than induction motors. I will add that to the code. I am also going to change the mosfet driver to TLP358. The TLP358 doesn't have the under voltage lockout but is similar in other respects to UCC23513. The UCC23513 has UVLO of 13.5v so I had to go back to 15V zener. [B]fernando_g[/B] has told me that UCC23513B has an 8.5 UVLO which would have been perfect but these seem to be unavailable anywhere. I am trying hard not to get to excited about this project but it's difficult. Thank you
 
Hi,
If Difference < 5 Then 'Difference is between 1 and 4
IncVal = 1
ElseIf Difference < 10 Then 'Difference is between 5 and 9
IncVal = 3
ElseIf Difference < 20 Then 'Difference is between 10 and 19
IncVal = 8
ElseIf Difference < 40 Then 'Difference is between 20 and 39
IncVal = 17
ElseIf Difference < 80 Then 'Difference is between 40 and 79
IncVal = 35
Else 'Difference is over 79
IncVal = 50
EndIf

The program in the above post #61 looks more like I would "expect" to work well, but a Servo Control Loop normally uses primarily a Linear (i.e. non-discontinuous) Transfer Characteristic, so it shouldn't need so many IF .... conditions. ;) I think that the code immediately above basically reduces to IncVal = Difference / 3 + 1 MAX 50 , producing quite similar values, but with less "granularity". Note that if you wanted to divide by (say) 2.5 , you can use the ** operator, i.e. * 65536 / 2.5 is equivalent to ** 26214 .

Obviously PWMVal must not go below zero, but the servo loop might work better if Difference IS allowed to go negative (i.e. by treating its "very large" wraparound value as a two's complement number). But it's not possible to use the MIN operator, nor PICaxe's * , / or ** operators directly. Thus my (untested) "take" on the program would be:
Code:
; As above, until the READADCs , then:

Difference = setpointvalue - tachovalue      ; Result CAN be Negative (2's complement)
IF Difference < 32768 THEN                   ; It's positive (2's complement)
  IncVal = Difference + 2 ** 21845 MAX 50          ; Divide by 3 with range limited 0 to 50
  PWMVal = PWMVal + IncVal MAX PWMMax            ' PWM must not go higher than PWMMax
ELSE                                                    ; "Optional" processing of negative value follows
  IncVal = 2 - Difference / 3 MAX PWMVal         ' PWM must not go lower than zero
  PWMVal = PWMVal - IncVal                       ; Sometimes IncVal might need to be a Word value to "sign extend" correctly
ENDIF
pwmout pwmdiv16, pwmport , 200 , PWMVal    ' Period of 200 sets freq. to 2490Hz @32MHz

; etc..

The PWMVal +/- IncVal expression is effectively an Amplifier combined with a Low-Pass Filter (using mathematical Integration) to give (almost) "infinite" gain for very low frequencies (permitting any PWM duty cycle to be generated with nearly zero error, in the "steady state") but a limited gain at high frequencies to maintain stability. If I've calculated the constants correctly then IncVal will (only) take the value of zero if Difference is zero. Perhaps I can explain how one might "optimise" the filter characteristics simply in a later post.

Cheers, Alan.
 
Last edited:
Today I ran both programs #61 and 63 and the results, in terms of motor performance, were very similar. hunting around the setpoint and worsening with load added. These are the figures for #63. Because of the larger numbers a graph was of no value.
I have previously been trying #61 and found the performance was better when I replaced all the < numbers with 1 and the IncVal numbers with 1 also. The hunting is still there but not as pronounced. I didn't check for overshoot at that time. Because I had to upload as a text file the headings are in the wrong place but are in the correct order.
By "worsening with load added" i mean that when load is added the speed quickly accelerates until it over speeds, the pwm is then 0, then the motor quickly slows to below the setpoint and the the cycle of acceleration begins again. The higher the setpoint the more extreme this effect becomes. After more testing, #59 had much better and closer control than #61 and #63.
 

Attachments

Last edited:
Some very useful data there!

I have placed the data from the two log files into Excel and adjusted the two's complement values into negative ones for improved visual effect in the charts on pages 1 and 9. I have also added a 'hit' count for the error (difference) value.

Since you are using Alan's algorythm, I'll let him revise his mathematics. My observation is that the motor speeds up quicker than it slows down, so perhaps a pause of, say, 50mS (Pause 400) in the "speed up" branch. This may need to be graduated according to the amount of error.
 

Attachments

Hi,

Sorry, I'm "traveling" at the moment so can't give a very comprehensive reply, but my first observation is that the Tacho signal looks quite "noisy" rather than being truly periodic. The Tacho signal is presumably a moderate-frequency sine wave which is rectified by the diode/capacitor combination, but the residual ripple might be "beating" (i.e. creating a sub-harmonic frequency) with any other instability in the system?

It would take only a few extra lines of code to convert the 2's complement numbers to signed numbers within the PICaxe program. Basically you just detect any "large" value, then send a "-" sign (or maybe set a "sign" byte variable to "+" or "-") and subtract the 2's complement variable from zero (e.g. Diff = 0 - Difference ). This may have an advantage of also stabilising any delays in the program. Personally, I always try to minimise program delays (almost never adding PAUSEs ! ) because I would be looking for at least 10 loops/iterations within each cycle of "instability").

The slower decay rate of the motor speed may be due to the inertia of the motor (or the time constant of the Tacho rectifying capacitor?) , whilst a "pulse" of electrical drive can be larger than the friction/windage of the motor slowing it down. Servo-motors are often driven by an "H-Bridge" which allows them to be driven in either direction, but also the motor can be selected to "Free Run" (by disconnecting the electrical drive) or "Braked" by connecting both terminals to the same line (i.e. a short-circuit). I'm not sure how this might apply in a single-sided/direction system, but I think the "Flywheel" diode (often inside the FET) might act as an (Eddy Current) Brake anyway. But IMHO, maintaining control (with a lower drive level) when the motor is too fast (rather than just chopping off the drive) is likely to produce more stable results.

If you're using a simple "mathematical" function (particularly in preference to a list of IF .. THENs ..) to control the feedback loop, the delay should automatically be less and I would use symbolised constants for the Gain (or attenuation) and limit values, etc., so that they are easy to change experimentally and record quickly). I'm not sure if it would be "safe" with a high powered mains system, but I have often changed some of my system constants "On the fly" (i.e. whilst running) using the (PICaxe) Terminal (which is already connected to record the SERTXD data: The SERRXD command can receive key-presses from the computer keyboard, for example "I" and "D" (or I often use upper-case and lower case characters of the same letter) to Increase or Decrease a particular "System Constant" (e.g. loop gain). However, I should probably give you a few more "tips" (for example that the SERRXD automatically generates a DISCONNECT of the Programming Capability ! ) if you want to give it a try.

Cheers, Alan.
 
Last edited:
The armature is heavy which does make slowing down relatively slow compared to accelerating, unless it's loaded. I looked at the feedback from the tacho and the filtering is clean as shown in the pictures.

Thanks for joining us Allan. Your right about cutting off power, Pete's earlier code with IncVal and DecVal had much better and closer control than #61 and #63. Having read your post a number of times I am struggling with paragraphs 2 and 4. Not because there is any thing wrong with them but because they are outside my programming ability. Also I need to say that this will not be a reversable motor. This heavier motor is a substitute for a 700W router motor that will become a spindle motor for a cnc machine when I find a replacement tachometer for it

The code I wrote myself #59 works really well with the power cut off even when heavily loaded and doesn't overspeed when the load is removed, the only problem I have with it is the fall off in speed. I have reduced this with the graduated multipliers over the speed range but the speed still falls off by about 1,000 rpm in 10,000rpm.
 

Attachments

  • Ripple AfterFilter.jpg
    Ripple AfterFilter.jpg
    441.6 KB · Views: 5
  • TachoAfterFilter.jpg
    TachoAfterFilter.jpg
    403.4 KB · Views: 5
  • TachoOutputFullSpeed.jpg
    TachoOutputFullSpeed.jpg
    374.4 KB · Views: 6
  • TachoOutputLowSpeed.jpg
    TachoOutputLowSpeed.jpg
    418.9 KB · Views: 6
Hi,

I have been "following" this thread from the start, but haven't analysed in detail all the programs listed. But from the above 'scope photos in #67 and the schematic in #53, it appears that typically the Tacho is delivering 30 volts peak at just over 1 kHz and the ripple on the filter capacitor is about 300 mV. That's around 1% , as expected with a 100 ms time constant (1 uF * 100 kohms), but a potential issue is that the READADC occurs "randomly" during the cycle so there may be around 1% variation, which I referred to as "noise".

A potential problem in optimising the value (or time constant) of this filter capacitor (C1) is that, if too small it will allow ripple/noise through, whilst if too large may not follow the speed accurately downwards when the motor speed falls. If the motor has considerable inertia (e.g. takes more than a second to fall to half-speed) then perhaps up to a 1 second time constant (10 uF * 100k) would be satisfactory. But if a significant load is "instantly" applied then the speed may fall much more rapidly, so perhaps 100 ms is about right. One alternative solution would be to read the ADC about 3 - 5 times consecutively and calculate the highest, or simply the average value. READADC is not significantly slower than most other PICaxe instructions (although I'm not sure that it observes the SETFREQ command entirely) so an "In-Line" sequence of 3 - 5 measurements shouldn't take too long, or use much program space, for example :
Code:
READADC10 tachoport , tachovalue 
READADC10 tachoport , b11 : tachovalue = tachovalue + b11
READADC10 tachoport , b11 : tachovalue = tachovalue + b11
Normally, to create an average, one would divide by the number of samples, but there is no need here as we can just scale it down later if required. There are other ways to reduce the "noise", for example syncronising the READADCs to the phase of the tacho signal (or even reading the sine wave output directly) but let's Keep It Simple for now.

Sample code for Paragraph 2 could be as follows :
Code:
Symbol DiffSign = b11      ; ASCII symbol
; Symbol DiffPos = w6       ; Not required unless value of "Difference" will be used again before it's re-loaded
  DiffSign = "+"                 ; This is already an ASCII value so don't use the # prefix
  IF Difference > 32767 THEN     ; It's a negative number (i.e. Bit 15 is a "1")
    DiffSign = "-"
    Difference = 0 - Difference     ; Or use "DiffPos =" if the present value of Difference is still required
ENDIF
SerTxd (DiffSign , #Difference, ", ", #PWMVal , CR, LF)

Concerning Paragraph 4; it's good programming practice to NOT use "Magic Numbers" in the core of a program, but to Symbolise them near the top of the Program so that they can be easily found and adjusted. For example for my code in #63:
Code:
Symbol LOOPMULT = 21845                      ; (Fractional) Loop-Gain Multiplier
Symbol MAXLOOPINC = 50                       ; Maximum Loop Step.  NOTE: This is probably far too large
; ..................
  IncVal = Difference + 2 ** LOOPMULT max MAXLOOPINC          ; Reduce Gain with range limited
; etc..
Personally, I usually Fully-Capitalise these names to signify that they are "Constants" (whilst the program runs) rather than "Variables". However, one could actually symbolise these as Variables (e.g. Symbol LOOPMULT = W10 : LOOPMULT = 21845 ) and then use some "special" code (e.g. receiving instructions from the Terminal Keyboard) to "trim" their values (e.g. Incrementing or Decrementing their value by 10%) whilst the program runs. But that's something for the future (if at all).

Cheers, Alan.
 
Today was more testing and a very interesting result, but first the motor, it takes 9 seconds from full speed of 10,000rpm to free wheel to a stop so I'm guessing that 4.5 to half speed.
I also did what was suggested with the tachovalue, ie read it three times and averaged. I also did a load load test and discovered that if the load is constant, the oscillations gradually decrease and it comes to the setpointvalue as can be seen in the graph but it takes a few seconds. I just picked out this important part because the file is to big to post. I have not seen it do this before.
I'm still struggling with the coding in #68 because of the difference in experience but I am trying to follow it so thank you.
 

Attachments

  • Post#63 LoadTest5.jpg
    Post#63 LoadTest5.jpg
    356.6 KB · Views: 3
Hi,

I would expect the motor speed to initially fall rather faster because some of the load will be speed-dependent, for example the windage on the rotor. Also, when a motor rotates it acts (also) as a voltage generator which opposes the driving voltage. That is why the running current is much lower than the starting current (basically this current is limited only by the dc resistance of the coil(s) ). When the electrical drive is removed, the "Flywheel"/Protection Diode (D2) may act as a "Short Circuit" to the coils and act like a Eddy Current Brake, again proportional to (at least) the rotational speed (and maybe the square). Similarly, the voltage across a Capacitor (being discharged by a Resistor) falls "exponentially". Hence the concept of its TIme-Constant, which is the time it would take to fully discharge if the initial rate continued linearly (which it doesn't, because the voltage and hence current reduces).

Your "Ringing" might have appeared because some of the disrupting "noise" has been removed. It's a classic example of a "nearly unstable" (negative) feedback loop. Feedback loop design can be a complex subject (and believe it or not, I'm NOT a very competent mathematician), but I'm considering whether I can describe a few usefully simplified "hints". ;)

Cheers, Alan.
 
The forum has been a real learning curve for me. Today my new mosfet drivers, TLP358, arrived and was installed and I learnt what a difference it has made to the temperature of the mosfet with the motor running at full load. After 10 minutes, still cool as a cucumber whereas in my post #1 it was running at about 80 deg C and rising after just a few minutes. So thank you to fernando g for your advise. He also told me that 12v was sufficient drive voltage for mosfets but I can't find any mosfet drivers that will run off a 12V supply. They all seem to need 15-30V.

 
Since post #71 I have been working on a permanent board for the motor controller and thought I would post a picture. It works just as the prototype just more compact. The mains voltage part I will retain from earlier and the mosfet will have a larger heat sink although it barely gets warm. So this larger motor part of the project has come to an end. The router motor that will become a spindle motor is now what I need to work on next because the speed sensor I have been using has failed and I am unable to find anything that will substitute for it so I will need to use a hall effect sensor to measure the speed but I don't know how to then integrate it into the program or how to convert the pulses, 1 per revolution, into something useful while still maintaining control of the motor. The only unused input is c.3 input. Your help would be much appreciated.
 

Attachments

  • MotorController.jpg
    MotorController.jpg
    390.8 KB · Views: 5
  • MotorController2.jpg
    MotorController2.jpg
    352.1 KB · Views: 5
The only unused input is c.3 input. Your help would be much appreciated.
Hi,

Presumably the original Tacho input (C.4) is still available? Very little has been said about the actual speeds (or frequencies) of operation, for example was the sine-wave output from the Tacho similar to the rpm of the main motor, or a (much) higher frequency? Also what is the approximate frequency of the "ringing" in the photo in post #69?

At one time I was concerned that the forward voltage drop across the Tacho rectifier diode (D1) of about 600 mV would "lose" some low-speed resolution. But it became apparent that the (peak sine) voltage at maximum rpm was about 30 volts, so the rectification would "fall out" only at about 2% of the maximum speed. The maximum speed has been quoted as 10,000rpm so the Tacho could have been generating a useful signal down to about 200 rpm, which might be difficult to reproduce easily with other methods.

Normally the "best" method to measure the rpm of a wheel/shaft is to use the PICaxe PULSIN command for (typically) a single revolution, and then to convert to rpm/frequency by mathematical division (because the period delivered by PULSIN is the inverse of the frequency or rpm). But the READADC10 command takes less than 1 ms, whilst a PULSIN for a single revolution, even at 10,000 rpm, would be about 6 ms, and 60 ms at 1,000 rpm. Actually, PULSIN can't measure a complete revolution, but only the Pulse (e.g. High) or Gap (Low) periods from most types of sensor. If the Duty Cycle of the sensor output is known (and constant) then the rpm can be accurately calculated. But if not, a PULSIN for "High" can be added to a PULSIN of "Low" to give the accurate period for a single revolution.

Another possible sensor method could be optical, which has the advantage that it's relatively easy to use a "Stroboscope Band" of marks around the shaft to increase the frequency (i.e. to reduce the sampling period), but optical methods raise issues of cleanliness, etc.. The equivalent could a be magnetic gear (pinion) on the shaft (producing a varying magnetic field), but that's more difficult to implement than simply adding a small magnet to the shaft for a Hall (or Magnetic Reed) sensor.

There are various types of "Hall" sensors, both Analogue and Digital, which can be sensitive to the Magnetic Field Strength and/or its Polarity (N-S). The output from an Analogue sensor can of course be "sliced" by a comparator, or by just a digital input threshold (a PICaxe has both), or one might perform more sophisticated detection directly from the Analogue Magnetic Field strength (via a PICaxe ADC Input). It's difficult to predict which method might be most suitable, until it's clearer what frequencies are likely to be involved and the degree of mechanical "complication" that is acceptable.

Cheers, Alan.
 
Hi Alan, To answer your questions,
Yes, the tacho input c.4 is available and can be used.
The speed range is 3,000 to 10,000 rpm.
As shown in the attached pictures. I have inserted one 2mm magnet into the collet holder and so it's one pulse per revolution. It is a form of sine wave and appears as a + and - blip as the magnet passed the sensor. I could install more magnets if needed when they arrive. Also pictured is the sensor that has failed.
The ringing in #69 is low and took place over a period of about 4 seconds, so I 'm guessing about 3hz as I didn't have a time stamp from the file.
The hall effect sensor I have is an Allegro A3144, a digital sensor and this picks up signals over the 3 to 10,000 range. and runs on 4.5 -28V
I also have some smd IR emitters and diodes that I could use with reflective tape, again a digital signal.
Another alternative is using LM2917 which convert digital pulses into an analogue signal. I've never used these so not sure if they would be suitable.
 

Attachments

  • DSCN3258.JPG
    DSCN3258.JPG
    136.5 KB · Views: 2
  • DSCN3260.JPG
    DSCN3260.JPG
    190.9 KB · Views: 2
  • DSCN3259.JPG
    DSCN3259.JPG
    194.5 KB · Views: 2
Hi,

Thanks for the "numbers" which give me some food for thought, although not many definitive answers yet. The "ringing" at about 3 Hz suggests that the feedback loop is potentially unstable at this frequency, probably due mainly to the inertia of the motor, which is not very dependent on the rotational speed. To control this requires the program to process a "large" number of samples during each (ring) cycle, perhaps at least 10. Thus my "ballpark" target would be for each loop around the program to take no more than 30 ms.

At a minimum target shaft speed of 3000 rpm, a single revolution takes 20 ms, which is already a large proportion of the "available" processing time. But we need to consider how long PULSIN takes to execute, for example with a 10% Duty Cycle Pulse, as might occur when a magnet is close to a Hall sensor. PULSIN first "looks" for the leading edge of a pulse (which can be selected as either rising or falling) and then "counts" the time until the trailing (falling or rising) edge is encountered. But if we are "unlucky" a leading edge may have occurred just before the instruction starts looking, so it may need to wait for almost a full revolution of the shaft before the measurement can even start**. Thus in this example it may be necessary to wait for 1.1 revolutions (22 ms) to measure the Pulse or 1.9 revolutions (38 ms) to measure the Gap between pulses (which is the more normal method to measure a single rotation). In both cases the actual execution time of the instruction can "randomly" vary by the duration of a full revolution, i.e. 20 ms at 3,000 rpm, but the program cannot "know" how long it needed to pause (i.e. only the pulse width is returned, not the length of the "wait" for it to start).

An alternative method could be to use Interrupts with a configurable Timer/Counter, but these need to be Hardware-based and only the X2, not the M2, chips have these. If you were using a 20M2 then it might be worthwhile to upgrade to a 20X2, but from an 08M2 seems a step too far. Actually, all the M2 chips do have a "Timer1 Gate" Hardware module which might be able to perform this function, but it's not supported by the PICaxe Operating System and actually conflicts with it's operation, so this could involve some very "advanced" programming methods. Therefore, my proposal is to begin by using a second PICaxe 08M2, basically to emulate the operation of the original Tacho Generator. Later, if this works well, then we could consider merging the two programs into a single 08M2, if desired. But an advantage of the second 08M2 is that the Tacho program can effectively synchronise itself to the revolutions of the motor shaft, so we don't need to worry about randomly changing time delays being introduced into the main program.

Here is an (untested) program to emulate the previous Tacho, using a separate 08M2. It connects to a rotation sensor such as a (digital) Hall Magnetic device via Pin C.3 and (for this example) detects the duration of a full revolution by adding the High Pulse time to the Low pulse time*. It then uses division to calculate the equivalent frequency (or rpm) which is converted to PWM to output on Pin C.2. The PWM needs to be Low-Pass filtered via a resistor (typically 10k) from C.2 to C.1, and a capacitor (typically 1uF) from C.1 to ground This should give an analogue swing between 0 and Vcc (5v), that can be measured (for testing) via the ADC on that pin. This example uses PICaxe's native division operator (/) which can achieve a resolution/accuracy of about +/-1% by dividing a "large" Word value (e.g. around 60,000) by a large Byte value (e.g. around 250) to give a similar-valued Byte result. If higher accuracy is needed, many a years ago I developed a subroutine to divide a "Double Word" by a single-Word to give a full Word result, which executes in about 6 ms with a 32 MHz clock.

*EDIT: Note that the code cannot measure a consecutive Pulse and Gap (because the Gap must have already started when the PULSEIN command ends), so this double-reading method adds at least another full revolution to the execution time. But the problem with a single Pulse or Gap measurement is that it may vary with any differences in the Rise and Fall times (or delays), or the widths of the pulses.

Code:
; Tachometer Emulator
#picaxe 08m2
#no_data
setfreq m32
#terminal 38400

symbol pulse = C.3           ; Pulse input
symbol pwmpin = C.2          ; PWM (DAC) Output
symbol tachopin = C.1        ; Filtered Analogue Output
symbol hipulse = w2
symbol lopulse = w3
symbol onerev = w4           ; Period of one revolution of shaft (1.25us units)
symbol duty = w5
do
   pulsin pulse,0,lopulse
   pulsin pulse,1,hipulse
;   lopulse = 14400 : hipulse = 1600  ; sample values for 3000 rpm (uncomment when simulating)
   onerev = hipulse + lopulse        ; 16000 for 20ms = 3000 rpm
   w1 = onerev / 4 * 5
   sertxd(cr,lf,#w1,"us=")
   onerev = onerev ** 1024           ; scale down for division
   duty = 62500 / onerev             ; 256 for 25% of full-scale frequency
   pwmout pwmpin,255,duty
;   readadc10 tachopin,duty           ; Test the analogue output (uncomment when hardware running)
   w1 = duty * 12                    ; convert to rpm
   sertxd(#w1,"rpm")
loop

**ADDENDUM: Attaching additional magnet(s) to the shaft is unlikely to be helpful. Remember that the Hall sensors (or equivalent optical devices) are fundamentally analogue components, even if they contain a threshold detector to deliver a digital output signal. Any additional magnet is unlikely to have exactly the same field strength or perfect positioning, so the detected pulses are very unlikely to be identical and/or be spaced exactly symmetrically around the shaft. An optical system might be more practical, because one might stick "stripes" of (say) 1cm or 1 inch wide tape around the shaft/collet, and detect the pulses generated by the width of the bands (not the gaps between them). But optical transmitters and receivers (e.g. LEDs) must still have a finite size, so their resolution/accuracy will always be limited, and ultimately may be compromised when the stripes become (differentially) "dirty".

Cheers, Alan.
 
Last edited:
Thanks Alan, It will take me some days to fully understand everything in your post and to try this out and to return with feedback but that's my plan. This router motor is lighter and performs very differently to the larger motor I was using earlier. If more magnets are beneficial I can actually place them very accurately and they will all be from the same batch. I will return.
 
Back
Top