Shop OBEX P1 Docs P2 Docs Learn Events
Need Help with PWM_32.spin Object — Parallax Forums

Need Help with PWM_32.spin Object

AndyKvAndyKv Posts: 8
edited 2014-12-31 13:13 in Propeller 1
Greetings All.

I need a bit of help using the PWM_32 object.

Background:
What I am needing to do is to produce 4 signal waves that are all in phase. These signal waves will then be used by other cogs to synch the motion of 4 motors.

Imagine you have 4 motors each connected to a piston moving up and down. I want all the pistons to reach top dead center (TDC) at the same time. My plan is to accomplish this by synching the motors to a master signal. Or in other words, all the pistons should be at TDC when the signal wave goes high.

The reason I need 4 signal waves is because each motor will be controlled by a separate cog running a routine that will control the motor and keep it in synch with the master signal.

Complicating matters just a bit is the need to increase the speed of a pair of motors temporarily then bring them back into synch with the other motors.

Test Apparatus:
I have set up the following to test. I have 4 LEDs on Pins 16 thru 19. The LEDs form a box with LED16 the lower right, LED17 upper right, LED18 lower left, and LED19 upper left. I also have 4 buttons set up on Pins 12 thru 15. When button 12 is pushed the LEDs on the right side of the box will blink at a faster rate. When button 13 is pushed the LEDs at the bottom flash faster. When button 14 is pushed the LEDs at the top of the box flash faster. And finally, when button 15 is pushed the LEDs on the left side of the box flash fast. (note: only one button will be active at a time)

When the button is released, the LEDs should be synched back to the master signal.

Problem:
I am trying to use PWM.PhaseSynch method of the PWN_32 object to synch the LEDs with the master signal but I am having mixed results. There are two basic issues. #1 is that upon start up only 3 of the LED flash in synch - the other is 180 out of phase. #2 When the button is released sometimes all the LEDs synch to the master signal, sometime three LEDs are in synch with the other one 180 degree out of phase, or sometime two LEDs are in synch with the other two 180 degrees out of synch.

Need some help figuring out how to consistently get the LEDs in synch at start up and when they come off their disturbed state. Please note that I am relatively new to the Propeller and Spin and don't know PASM. I understand PWM_32 runs ASM in a separate cog to create and synch the PWMs but beyond that I can't follow the ASM code.

Thanks for the help.

Here is my code.


Con
PWMFreq1 = 1000000
PWMFreq2 = 100000

VAR
BYTE Flag12, Flag13, Flag14, Flag15

OBJ PWM : "PWM_32_test.spin"

PUB Go

dira[12..15]~ ' pins 12 thru 15 used as inputs
outa[12..15]~

PWM.Start '' Initialize PWM cog

'create 2 master PWMs

PWM.Duty(20,50,PWMFreq1) ' Create a PWM on pin 20 = Master 1
PWM.Duty(21,50,PWMFreq2) ' Create a PWM on pin 21 = Master 2


' Create individual waves on pins 16, 17,18, 19 and synch with master wave on pin 20
PWM.Duty(16,50,PWMFreq1)
PWM.Duty(17,50,PWMFreq1)
PWM.Duty(18,50,PWMFreq1)
PWM.Duty(19,50,PWMFreq1)

PWM.PhaseSync(20,16,0)
PWM.PhaseSync(20,17,0)
PWM.PhaseSync(20,18,0)
PWM.PhaseSync(20,19,0)

'pin 16 ==> lower right LED
'pin 17 ==> upper right LED
'pin 18 ==> lower left LED
'pin 19 ==> upper left LED

'Use button inputs to change duty cycle values of a pair of LEDs
' Pin 12 ==> LEDs on right (16 & 17)flash faster
' Pin 13 ==> LEDs at bottom (16 & 18)flash faster
' Pin 14 ==> LEDs at top (17 & 19) flash faster
' Pin 15 ==> LEDs on left (18 & 19)flash faster

repeat
if ina[12] == 1
if Flag12==0 'use flags to prevent multiple calls while button is continually pushed
PWM.Duty(16,50,PWMFreq2)
PWM.PhaseSync(21,16,0)
PWM.Duty(17,50,PWMFreq2)
PWM.PhaseSync(21,17,0)
Flag12:=1

if ina[13] == 1
if Flag13 == 0
PWM.Duty(16,50,PWMFreq2)
PWM.PhaseSync(21,16,0)
PWM.Duty(18,50,PWMFreq2)
PWM.PhaseSync(21,18,0)
Flag13:=1

if ina[14] == 1
if Flag14 == 0
PWM.Duty(17,50,PWMFreq2)
PWM.PhaseSync(21,17,0)
PWM.Duty(19,50,PWMFreq2)
PWM.PhaseSync(21,19,0)
Flag14:=1

if ina[15] == 1
if Flag15 == 0
PWM.Duty(18,50,PWMFreq2)
PWM.PhaseSync(21,18,0)
PWM.Duty(19,50,PWMFreq2)
PWM.PhaseSync(21,19,0)
Flag15:=1

if ina[12] == 0 and Flag12 == 1
Flag12:=0
SynchToMaster

if ina[13] == 0 and Flag13 == 1
Flag13:=0
SynchToMaster

if ina[14] == 0 and Flag14 == 1
Flag14:=0
SynchToMaster

if ina[15] == 0 and Flag15 == 1
Flag15:=0
SynchToMaster

PUB SynchToMaster

PWM.Duty(16,50,PWMFreq1)
PWM.Duty(17,50,PWMFreq1)
PWM.Duty(18,50,PWMFreq1)
PWM.Duty(19,50,PWMFreq1)

PWM.PhaseSync(20,16,0)
PWM.PhaseSync(20,17,0)
PWM.PhaseSync(20,18,0)
PWM.PhaseSync(20,19,0)

Comments

  • PublisonPublison Posts: 12,366
    edited 2014-12-29 12:07
    Welcome to the forums!

    Use this link to post your code. It keeps it formated for the forum.

    attachment.php?attachmentid=78421&d=1297987572
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-12-29 13:18
    Besides the obvious need to use code tags, it also helps if you at least provide links to the objects you're using.

    Ideally you should post your code as an archive so it's easy for others to test it out.

    I'm skeptical PWM_32.spin is a good match for what you want to do. If you read the comments in the object, you'll see it's intended to be used with LEDs rather than for motor control. I know people have modified PWM_32 to use with motors but I don't think it would work well without modification.
  • AndyKvAndyKv Posts: 8
    edited 2014-12-29 17:23
    Apologies for not using <code> </code>. I will keep that in mind next time I post code.

    The object I am using is version 4 of the PWM_32 object created by Beau Schwabe. I tried finding it again in the Object Exchange but I can no longer find it, which is a bit weird as I recently downloaded it from the exchange.

    I understand PWM_32 is not intended to drive motors but for what I need it actually works quite decent. I'm using a 3v hobby motor and when I run the PWM output through a MOSFET I get pretty speed control good control. But the main reason I was trying to use PWN_32 is because it's the only object I've seen thus far that will synch PWMs.

    If someone can direct me on how to post my code as an archive, I'll post what I have in that format,

    If there are other ways of creating and synching PWMs I'm open to that as well.
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2014-12-29 17:56
    AndyKv wrote: »
    Apologies for not using <code> </code>. I will keep that in mind next time I post code.

    The object I am using is version 4 of the PWM_32 object created by Beau Schwabe. I tried finding it again in the Object Exchange but I can no longer find it, which is a bit weird as I recently downloaded it from the exchange.

    I understand PWM_32 is not intended to drive motors but for what I need it actually works quite decent. I'm using a 3v hobby motor and when I run the PWM output through a MOSFET I get pretty speed control good control. But the main reason I was trying to use PWN_32 is because it's the only object I've seen thus far that will synch PWMs.

    If someone can direct me on how to post my code as an archive, I'll post what I have in that format,

    If there are other ways of creating and synching PWMs I'm open to that as well.

    I have a 32-channel 8-bit PWM that's built into Tachyon that is completely synchronous because it uses a pattern array so the PWM cog reads out a long at up to a 2MHz rate and outputs that directly onto the outputs. This could easily be adapted for a general Spin object with the only down-side being that to vary a channel requires the array to be updated. In Tachyon this happens very quickly but Spin is a little slow so it might need it's own cog just to look after the updating.

    EDIT: BTW, Duane's right, how does having phase synch help with brushed motors?
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-12-29 17:56
    AndyKv wrote: »
    If someone can direct me on how to post my code as an archive, I'll post what I have in that format,

    In the Propeller Tool you can archive a project by first compiling the top object and then selecting File\Archive\Project...
    AndyKv wrote: »
    . . .What I am needing to do is to produce 4 signal waves that are all in phase. These signal waves will then be used by other cogs to synch the motion of 4 motors.

    I'm not sure what being able to produce four waves in sync has to do with syncing the motion of four motors? Just because the PWM signals are synced has no bearing on whether or not the motors will be in sync.

    In order to synchronize the motion of multiple brushed motors, you need some sort of feedback from the motors. Often this feedback is from quadrature encoders. A couple examples of motors with quadrature encoders are these 30:1 gearmotors and Parallax's Motor and Wheel Kit which includes Parallax's quadrature encoder kit.

    Producing four synchronized pulses is rather trivial for the Propeller however synchronizing the motion of four motors is far from trivial (but very possible).
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-12-29 18:23
    I'm not sure if you're aware you should NOT directly power a motor from a Propeller I/O pin or not.

    Motor are inductors and resist change in current. If you were to drive a motor (even a 3V one) directly from a Propeller I/O pin it would likely damage the Propeller.

    To drive the motors in a single direction you could use a transistor or similar device. If you want to control the motor both forward and reverse you need a h-bridge. Here's my attempt of explaining how to use a h-bridge with a microcontroller.

    Here are a couple links to encoder projects.
    Ron Czapala using a single channel encoder.
    Kye's PWM with quadrature encoder feedback plus PID. (I think this object is very aplicatble to your project.)
  • AndyKvAndyKv Posts: 8
    edited 2014-12-29 20:00
    Thanks for the replies thus far. Let me address some of the questions/comments that have been posed.

    I am not driving a motor directly from an I/O pin. Rather I am taking the PWM output and connecting it to a MOSFET. The gate on the MOSFET doesn't draw any current so the chip is protected. Been testing this out for a couple of days an still haven't fried my Propeller. :o)

    I understand the synched waves alone are not enough. I am taking this project one step at a time and right now I need synchronized PWMs. Once I have those I can feed that output to 4 separate cogs running a PID routine (currently under development) that will control each motor. In my original example, a motor connected to a piston, I will have an encoder that will fire when the piston is at TDC and this will feed into the PID routine. I am using a hall sensor to determine TDC. When I run this through a D flip flop I get a nice square wave with a 50% duty cycle at 1/2 the freq. When I match the period of the wave I get from the hall sensor with that of the synch PWM I'll be at the desired RPM. When the rising edge of the hall sensor PWM and the synch PWM are 0 degrees out of phase, then the motor will be at the position I desire. The thinking is the PID routine will control RPM and correct for any phase shift. I also understand that using a single firing once a cycle does not give me good resolution. But at this point I'm not so much interested in precision. Rather, I am just trying to prove a concept that I can later refine.

    I did look at a quadrature but I don't think that will work as it gives me speed and direction of rotation. What I need is to synch the absolute position of each motor. Direction of rotation will be fixed.

    I will take a look at the suggested projects. Hopefully I will get some insights. Please keep the suggestions coming.
  • r.daneelr.daneel Posts: 96
    edited 2014-12-29 20:29
    A student of mine recently submitted a project for his final year at high school that was very similar to this. He had 4 push solenoids connected to the journals of a crankshaft, and as each solenoid fired in sequence the crankshaft would crank a quarter of a turn - so the solenoids were simulated pistons. To fire the solenoids at precisely the right time so that the crankshaft rotated smoothly I built him a control board using a prop and a QTI IR sensor. We had a small DC motor that we could adjust the speed of, and we put a white disc of paper on the shaft of the motor with opposite quadrants coloured black. The IR sensor monitored the disc as it spun, and on each white/black or black/white transition it fired the next solenoid - so the DC motor, disc and IR sensor simulated the distributor and camshaft (sort of). We could then change the speed of rotation of the crank by changing the speed of the DC motor - within the limits of the solenoids. Since the prop had spare cogs we could fire LEDs in sync with the pistons, measure RPM, drive an LCD display etc. Worked a treat...
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-12-29 21:27
    AndyKv wrote: »
    I did look at a quadrature but I don't think that will work as it gives me speed and direction of rotation. What I need is to synch the absolute position of each motor.

    Quadrature encoder are great for position feedback.

    Just today I was testing the 36 slotted quadrature encoders in the motor and wheel kit. With 36 slots and two sensors (as all quad encoder have) the encoder provides 144 transitions per revolution of the wheel. This lets me position the wheel to within 2.5 degrees of the desired location.

    If you have the quadrature encoders on the motor instead of the drive shaft, you can have much higher resolution than 2.5 degrees. One could easily position a wheel/shaft very precisely with quadrature encoders.

    I still don't understand what the timing of the PWM pulses has to do with the motors' position? You need the PWM to provide the correct average power to motors, it shouldn't matter where in the rotation of the motor the high pulses occur. I'd think the duty cycle of the PWM will be much more important than the timing of the pulses in relation to the position of the shaft.

    Edit: I likely don't understand the project well enough to understand the concern about synchronized pulses. Do you intend to have the PWM frequency match the frequency of the motors' revolutions? From my limited understanding, it still seems like quadrature encoders would be the most appropriate feedback mechanism.
  • AndyKvAndyKv Posts: 8
    edited 2014-12-30 10:10
    A bit more clarification ....

    I think using the term PWM is confusing things a bit so let me describe this way.

    The synchronized PWMs I've been talking about are not directly driving the motor. The synchronized signal I need is a square wave with a 50% duty cycle which will vary by frequency. This signal will then be fed into the motor's PID controller which compares it to the encoder signal. The PID will then generate a separate PWM to drive the motor based on that comparison.

    Why a square wave for the master synch signal? The signal I get from the motor encoder will be a 50% duty cycle square wave. I have created a calibration chart by driving a motor at different duty cycles and measuring the frequency of the motor encoder output. Based on this data I have created a look up table the PID uses to set the bias duty cycle of the motor driving PWM (i.e., master signal has period x thus duty cycle should be y). After the bias duty cycle is set the PID routine will then kick in to keep the RPM in check and synch the position. When the motor is driven at the bias duty cycle the master synch signal and the encoder signal will be nearly identical (i.e., a 50% duty cycle square wave at some frequency). And when the rising edge of the master synch signal aligns with the rising edge of the encoder signal the position of the piston will be synched to the master signal. My goal is to have all pistons at TDC at the same time.

    Each motor will have it's own PID controller running in a separate cog so the synching of the piston position will be done independently. Thus the need to have 4 synchronized signal waves.

    Also keep in mind that at certain times it will be necessary for a pair of the motors to speed up for a brief period of time. This will be done by simply increasing the frequency of the master signal fed to those motor's PID. When the motors need to return to their previous speed the master signal will be reset to the previous value and the PID will take care of the speed and position synching.

    If you're wondering what I am trying to do, this is for a school project. I am attempting to create a multi motor ornithopter. It has 4 wings each driven be a separate motor. The flapping needs to be in synch as lift is only produced on the down stroke. (If they don't flap in synch, you loose control.) To control direction in flight the idea is to have a pair of wings flap faster (i.e., produce more lift) that will then tilt the ornithoper which will result in movement in a given direction. Basically I am trying to apply the quadcopter flight control theory to an ornithopter.

    At this point in time I am far from creating a flying prototype. I'm just trying to prove the flight control concept with a large scale model.

    Hope this gives you more context.

    But back to my original question. The PWM_32 object has a method for creating synchronized square waves. I can create a master signal, which runs in the back ground, then synch other signals to it when needed. But the problem is that the PhaseSynch method sometime synchs things 180 degrees out of phase (even thought the phase input to the method is set at zero). I am hoping someone could open the hood on that method and tell me how is works and give me some ideas on how to compensate for it or how to fix it as I don't know assembly language.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-12-30 11:46
    AndyKv wrote: »
    Hope this gives you more context.

    Absolutely. Your omithopter project sounds very interesting.

    I still think you'll have a better chance of getting help if you attach an archive or your program.
  • AndyKvAndyKv Posts: 8
    edited 2014-12-30 12:58
    Attached is the program I am using to test the PhaseSynch method of PWM_32.

    The way this program works is as follows:

    The LEDs are set up such that they form a box

    I create two PWMs that run in the "background" on pins 20 & 21. Those pins are connected to ground via a 10K resistor.

    At start up all 4 LEDs should blink in synch. (my results show only the first three blink in synch with the forth one 180 degrees out of synch. If I put a 180 degree offset as the phase value in the call [i.e., 1/2 the master period], they will all blink in synch)

    When one of the buttons is pushed one side of the square should blink faster as long as the button remains pushed. (see code notes) This is done by decreasing the period of the PWM to the LEDs. I don't have a problem with the two faster blinking LEDs blinking in synch.

    When the button is released, all 4 LEDs should go back in synch at the initial frequency. (but my results show very inconsistent results)
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-12-30 13:45
    I as wiring up a board to test out the code when I found this line:
    PWM.Duty(11,50,MASTER_PERIOD_1)       ' Create a PWM on pin 20 = Master 1
    

    Is the "11" where a "20" should be causing the problem?

    You wouldn't be the first to benefit from an extra set of eyes examining ones code.

    Let me know if you're still having trouble, my setup is about halfway complete.

    You might have to wait until I'm in a procrastinating mood (it probably won't take long) before I finish setting up my board to test the code.
  • AndyKvAndyKv Posts: 8
    edited 2014-12-30 23:49
    Doh!

    That "11" is a typo. The pin value should = 20 and this is what I did my testing with. (If it were 11 I would get no synching at all which isn't what I saw.).
  • kuronekokuroneko Posts: 3,623
    edited 2014-12-31 01:14
    Where can I find said object? Seems that all of Beau's contributions disappeared from the OBEX.
  • kuronekokuroneko Posts: 3,623
    edited 2014-12-31 02:31
    I can only speculate what the original intention was for PhaseSync but all it does is copy the current reference phase time (plus offset) to the target pin without adjusting polarity. So it's not aligning it to any specific edge. If you want that try the following change:
    _SyncPhase                                              
                  rdlong    temp1,       ARG_0              'Read Channel position 1
                  add       temp1,       #t1                'add database offset
                  movs      Ch1_Read,    temp1              'Self modify code to read proper position            
                  [color="orange"]movs      Chx_Sync,    temp1[/color]              'delay for pipelining
    Ch1_Read      mov       temp1,       00_00              'Read current value
    
                  rdlong    temp2,       ARG_2              'Read Phase Offset
                  add       temp1,       temp2              'Add Phase Offset
    
                  rdlong    temp2,       ARG_1              'Read Channel position 2
                  add       temp2,       #t1                'add database offset
                  movd      Ch2_Write,   temp2              'Self modify code to write proper position           
    
                  [color="orange"]add       temp2,       #Ch - t1           '|
                  add       Chx_Sync,    #Ch - t1           'channel array base
                  movd      Chx_Sync,    temp2[/color]              'delay for pipelining
    Ch2_Write     mov       00_00,       temp1              'Write new value                           
    
    [color="orange"]Chx_Sync      mov       2-2, 1-1                        'transfer polarity[/color]
    
                  wrlong    Zero, cmd_address               'Tell SPIN command has been processed
                  jmp       #Main_PWM_Loop                  'Return to main PWM loop
    
  • AndyKvAndyKv Posts: 8
    edited 2014-12-31 10:30
    Thank you for the code suggestion. I incorporated the changes but the problem still exists.

    I've attached my changes and a zip file with a couple of videos to show what's happening . (note: video isn't the greatest as I had to reduce resolution to keep file size small.)

    In the first video (button behavior), I incorporated kuroneko's changes verbatim and tested without making any other changes. As you can see, upon start not all LEDs are in synch. (I saw this even before kuroneko's changes.) And depending upon when a button is release I get different behaviors in the base state.

    In the second video, I put in a waitcnt line right after I initialized the PWM_32 object thinking the object needed time to boot up. It's interesting that depending upon the delay time, I get different initial base state. The video show start up with a 1, 2, 3, 4, & 5 second delay.
  • kuronekokuroneko Posts: 3,623
    edited 2014-12-31 10:40
    AndyKv wrote: »
    Thank you for the code suggestion. I incorporated the changes but the problem still exists.
    Any comment as to why the Chx_Sync label (incl code) ended up in the wrong location?
  • AndyKvAndyKv Posts: 8
    edited 2014-12-31 13:13
    User Error???? :-)

    Funny - I triple checked before I posted again but as ya all know you can blind yourself sometimes looking at your own code. Thanks for second set of eyes.

    I put the label in the appropriate place and now it works like a charm. Whooo Hooo!

    Thanks so much - this is a tremendous help and boost to my project. I've only got one more issue to solve and that is to get the master signal and encoder signal in phase.

    P.S. Do you think it would be a good idea to repost the PWM_32 object to the OBEX with kuroneko's changes?
Sign In or Register to comment.