Shop OBEX P1 Docs P2 Docs Learn Events
Reading a variable in another cog started by an Object — Parallax Forums

Reading a variable in another cog started by an Object

xanaduxanadu Posts: 3,347
edited 2014-04-08 17:02 in Propeller 1
I seem to be confused on global VARs. I have the PE kit book in front of me, and have done the examples related to cogs and variables. I have written code in the past that seemed to work fine, but I cannot get this simple example to work for some reason.

This is the main program, it counts up from 0 to 10 on the PST. It is also supposed to display the variable from the Object below.
'' Cogs and VARs version 1 Main Program 


OBJ


 PST       : "Parallax Serial Terminal"
 OBJ1      : "Object1"
  
CON
   
 _clkmode = xtal1 + pll16x           
 _xinfreq = 5_000_000


VAR


 long mainnum
 
 long obj1num 


PUB Main  


'---Init Vars---


 mainnum := 0


'---Start PST---
 
 pst.Start(115200)            
 waitcnt(clkfreq * 2 + cnt)
 pst.str(string("PST Online"))
 pst.newline


'---Begin Object 1---


 OBJ1.Start


'---PST VARs from this object, and new cog in Object 1---


 repeat until mainnum => 10 


   pst.str(string("Main:"))


   pst.dec(mainnum)


   pst.newline
  
   obj1num := obj1.go


   pst.str(string("Obj1:"))


   pst.dec(obj1num)


   pst.newline  


   mainnum := mainnum + 1
  
   waitcnt(clkfreq * 1 + cnt)


'---End Program---


 pst.str(string("End Program"))   
  

This is my test object that produces a variable that counts down from 10.
'' Cogs and VARs version 1 Object 1


OBJ




   
CON
   
 _clkmode = xtal1 + pll16x           
 _xinfreq = 5_000_000


VAR


 long stack[100]


 long obj1num


PUB Start 


  cognew(Go,@stack[0])


PUB Go


 obj1num := 10


 repeat until obj1num =< 0


   obj1num := obj1num - 1


   waitcnt(clkfreq * 1 + cnt)
                     

Thanks for any help.

Comments

  • msrobotsmsrobots Posts: 3,709
    edited 2014-04-05 13:57
    I do not know why you use another cog in your Obj1.

    You are mixing two concepts here. What is the goal you want to archive?

    You are starting a parallel process counting its own variable down from 10 to zero. One time. then this cog finishes.

    you also call obj1num := obj1.go

    thus calling the same thing once from main. And return the RESULT which is simple 0 since you do not set RESULT in GO it will return RESULT as 0.

    All expected behavior.

    Give a example of what your expected output in PST should look like and I may be able to build a small example for you.

    Enjoy!

    Mike
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-04-05 14:01
    I'm not sure what the call to "Go" from the parent object was supposed to do. It is possible to pass a variable from a child to the parent with a call to the child object.

    The child object has no knowledge of the variables in the parent object unless the address of the variable is passed to the child. Variables in Spin don't care about cogs. Only objects make variables inaccessible to other methods.

    Naming the variables the same name in the parent and child don't do anything towards having the variable shared.

    Here's my take on your objects.

    Parent:
    '' Cogs and VARs version 1 Main Program OBJ
    
    
    
    
     PST       : "Parallax Serial Terminal"
     OBJ1      : "Object1b"
      
    CON
       
     _clkmode = xtal1 + pll16x           
     _xinfreq = 5_000_000
    
    
    
    
    VAR
    
    
    
    
     long previousNum
     
     long obj1num 
    
    
    
    
    PUB Main  
    
    
    
    
    '---Init Vars---
    
    
    
    
     previousNum := -1 ' some unlikely number. 
    
    
    
    
    '---Start PST---
     
     pst.Start(115200)            
     waitcnt(clkfreq * 2 + cnt)
     pst.str(string("PST Online"))
     pst.newline
    
    
    
    
    '---Begin Object 1---
    
    
    
    
     OBJ1.Start(@obj1num)
    
    
    '---PST VARs from this object, and new cog in Object 1---
    
    
     
     
     repeat 'until mainnum => 10 
        
       repeat while previousNum == obj1num  ' wait for obj1num to change
    
    
       previousNum := obj1num ' get ready for next loop
    
    
       pst.str(string("Obj1:"))
    
    
    
    
       pst.dec(obj1num)
       
       pst.newline
     while previousNum
    
    
    '---End Program---
     
     pst.str(string("End Program"))   
      
     repeat ' keep program alive so terminal window behaves
    

    I added a "b" to the end of the child object's name. Make sure and name the object appropriately.

    Here's the child object.
    VAR
    
    
    
     long stack[100]
    
    
    
    
     long obj1numPtr
    
    
    
    
    PUB Start(obj1numPtr_) 
    
    
    
    
      obj1numPtr := obj1numPtr_
      
      cognew(Go,@stack[0])
      waitcnt(clkfreq / 100 + cnt)  ' time for cog to launch
    
    
    PUB Go
    
    
    
    
     long[obj1numPtr] := 10
     waitcnt(clkfreq * 1 + cnt) ' so the value "10" has time to be noticed in parent
    
    
     repeat until long[obj1numPtr] =< 0
    
    
    
    
       long[obj1numPtr] -= 1
    
    
    
    
       waitcnt(clkfreq * 1 + cnt)
    

    This example shows how the child object can change the value of a variable in the parent object. To access the value of a variable in the child object you'd use a different technique. I'll modify this example to show you an example of accessing a child's variable and post it soon.

    Edit (4/20/14): Corrected typo. I had used "accessible" when I should have used "inaccessible".
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-04-05 14:27
    Here's an example of having the parent request the value from the child.
    '' Cogs and VARs version 1 Main Program 
    OBJ
     PST       : "Parallax Serial Terminal"
     OBJ1      : "Object1c"  
    CON   
     _clkmode = xtal1 + pll16x           
     _xinfreq = 5_000_000
    VAR
     long previousNum 
     long childNumber 
    PUB Main
    '---Init Vars---
     childNumber := previousNum := 0  ' There are several ways to do this. 
                                      ' We just need to make sure the
                                      ' loop doesn't prematurely end.
                                      ' In this case, this could be any number.
    '---Start PST--- 
     pst.Start(115200)            
     waitcnt(clkfreq * 2 + cnt)
     pst.str(string("PST Online"))
     pst.newline
    '---Begin Object 1---
     OBJ1.Start
     
     repeat   
       repeat while previousNum == childNumber  ' wait for obj1num to change
         childNumber := OBJ1.GetNumber
       previousNum := childNumber ' get ready for next loop
       pst.str(string("Obj1:"))
       pst.dec(childNumber)   
       pst.newline
     while previousNum
     
    '---End Program---
     pst.str(string("End Program"))  
     repeat ' keep program alive so terminal window behaves
    

    The variable is passed with the method "GetNumber".

    Here's the child (I removed some white space so it doesn't take up as much space in the forum code block).
    VAR
     long stack[100]
     long obj1num
    PUB Start
    
    
      cognew(Go,@stack[0])
      waitcnt(clkfreq / 10 + cnt)  ' time for cog to launch
    
    
    PRI Go
    
    
     obj1num := 10
     waitcnt(clkfreq * 1 + cnt) ' so the value "10" has time to be noticed in parent
    
    
     repeat until obj1num =< 0
       obj1num -= 1
       waitcnt(clkfreq * 1 + cnt)
    
    
    PUB GetNumber
    
    
      result := obj1num
    

    This technique is probably the most common way of passing variables from child to parent.

    Another technique, similar to the first example, is to pass the address of the child variable back to the parent.

    Edit: Somehow I missed Mike's earlier reply. I doubt Mike will mind my not waiting for xanadu's clarification before proceeding with an example.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-04-05 14:43
    One last example.

    This one returns the address of the child's variable with the Start method.
    '' Cogs and VARs version 1 Main Program OBJ
     PST       : "Parallax Serial Terminal"
     OBJ1      : "Object1d"  
    CON   
     _clkmode = xtal1 + pll16x           
     _xinfreq = 5_000_000
    VAR
    
    
     long previousNum 
     long childNumberPtr
      
    PUB Main
    '---Init Vars---
     previousNum := -1  ' some unlikely number 
    '---Start PST--- 
     pst.Start(115200)            
     waitcnt(clkfreq * 2 + cnt)
     pst.str(string("PST Online"))
     pst.newline
    '---Begin Object 1---
     childNumberPtr := OBJ1.Start
     
     repeat   
       repeat while previousNum == long[childNumberPtr]  ' wait for child variable to change
       previousNum := long[childNumberPtr] ' get ready for next loop
       pst.str(string("Obj1:"))
       pst.dec(long[childNumberPtr])   
       pst.newline
     while previousNum
     
    '---End Program---
     pst.str(string("End Program"))  
     repeat ' keep program alive so terminal window behaves
    

    The child object is almost the same as last time. The main difference is the address of the variable of interest is returned in the Start method. Since the address is returned, the method "GetNumber" is no longer needed.
    VAR long stack[100]
     long obj1num
    PUB Start
    
    
      cognew(Go,@stack[0])
      waitcnt(clkfreq / 10 + cnt)  ' time for cog to launch
      result := @obj1num
      
    PRI Go
    
    
     obj1num := 10
     waitcnt(clkfreq * 1 + cnt) ' so the value "10" has time to be noticed in parent
    
    
     repeat until obj1num =< 0
       obj1num -= 1
       waitcnt(clkfreq * 1 + cnt)
    

    Just to reiterate, cogs don't have any effect on how variables are accessed in Spin. The trick comes when you want to share variables among several objects.

    @Mike, sorry for cutting in line.

    I guess it's time for me to stop procrastinating and get back to work.
  • xanaduxanadu Posts: 3,347
    edited 2014-04-05 14:57
    msrobots wrote: »
    I do not know why you use another cog in your Obj1.

    You are mixing two concepts here. What is the goal you want to archive?

    You are starting a parallel process counting its own variable down from 10 to zero. One time. then this cog finishes.

    you also call obj1num := obj1.go

    thus calling the same thing once from main. And return the RESULT which is simple 0 since you do not set RESULT in GO it will return RESULT as 0.

    All expected behavior.

    Give a example of what your expected output in PST should look like and I may be able to build a small example for you.

    Enjoy!

    Mike

    Thank you. My goal is to find a bare bones example of how to access global variables produced by other cogs in other objects. All of this is part of building my robot in the projects section. I have a PWM object and an encoder object (both not written by me) producing variables I'd like to be able to access from my main program which I am writing personally. I'd like to just leave the objects I'm not writing fully intact, and call on them when needed.

    In order to do that I have decided to stop messing with that code, and write my own very simple object that calls another cog, and makes that cog produce a variable, then display it in my main program. So the inoperative example I posted was supposed to be a minimal code example of passing around variables.

    The output should look like this. My main object (main1) counting up while the child object (obj1) counts down.
    PST Online
    Main:1
    Obj1:10
    Main:2
    Obj1:9
    Main:3
    Obj1:8
    Main:4
    Obj1:7
    Main:5
    Obj1:6
    Main:6
    Obj1:5
    Main:7
    Obj1:4
    Main:8
    Obj1:3
    Main:9
    Obj1:2
    Main:10
    Obj1:1
    End Program
    
    

    In my altitude hold project which works as far as sharing the variable goes in the main program I have this:

    I can display the "balt" var on the pst no problemo.

    Main Object:
    balt := alt.altitude(alt.average_press) / 30
    

    That pulls the variable from the altimeter object with no problems. I can't seem to wrap my head around why it won't work the same way in my code above:

    Altimeter Object:
    PUB altitude(mb) : alt | i, p, p2, x, qm, q0, q1, q2
    
    
      {{ Given the local pressure in hundredths of a millibar and the predetermined air pressure
         at sealevel, return the current altitude in centimeters (hundredths of a meter).
      ''
      '' `Parameters:
      ''
      ''     `mb: Pressure reading in hundredths of a millibar.
      ''
      '' `Return: What gets returned, or 'none'.
      ''
      '' `Example: Sample method call.
      ''
      ''     Explain what the sample call does.
      '-     Next lines, if needed...
      }}
    
    
      'Correct the local pressure for the pressure at sea-level:
      
      mb := ((_umultdiv(mb, constant(SEA_PRESS_STA << 2), sea_press) >> 1 + 1) >> 1) <# $1_f7ff #> $800
    
    
      'Compute an index into the table, plus fractional values for interpolation:
      
      i := mb >> 11
      p := mb & $7ff
      p2 := p * p
    
    
      'Copy the four table values surrounding the pressure into the local variables:
      
      longmove(@qm, @alt_table[i - 1], 4)
    
    
      'Compute the altitude using cubic interpolation:
      
      alt := (qm << 1) - 5 * q0 + (q1 << 2) - q2
      alt := (p2 ** alt) << 9 + (p2 * alt) >> 23 + (p2 ** (p * (3 * (q0 - q1) + q2 - qm))) ~> 2 +  (p * (q1 - qm)) ~> 12 + q0
    
  • xanaduxanadu Posts: 3,347
    edited 2014-04-05 14:59
    Duane, thank you the more examples the better, I really appreciate it.

    I will run this example now and see if I can understand it better than what I am trying to do. Thanks again.
  • msrobotsmsrobots Posts: 3,709
    edited 2014-04-05 15:22
    Ah. I see your problem.

    Every Spin Medthod has a implicit existing local variable named RESULT. In opposite to all local vars you define it is set to zero by default.

    If you do not end your Method with a explicit RETURN someVar a RETURN RESULT is the default behavior.

    Here now comes the crude part. If you do not like the name RESULT for thet return Variable you also can rename it.

    look at

    PUB altitude(mb) : alt | i, p, p2, x, qm, q0, q1, q2

    here alt is renaming result.
    : alt
    all other local vars are defined after the |
    | i, p, p2, x, qm, q0, q1, q2

    so now PUB altitude(mb) has a implicit 'RETURN alt' at the end.

    and that is the value you get by calling

    balt := alt.altitude(alt.average_press) / 30

    in your code above you just return 0 since RESULT is not set to anything else.

    Duane showed a solution for alternate output.

    Enjoy!

    Mike
  • xanaduxanadu Posts: 3,347
    edited 2014-04-05 16:00
    I made an example a little more simple, but I'm still getting an unexpected result:

    Main
    '' Cogs and VARs version 1 Main Program 
    
    
    OBJ
    
    
     PST       : "Parallax Serial Terminal"
     OBJ1      : "Object1"
      
    CON
       
     _clkmode = xtal1 + pll16x           
     _xinfreq = 5_000_000
    
    
    VAR
    
    
     long mainnum
    
    
    PUB Main | obj1num 
    
    
    '---Init Vars---
    
    
     mainnum := 1
    
    
    '---Start PST---
     
     pst.Start(115200)            
     waitcnt(clkfreq * 2 + cnt)
     pst.str(string("PST Online"))
     pst.newline
    
    
    '---Begin Object 1---
    
    
     obj1num := OBJ1.Start            'get Object1 VAR
    
    
    '---PST VAR from this object---
    
    
       pst.str(string("Main:"))
       pst.dec(mainnum)               'should be 1
       pst.newline
       
    '---PST VAR from Object1---
      
       pst.str(string("Obj1:"))
       pst.dec(obj1num)               'should be 10
       pst.newline  
    
    
    '---End Program---
    
    
     pst.str(string("End Program"))
    
    
     waitcnt(clkfreq / 500 + cnt) 
    
    
     pst.stop 
    
    
    

    Object 1:
    '' Cogs and VARs version 1 Object 1
    
    
    OBJ
    
    
    
    
       
    CON
    
    
    
    
    VAR
    
    
     long obj1num
     
    PUB Start   
    
    
      obj1num := 10
    
    
      result := @obj1num 
                    
    

    PST Window Result:
    PST Online
    Main:1
    Obj1:1484
    End Program
    
  • kuronekokuroneko Posts: 3,623
    edited 2014-04-05 16:24
    You return an address so you have to dereference it, i.e. pst.dec(long/COLOR]obj1num[COLOR="#FF8C00").
  • xanaduxanadu Posts: 3,347
    edited 2014-04-05 17:35
    kuroneko wrote: »
    You return an address so you have to dereferenc it, i.e. pst.dec(long/COLOR]obj1num[COLOR=#FF8C00).

    Oh right, like Duane said twice already... I changed that and now it works.

    Thanks everyone for your help, I much appreciate being unstuck on this one!
  • msrobotsmsrobots Posts: 3,709
    edited 2014-04-05 18:22
    xanadu wrote: »
    Semi-pro meat servo.

    Wow. It took me about 2 weeks to get the meaning of that footer. I guess. It is irritating me for a while now.

    So when you finish that school you talked about going to in that other thread you will be a professional meat servo?

    Enjoy!

    Mike
  • xanaduxanadu Posts: 3,347
    edited 2014-04-08 17:02
    msrobots wrote: »
    Wow. It took me about 2 weeks to get the meaning of that footer. I guess. It is irritating me for a while now.

    So when you finish that school you talked about going to in that other thread you will be a professional meat servo?

    Enjoy!

    Mike

    I guess depending on how you use the word professional hahaha. The other day I thought I had a servo going bad because the autopilot was climbing way over the pre-selected altitude. Sure enough I had the wrong barometric pressure programmed in. Semi-pro move for sure...
Sign In or Register to comment.