Shop OBEX P1 Docs P2 Docs Learn Events
(Hopefully) A simple question, possibly about variable scope — Parallax Forums

(Hopefully) A simple question, possibly about variable scope

David StokesDavid Stokes Posts: 5
edited 2008-06-30 19:59 in Propeller 1
Hello! I hope someone can point me in the right direction...

I have an object with several variables and methods. One method is run on a cog and it continuously increments one value in main memory and checks another. This appears to be working. Another method, not run on its own cog, tries to wait until that first value reaches a certain size (I modeled this off of waitcnt) and changes the second value. However, I don't seem to ever escape the loop.

Here is the code that I believe to be malfunctioning:

[b]pub[/b] Turn (dir) | t
  ApplyBrakes
  t := totalTicks + TURNING_TICKS
  currentState := dir
  [b]repeat[/b] [b]while[/b] totalTicks < t
    [b]waitcnt[/b](clkfreq / 16 + [b]cnt[/b])
    ' Let cog run
  
  ApplyBrakes
  currentState := FORWARD




This is an edited version of the method running on the cog. I trimmed out some of the unnecessary portions that affect neither currentState or totalTicks. It's using the Mouse object to monitor the wheels of a robot, keeping them in sync. I'm taking advantage of the demo board's PS/2 ports and using a hacked mouse as a dual encoder. stateAddress is the address of currentState, and ticksAddress is the address of totalTicks.

[b]pri[/b] RunMotors (stateAddress, ticksAddress) | l, r
    
    ' get absolute values of mouse position
    l := ||(mouse.delta_x)
    r := ||(mouse.delta_y)
         
    ' If one wheel is ahead of the other, slow it down.
    ' Just cut its power and put it in 'free' mode (0,0).
    [b]if[/b] r > l
      [b]outa[/b][noparse][[/noparse]MOTOR_R1..MOTOR_R2]~
      [b]long[/b][noparse][[/noparse]ticksAddress] += l
    [b]elseif[/b] l > r
      [b]outa[/b][noparse][[/noparse]MOTOR_L1..MOTOR_L2]~
      [b]long[/b][noparse][[/noparse]ticksAddress] += r
    [b]else[/b]
      [b]long[/b][noparse][[/noparse]ticksAddress] += r
       
  ' Reset mouse coordinates 
    mouse.delta_reset

    ' Let the motors do their thing for a bit.
    ' Should be about 1/20th of a revolution, i.e. one encoder 'tick'
    [b]waitcnt[/b](clkfreq / 8 + [b]cnt[/b])  ' 1/8th of a second





My little robot dutifully starts turning on the line "currentState := dir" but never stops; it just keeps spinning on the spot.

Is there anything special about repeat in this case? Is the current value of the variable totalTicks somehow not getting updated in the loop? The rest of the code seems to be working correctly; the motors change direction when currentState is changed and are kept in almost perfect sync. I confess that I don't know for a fact that totalTicks is incrementing, but I can't see why it wouldn't. These are the only places that totalTicks is referenced, other than the cog being started with @totalTicks as an argument to the method.

I apologize if this is all overly vague, but can anyone offer some advice? Am I making some obvious newbie mistake?

Comments

  • grasshoppergrasshopper Posts: 438
    edited 2008-06-26 20:46
    I can try to help but it looks like i need to see more code.
    your code below
    pub Turn (dir) | t
      ApplyBrakes
      t := totalTicks + TURNING_TICKS
      currentState := dir
      repeat while totalTicks < t
        waitcnt(clkfreq / 16 + cnt)
        ' Let cog run
      
      ApplyBrakes
      currentState := FORWARD
    
    
    



    In this method you never address the Forward? perhaps the code may help

     if (dir == 1) 
      stop
    if (dir == 2)
     forward
    
    
    



    Also it looks like T is never incremented or decremented

    Try something like this

    pub Turn (dir,toatlTricks,Turning_Tricks) | t
      ApplyBrakes
      t := totalTicks + TURNING_TICKS
      currentState := dir
      repeat while totalTicks < t
        waitcnt(clkfreq / 16 + cnt)
        ' Let cog run
      
      ApplyBrakes
      currentState := FORWARD
    
    

    Post Edited (grasshopper) : 6/26/2008 8:56:46 PM GMT
  • David StokesDavid Stokes Posts: 5
    edited 2008-06-26 21:10
    FORWARD and TURNING_TICKS (and everything else in all caps) are constants. totalTicks is a variable defined in the object's VAR block and it is being updated by the method running on the cog; if I passed it to the Turn method it would never change. t is not incremented/decremented in Turn because totalTicks is the value that's changing.

    Here is hopefully all the missing, relevant code:

    [b]con[/b]
      ' Mouse (a/k/a wheel encoder) pins. Hardwired on demo board.
      MOUSE_DATA       = 24
      MOUSE_CLOCK      = 25
      
      ' Pins used for motor control. Two for each motor.
      MOTOR_L1         = 4
      MOTOR_L2         = 5
      MOTOR_R1         = 6
      MOTOR_R2         = 7
      
      ' The motor states. In this project, the two motors are always doing something
      ' simultaneously, so there are six (out of a possible 16).
      OFF             = %0000       ' Both motors in 'free' mode
      FORWARD         = %0101       ' Both motors forward
      REVERSE         = %1010       ' Both motors reverse
      TURN_CW         = %0110       ' L forward, R reverse
      TURN_CCW        = %1001       ' L reverse, R forward
      BRAKE           = %1111       ' Stop! Use after every motor direction change to limit drift.
    
      ' The number of encoder ticks for each operation.
      TURNING_TICKS                 = 11                    ' The number of encoder ticks for a 90 degree turn
      
    [b]obj[/b]
      mouse         : "Mouse"
      
    [b]var[/b]
      [b]long[/b]  currentState
      [b]long[/b]  totalTicks
      [b]long[/b]  stack[noparse][[/noparse]10]
      [b]byte[/b]  cog
    
    [b]pub[/b] Start
      '' Initialize the motor controller. Returns the address of the motor's current state.
      mouse.Start(MOUSE_DATA, MOUSE_CLOCK)
      currentState := OFF
      totalTicks := 0
      [b]dira[/b][noparse][[/noparse]MOTOR_L1..MOTOR_R2]~~
      [b]outa[/b][noparse][[/noparse]MOTOR_L1..MOTOR_R2] := currentState
      mouse.delta_reset
      cog := [b]cognew[/b](RunMotors(@currentState, @totalTicks), @stack) + 1
    
      ' Turn on an LED to show the robot is ready.
      [b]if[/b] cog 
        [b]dira[/b][noparse][[/noparse]23]~~
        [b]outa[/b][noparse][[/noparse]23]~~
    
      ' Return the address of the motors' current states.
      [b]result[/b] := @currentState
    
     
    [b]pri[/b] ApplyBrakes
    '' Stops the robot by putting the motors in 'brake' mode, then powering them off.
    '' The robot is left in 'off' mode.
      currentState := BRAKE
      [b]waitcnt[/b](clkfreq / 4 + [b]cnt[/b])    ' Pause to let braking take effect
      currentState := OFF
    
    
    [b]pub[/b] Turn (dir) | t
      ApplyBrakes
      t := totalTicks + TURNING_TICKS
      currentState := dir
      [b]repeat[/b] [b]while[/b] totalTicks < t
        [b]waitcnt[/b](clkfreq / 16 + [b]cnt[/b])
        ' Let cog run
      
      ApplyBrakes
      currentState := FORWARD
    
    
    [b]pri[/b] RunMotors (stateAddress, ticksAddress) | l, r
        
        ' get absolute values of mouse position
        l := ||(mouse.delta_x)
        r := ||(mouse.delta_y)
             
        ' If one wheel is ahead of the other, slow it down.
        ' Just cut its power and put it in 'free' mode (0,0).
        [b]if[/b] r > l
          [b]outa[/b][noparse][[/noparse]MOTOR_R1..MOTOR_R2]~
          [b]long[/b][noparse][[/noparse]ticksAddress] += l
        [b]elseif[/b] l > r
          [b]outa[/b][noparse][[/noparse]MOTOR_L1..MOTOR_L2]~
          [b]long[/b][noparse][[/noparse]ticksAddress] += r
        [b]else[/b]
          [b]long[/b][noparse][[/noparse]ticksAddress] += r
           
      ' Reset mouse coordinates 
        mouse.delta_reset
    
        ' Let the motors do their thing for a bit.
        ' Should be about 1/20th of a revolution, i.e. one encoder 'tick'
        [b]waitcnt[/b](clkfreq / 8 + [b]cnt[/b])  ' 1/8th of a second
    
    



    I've left out the method ApplyBrakes, but that is known to work. It just sets currentState to BRAKE for a fraction of a second, then STOP. Also, I'm aware that cog isn't actually used for anything except locally in the Start method; it's left over from something else.

    Edit: I've added the missing ApplyBrakes method and rolled the other code snippets into the listing above.

    Post Edited (David Stokes) : 6/30/2008 5:11:10 PM GMT
  • David StokesDavid Stokes Posts: 5
    edited 2008-06-30 17:01
    I've done some more work on my program, and I'm starting to think that the culprit may not be the Turn method. Can the Propeller lock up on a crash, leaving its outputs in their last state? I've written some bad code in the past and it seemed that the board simply reset. Thinking about it now, though, I may not have been using multiple cogs in those tests.

    I still do not have a good idea of what's wrong. Does anyone else see what I'm doing wrong?

    (BTW: I've edited my previous post to roll all the code together into one block, rather than leave Turn and RunMotors in the first post.)

    Post Edited (David Stokes) : 6/30/2008 5:13:27 PM GMT
  • Mike GreenMike Green Posts: 23,101
    edited 2008-06-30 17:14
    The stack space is way too small. You've got two parameters, two local variables, and the method call (and result field). That's already about 10 longs. On top of that, you call the mouse object. Who knows how much that uses? Try a stack of 20 or 30 at least.
  • David StokesDavid Stokes Posts: 5
    edited 2008-06-30 18:19
    I see... I had thought that the stack was just used for method calls on the current cog, and I hadn't considered the method calls in Mouse would use the cog's stack. Thanks!

    The stack has been increased to 40, just to be sure. Now I have another problem, one which I've seen before and thought I'd fixed: the right wheel's delta seems to always be greater than the left wheel's, so the right wheel stops almost immediately. Since I have LEDs displaying the motor controller's inputs, I can see the right wheel flickering -- this is probably the line before checking the wheels: outa[noparse][[/noparse]MOTOR_L1..MOTOR_R2] := long[noparse][[/noparse]stateAddress]. The last time I saw this happening, I thought I'd solved it by increasing the delay before the wheels were checked, giving the wheels a little more time to turn. Unfortunately, that does not seem to be the problem in this case.

    I'm not sure why the right wheel's delta is always greater than the left's... direction doesn't matter (I've tested forwards and backwards) and I'm taking absolute values, anyway. After the deltas are reset they should both read zero, and since the left is moving and the right is not, it should be higher. Is there something fundamentally wrong with my logic?

    (BTW: I've tried increasing the stack more and more, going up to 200... no dice. This new problem doesn't seem to be caused by an undersized stack.)
  • David StokesDavid Stokes Posts: 5
    edited 2008-06-30 19:59
    Okay, dumb mistake on my part: I had the wrong axes associated with each wheel. I must have swapped them while I was testing.

    Things are working just fine now... it must have been the small stack all along.

    Thanks again!
Sign In or Register to comment.