Shop OBEX P1 Docs P2 Docs Learn Events
Using Cogs Properly for motor control — Parallax Forums

Using Cogs Properly for motor control

LitefireLitefire Posts: 108
edited 2007-03-21 00:40 in Propeller 1
I'm using the Prop in a robot i'm trying to build. i've got a homebuilt H-Bridge (functioning perfectly) that is directly controlled by PWM for speed control. the issue is that there are two motors, and thus it needs to be in parallel. this is my first foray into parallel processing on the prop (very exciting), but my problem right now is that i can't figure out how to:

a) set up a program so it constantly updates the required speed of the motor
b) be able to send speed values to the specific controls

thanks!

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2007-03-19 02:03
    It would help if you post (as an attachment) what you've done so far including a simple schematic or description of what's connected to what.
  • LitefireLitefire Posts: 108
    edited 2007-03-19 02:17
    my.php?image=motorpropvr7.jpg

    The Green and Blue lines go from an I/O pin to my H-Bridge. Depending on which one is active, the motor runs forward or backward. both motors can be engaged (in one direction, of course) at once. activating both fwd and rev for one motor starts to seriously cook the transistors (i learned that today!).

    I need a program that can control the PWM output to the signal lines of the H-Bridge. I need the reaction to be as quick as possible, and to be able to run/control both motors simultaneously.

    Thanks so much for your help!

    ~~Brian
  • LitefireLitefire Posts: 108
    edited 2007-03-19 02:19
    The Green and Blue lines go from an I/O pin to my H-Bridge. Depending on which one is active, the motor runs forward or backward. both motors can be engaged (in one direction, of course) at once. activating both fwd and rev for one motor starts to seriously cook the transistors (i learned that today!).

    I need a program that can control the PWM output to the signal lines of the H-Bridge. I need the reaction to be as quick as possible, and to be able to run/control both motors simultaneously.

    Thanks so much for your help!

    ~~Brian

    EDIT: Link was broken, apparently i didn't use it as an attachment... oops.
    650 x 513 - 595K
  • Mike GreenMike Green Posts: 23,101
    edited 2007-03-19 02:30
    Have you looked in the Propeller Object Exchange? You can get to it from the main Propeller page of the Parallax website (ww1.parallax.com/Default.aspx?tabid=65). There's an object on the first page ("Control speed and direction of DC motors using H-Bridge chips such as the LMD18201") that may be helpful. It can control two motors and sounds like it would give you the kind of control you're asking for.

    There is a lot of information available from Parallax on the Propeller and how to use it. You should familiarize yourself with the relevant web pages and their contents including the "sticky threads" at the beginning of this forum.
  • LitefireLitefire Posts: 108
    edited 2007-03-19 02:35
    that was the first place i looked, actually. and i did see that, but the configuration of my H-Bridge vs. those of manufactured parts (such as the one that code is designed for) is different. that example expects there to be one PWM pin and one direction pin. on my bridge, the PWM pin is the direction pin. depending on which pin the PWM is being produced on.

    perhaps there's a way to manipulate that example to export the PWM signal on the direction pin? and how would i use that to control both motor simultaneously?

    thanks!

    ~~B
  • T ChapT Chap Posts: 4,223
    edited 2007-03-19 03:18
    You need a method to prevent both directions from being possible. Use an exclusive OR(one OR the other, but not both) from both the PWM pins per channel to a disable switch/enable input--- maybe use two other gates at each PWM input per motor, one input from the original PWM source, the other from the disable source (XOR output).

    Also, don't let the inputs to the Hbridge have a potential float state, use a 10k to GND on all Hbridge inputs as pull down in case the micro is in a weird state.

    The question is, what method are you using for PWM on each pin? Knowing that can help find a best method to control the 4 pins to your existsing Hbridges. The PWM object is great. You just run a loop updating the 4 variables for duty(assuming the cycle length can always remain the same).

    here is just an idea, you probably need 4 cogs in reality, and the loop just updates the 4 methods containing separate PWM objects.
    repeat    'pwm object updated based on input affecting the variables elsewhere(your control input method)
      MotorAForward(0, speedMotorAForward, cycleLength)    'pin, duty, cycle length
      MotorAReverse(1, speedMotorBReverse, cycleLength)
      MotorBForward(2, speedMotorAForward, cycleLength)
      MotorBReverse(3, speedMotorBReverse, cycleLength)
    
    

    Post Edited (originator) : 3/19/2007 3:29:29 AM GMT
  • Mike GreenMike Green Posts: 23,101
    edited 2007-03-19 03:53
    I think this will work for you. I've modified the assembly routine to use the PWM pin for the forward direction and the direction pin for the reverse direction. It puts out PWM as before, but only on one pin at a time with the appropriate direction. Although the routine will work with a duty cycle of 0%, you should stop the cog at that point. I haven't gone through the "SetMotor" object thoroughly, but I think it will work with the modified assembly routine. The "MotorsTest" object should work if you change the pin numbers appropriately. No guarantees.
  • crgwbrcrgwbr Posts: 614
    edited 2007-03-19 12:02
    Mike, I'm using the routine (premodified) on my robot. I just have two of the objects and assigned the direction pins to unused I/O's. I can say for sure (haven't fried my fets yet) that 0% duty cycle does just take the pin low.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    NerdMaster
    For
    Life
  • LitefireLitefire Posts: 108
    edited 2007-03-19 15:18
    Mike, as has been said before, you are TRULY the man.

    I assume that i need two of these (one per motor) to run the device? And, i know this is a newbie question, but how do i integrate this with my main code? Thanks so so much!

    When i get out of class later today i'll see if that works!

    ~~Brian
  • Mike GreenMike Green Posts: 23,101
    edited 2007-03-19 15:28
    Look at the MotorsTest (demo) program in the LMD18201 driver archive. It declares an array of these and shows how to use them. You can actually have more than two, up to the number of cogs you have available.
  • LitefireLitefire Posts: 108
    edited 2007-03-19 15:34
    again, awesome. will do that and will report back with results.

    ~~Brian
  • LitefireLitefire Posts: 108
    edited 2007-03-19 19:15
    mike-

    just got a chance to run your program. i looks like there's some form of undefined symbol ("addr" in the :loop section of the DAT block)

    what should i change it to? i have no assembler experience...

    ~~B
  • Mike GreenMike Green Posts: 23,101
    edited 2007-03-19 19:19
    Brian,
    I thought I got them all. Sorry. Please change them all to "temp" instead of "addr" and try again.
    Mike
  • LitefireLitefire Posts: 108
    edited 2007-03-19 20:05
    hmm... nothing seems to be happening. and i know that's not really helpful.

    any ideas on what might be wrong? here's what i have now.

    as noted above, motorstest.spin is the top file.

    ~~Brian
  • Mike GreenMike Green Posts: 23,101
    edited 2007-03-19 20:24
    Here we go. I made a mistake ... In the Spin, I used the bit mask for the pin to indicate the direction.
    In the assembly code, I (correctly) assumed it was the pin number. Now it's corrected. Change the
    name of the file by deleting the "-1" from the name before compiling.
  • LitefireLitefire Posts: 108
    edited 2007-03-19 20:36
    well, still nothing. i'm calling your code directly in the beginning using this:

        pwm.start(17,16,1000)
        pwm[noparse][[/noparse]0].start(18,19,1000)
        pwm[noparse][[/noparse]0].forward
        pwm.forward
        pwm[noparse][[/noparse]0].update(50)
        pwm.update(50)
    
    



    where pwm is your MotorPWMTwo object. again, nothing happens.

    when i drive the PWM pins high manually, the motors work perfectly (just in case you were wondering...) so it's not a hardware issue.

    ~~Brian

    edit: same as below. the [noparse][[/noparse]one] is not appearing when i post.

    Post Edited (Litefire) : 3/19/2007 8:54:19 PM GMT
  • LitefireLitefire Posts: 108
    edited 2007-03-19 20:50
    relating to my motorcontrol but not to anything else really:

    i tried the PWM method in the BS2_functions object and it works great. but here's something weird.

    when i do this:
        bs2[noparse][[/noparse]0].start(30,31)
        bs2.start(30,31)
        cognew(bs2[noparse][[/noparse]0].pwm(17, 128, 10000), @BS2_1)   'right motor forward
        ''cognew(bs2.pwm(18, 128, 10000), @BS2_2)   'left motor forward
    
    



    the right motor goes perfectly at half-power.

    do this:

        bs2[noparse][[/noparse]0].start(30,31)
        bs2.start(30,31)
        ''cognew(bs2[noparse][[/noparse]0].pwm(17, 128, 10000), @BS2_1)   'right motor forward
        cognew(bs2.pwm(18, 128, 10000), @BS2_2)   'left motor forward
    
    



    perfect, this time the left motor activates

    but try this:
        bs2[noparse][[/noparse]0].start(30,31)
        bs2.start(30,31)
        cognew(bs2[noparse][[/noparse]0].pwm(17, 128, 10000), @BS2_1)   'right motor forward
        cognew(bs2.pwm(18, 128, 10000), @BS2_2)   'left motor forward
    
    



    and only the right motor activates.

    confused...

    ~~Brian

    p.s. the index for the second instance of bs2 doesn't seem to be appearing... it's in my code though.
  • Mike GreenMike Green Posts: 23,101
    edited 2007-03-19 20:55
    Ah. The forum software uses square brackets for control information. You need to put a space after the opening bracket.

    I'm not sure what's going on. Here's a correction of some minor errors that wouldn't explain what's happening.

    Maybe someone else experienced in assembly can jump in and look at what I did. There must be something simple
    I'm forgetting. Sorry.
  • LitefireLitefire Posts: 108
    edited 2007-03-19 21:07
    i'd hate to disagree with ya, but i love that i have to!

    seems to be working just fine all on it's own now!

    thanks so much! they should change your tag from "Registered Member" to full-fledged "Guru"

    ~~Brian
  • Mike GreenMike Green Posts: 23,101
    edited 2007-03-19 21:10
    There's nothing like success, even if the explanations are confusing. Have fun with your robot.
  • LitefireLitefire Posts: 108
    edited 2007-03-20 14:55
    hey mike, if i wanted to add an encoder-driven feedback loop to monitor and control speed (using the quadrature encoder object on page three of the exchange), where would i put the code?

    i'm thinking that it'd look like this:
    var
      long speed[noparse][[/noparse] 2], duty[noparse][[/noparse] 2]
    
    pub speedcontrol(intended_speed1, intended_speed2) | duty_old[noparse][[/noparse] 2]
      duty_old := 0
      repeat while speed[noparse][[/noparse] 1] <> intendedspeed1 AND speed[noparse][[/noparse] 0] <> intended_speed2
        repeat i from 0 to 1
          speed(i) := (encoder.readDelta(i))/*Some time constant*
          if speed(i) < intended_speed
            motor[noparse][[/noparse] i].setmotor(duty_old[noparse][[/noparse] i]+1, 1, 1)
    [i]
     [/i]
    



    just as a quick idea i wrote that in this quick reply box :P. but where should i put that? it would be excellent if there could be some active section monitoring and updating speeds to keep the robot going straight. because right now i don't think the motors run at exactly the same speed (inherent of DC motors they run different speeds forward and reverse and we've got them mounted so one goes forward and one runs in reverse...).

    ~~Brian
  • Mike GreenMike Green Posts: 23,101
    edited 2007-03-20 16:35
    Brian,
    I'd probably try to find a way to build this into the setMotor routine since that runs by itself in a cog and is already responsible for the actual motor speed. In a way, now the setMotor routine blindly sets the expected motor speed as a % duty cycle. Instead, it could use the encoder outputs for feedback on the actual motor speed. I couldn't say offhand how or where to put the code, but, conceptually, this makes sense to me.
  • LitefireLitefire Posts: 108
    edited 2007-03-20 17:07
    hmm... i'm actually thinking about integrating some PID code into the setmotor routine. if it's running in its own cog now it's got plenty of processing overhead. this'll be a good combination: setmotor will ramp the motors, preventing them from forcing them immediately to 100% until they get close to rated speed. i'll go back and read up on the BS2 PID implementation forum topic somewhere. that'll be a powerful combination (in my opinion). give it your desired speed and have it get there...

    as usual, if i have questions i'll put them here. if it works i'll repost the object to the exchange. with all due props of course.

    edit: to save a look at the manual, how do i set minimum and maximum limits on variables?· equivalent to MIN and MAX on the BS2.

    ~~Brian
  • T ChapT Chap Posts: 4,223
    edited 2007-03-20 17:27
    http://forums.parallax.com/showthread.php?p=635059

    This may speed up the PID learning
  • LitefireLitefire Posts: 108
    edited 2007-03-20 20:56
    Thanks! That's quite useful. Will it care if i give it speeds instead of distances? if i do will that make the program attempt to get to a specific speed?

    ~~Brian
  • T ChapT Chap Posts: 4,223
    edited 2007-03-20 23:03
    From my understaning of how it would apply to your case, the PID is just a calculator that constantly takes an input of what the position error is, and outputs a PWM accordingly. I am working on something similar, only it is a single brushless DC motor with encoders. Unfortunately there are a few things ahead of that phase. I simply pointed out the link as it has a lot of ideas that could be considered when designing a closed loop system.

    In you case you seem to be more wanting to synchronize two motors, although they are getting the same PWM, may have a drift due to motor fluctuations. This would require the encoders as you stated to check distance travelled on one motor compared to a second motor.

    So just thinking out loud, you have a distance error between the motors, either negative or positive, depending on who is ahead in the race. Either way, it is a distance calculation, which really is an ERROR to correct. In my limited experience with PID, there may actually be several approaches. One is, an accurate measure of RPM, and correction. The second is the difference between the encoder counts. That difference is the error. So, lets imagine a loop doing nothing but comparing the quad encoder counts. MotorLeftCount - MotorRightCount = MotorError. So a variable is updated many times a second with the resulting error. That variable is an Offest to one of the motors, I see no need to compensate both motors right off hand.

    Forgetting PID for a second, which may even be overkill, if the Error is 50 counts, to correct, the left motor PWM increases duty by a ratio to catch up, if the left motor overshoots the speed(count) of the right, then the error is negative, and a negative compensation kicks in to offset the difference. I would start there first, see if there is an obvious way to add that to your existing code. Of course this means that the motors need to not always run at 100% duty, as there is no margin to over-power one to motor to "catch" up. This may not need some fancy PID calculation, but it may need some way to "smooth" the compensation to avoid constant overshooting back and forth, maybe not. Phil P posted a formula in a thread in the sandbox, I think is was by Owen, the subject was "joystick dampening math/ code", there may be some useful material there for the correction.


    Hope ths helps.


    An oversimplification:

    PUB LOOPPWM
       Repeat
          motorLeftPWM   := motorSpeed + Compensation    '  comp = (right count - left count) * smoothing
          motorRightPWM := motorSpeed
    
    
    

    Post Edited (originator) : 3/21/2007 3:14:59 AM GMT
  • LitefireLitefire Posts: 108
    edited 2007-03-21 00:15
    i'll do that once i get it working... right now the encoder on the left wheel is giving me lip. i think it's mechanical (broken lead somewhere probably) and i now need to take apart my pretty wiring job to get at the areas that i think might be problematic. sigh.

    But the right wheel's encoder seems to be working. so as a proof of concept thing it's working just fine.

    ~~Brian
  • LitefireLitefire Posts: 108
    edited 2007-03-21 00:40
    psht. the encoder wire wasn't pushed far enough into the connector. for ONCE I tried the simple explanation first! i've gotta get into the habit of doing that :P

    ~~Brian
Sign In or Register to comment.