Shop OBEX P1 Docs P2 Docs Learn Events
Is there a way to make a variable global to the child? — Parallax Forums

Is there a way to make a variable global to the child?

lardomlardom Posts: 1,659
edited 2013-04-16 06:35 in Propeller 1
I changed a value of a variable from 1 to 0 in a loop in the parent object. I passed the address of that variable to the child and created another loop to monitor that variable and watched the result with an LED. The child object could see the initial value but would not respond to changes that were made in the parent unless I used the "@" symbol again. I was looking for a way to let the child know when the parent had finished executing. Is there a way to do this?

Comments

  • kuronekokuroneko Posts: 3,623
    edited 2013-04-14 22:58
    Do you have a (small) sample case we can look at?
  • JonnyMacJonnyMac Posts: 9,107
    edited 2013-04-15 07:55
    In order for the child to respond to changes in the parent, it must be running autonomously, that is, in its own cog. Otherwise, you have to manually refresh the LED based on the state of the parent value. In that case, you may as well do it in the parent and keep things simple.
  • Mike GreenMike Green Posts: 23,101
    edited 2013-04-15 08:07
    Remember that objects and cogs are completely different things. You can have a program that consists of a single (main) object that uses all 8 cogs. You can also have a program that has lots of objects (way more than 8) and uses only a single cog for the whole thing. By convention, a lot of objects that make use of multiple cogs to do their work keep all of the code that runs on the other cogs within the single object. That way, the fact that the object uses multiple cogs to accomplish its function is mostly hidden from the user of the object.
  • lardomlardom Posts: 1,659
    edited 2013-04-15 09:09
    I'm working on an autonomous navigation robot. The left and right wheels are in separate cogs for differential steering. They call a servo/Ping object and use odometry to navigate. The servo/Ping scans 180° in 20° increments. The robot executes its instructions then the servo/Ping scans again. This is what I'm after.
    I wrote an object where the Ping acts as a motion sensor. The problem is that a breeze can also trigger a scan. I want a method as reliable as monitoring wheel encoders. I'm using steppers. I want the motors to write values to a "universal" global address that could be seen by the 'servo/Ping child.
    I'm stuck on how to update object "two".
    obj    'ONE
        two : "two"
    
    var
    
       word ref
       
    pub main
        ref := 1
     '   two.start(1)
     '   waitcnt(clkfreq/2+cnt)
        two.It_Works(@ref)
       ' two.It_Works(1)  
        repeat
          ref := 0
       '   two.It_Works(@ref)
      '    waitcnt(clkfreq/2+cnt)
          ref := 1
       '   two.It_Works(ref)
      '    waitcnt(clkfreq/2+cnt)  
    
    var    'TWO
       word refAddr
       long stack[10]
    
    pub start(a)
    
       cognew(It_Works(a), @stack+1)
    
    pub It_Works(n)
    
        dira[17]~~    
        refAddr := n
     '   repeat
          outa[17] := (word[refAddr])
          waitcnt(clkfreq/4+cnt)
          outa[17] := (word[refAddr])
          waitcnt(clkfreq*7+cnt)
     {   repeat
          refAddr := n
          if refAddr == 1
            outa[17]~~
     '       waitcnt(clkfreq/2+cnt)
          if refAddr == 0
            outa[17]~
       '     waitcnt(clkfreq/2+cnt)     }
    
  • Mike GreenMike Green Posts: 23,101
    edited 2013-04-15 09:44
    You've got to go back to the basics ... What information is supposed to be communicated back and forth between the main cog and each of the wheel cogs? What information is supposed to be communicated back and forth between the main cog and the servo / PING cog? Remember that having multiple cogs is the same as having separate microcontrollers except that communications back and forth is easier because of the shared memory.

    What's the reason for having the servo / PING handling in a separate cog (from the main one)? Is the servo and PING functioning autonomously? What about accounting for the motion of the robot? How's that done? If you're stopping the robot to avoid motion artifact, why not do the scan in the main cog? If you want the servo and PING to function autonomously, you do indeed want to have motion information passed on to the servo / PING cog via shared variables.
  • lardomlardom Posts: 1,659
    edited 2013-04-15 10:55
    The logic is "Start" calls the start method for servo/Ping which begins a scan. The next line executes two additional cognews for the 'left' and 'right motors which mirror each other. They call Ping and evaluate the return with case. Ping then becomes a motion sensor and waits for motion to begin and then stop. It then begins a new scan.
    It works but it's unreliable. I hope that makes sense.
    In a nutshell; When the motors finish executing I want them to copy "1" to a universal global address which the Ping object can see.
  • Mike GreenMike Green Posts: 23,101
    edited 2013-04-15 11:49
    It doesn't quite make sense. I understand about left and right motors mirroring each other. I hope you use the same code for each and just pass a constant or two to create the mirror effect since the two routines really do the same thing. It makes code maintenance easier. Note Bene: If it's unreliable something's wrong about the design.

    Who sets the flag values to zero?

    When you call the start method for the motor, you pass it the address of that motor's flag long. The start routine saves the address in a global variable (VAR) for the object. When the start routine does its cognew, it doesn't have to do anything special because the new cog's code can directly access the global variable that holds the flag's address. I don't recommend passing the address to a separate method because the address should be known before you start up the new cog.
    ' Main object
    VAR long flagRight, flagLeft
    OBJ right, left : "motorControl"
    PUB main | isMoving
       right.start(@flagRight, 1)   ' initialize right motor
       left.start(@flagLeft, -1)   ' initialize left motor
       ping.start(@flagRight,@flagLeft)   ' ping can see whether motor is running
       repeat
          isMoving := ping.doScan
          ' here you decide what to do
          right.doNewCommand( ???)   ' initiate a movement with left motor
          left.doNewCommand( ???)   ' initiate a movement with right motor
          ' you can wait here for both movements to finish if you want
    
    ' Object for right and left motors:
    VAR long saveAddr, saveCommand, stack[20]
    
    PUB start( flagAddr, direction)
       saveAddr := flagAddr   ' save flag address
       saveCommand := 0   ' "do nothing" command
       long[saveAddr] := 1   ' make it look like motor is ready
       cognew(motorMethod(direction),@stack)
    
    PUB doNewCommand( command)
       repeat until long[saveAddr]   ' wait for motor ready
       saveCommand := command
       long[saveAddr] := 0   ' signal new command is ready
    
    PUB motorMethod( directionSign)
       repeat while long[saveAddr]   ' wait for new command
       ' do stuff based on value of saveCommand and directionSign
       long[saveAddr] := 1   ' signal we're done
    
  • kuronekokuroneko Posts: 3,623
    edited 2013-04-15 16:58
    Two main issues, you never call the start method with the address and cognew is passed an unaligned stack address, NG.

    This works for me:
    obj    'ONE
      two : "two"
    
    var
      word  ref
       
    pub main
        
      two.[COLOR="#FF0000"]Start[/COLOR](@ref)       
      repeat                
        ref := 0            
    '   waitcnt(clkfreq+cnt)
        ref := 1            
    '   waitcnt(clkfreq+cnt)
    
    var    'TWO
      word  refAddr
      long  stack[10]
    
    pub start(a)
    
      cognew(It_Works(a), [COLOR="#FF0000"]@stack[/COLOR]{0})
    
    pub It_Works(n)
    
      dira[17]~~                   
      refAddr := n                 
      repeat                       
        outa[17] := (word[refAddr])
        waitcnt(clkfreq/4+cnt)     
        outa[17] := (word[refAddr])
        waitcnt(clkfreq*7+cnt)     
    
  • Prophead100Prophead100 Posts: 192
    edited 2013-04-15 19:01
    This code does something like what your talking about with two (actually three) motors, a ping and IR sensors. I just posted it to the OBEX. http://obex.parallax.com/objects/912/ It deals with the sharing of status and coordination between cogs
    1024 x 768 - 112K
  • lardomlardom Posts: 1,659
    edited 2013-04-16 06:35
    Wow... It works. 'Flags', passing memory addresses in the parameter list and making the address known before a "Start" method is called are important ideas. I was completely unaware of the problem with an "unaligned stack address".
    It is a big deal when people take the time to clarify concepts by writing code for me. Understanding a concept is better than simply memorizing syntax. Thank you.
Sign In or Register to comment.