Shop OBEX P1 Docs P2 Docs Learn Events
Inter-Cog Communication — Parallax Forums

Inter-Cog Communication

ReiserificKReiserificK Posts: 24
edited 2009-01-13 23:48 in Propeller 1
Hi everyone, I have been working on a SPIN program to control a formerly-remote-conrol car, and I am having some problems. I've done some searching but havent come up with anything directly related to my main problem. I am using one cog to send pulses to the motor controllers and another to poll sensors/make decisions. I am currently storing commands in the form of numbers in a word/long (cant remember which size is readable/writeable in one clock cycle, I'll have the source in front of me tomorrow) and passing the address of these variables to the new cog as it starts. I havent gotten this to work, and I havent figured out a debug method yet (lcd,terminal,etc). However, I think the problem involves the motor control cog reading these variables, as the code works on its own. Am I going about this in the right manner? How would you guys suggest I transmit commands between cogs? Any suggestions greatly appreciated.

Thanks very much

Comments

  • mctriviamctrivia Posts: 3,772
    edited 2009-01-13 03:42
    i am trying to do this myself in assembly with no luck yet but here is an example in spin

    http://obex.parallax.com/objects/91/

    I did not write it
  • SRLMSRLM Posts: 5,045
    edited 2009-01-13 04:22
    Below is some code that I've used to do a very similar thing. These are code snippets, but you should get the idea. The first program is the main (descision making structure) and the second program is the drive program. The main program declares all the variables used in the entire collection of programs. Then, for each program that it launches it gives the address to the new object. The exception to this is for things like pin numbers, which should never change. In that case, it's passed by value. Note that this totally violates all sorts of good, object oriented programming priniciples. Namely, that on program will access a variable for read in two consecutive places, and assumes that it will be the same both time. However, another program may change the value between the access of the first program, thereby creating all sorts of problems.

      'Start serial communication, and wait 2 s for Parallax Serial Terminal connection.
      debug.Start(31, 30, 0, 57600)
      'waitcnt(clkfreq*6 + cnt)
      drive.start(pinDrive, pinSteer, @idealDrive, @idealSteer, @rampDrive, @rampSteer)
      obstacle.start(pinSpinServo, pinSpinPing, pinFrontPing, pinRearPing, pinFrontBump, pinRearBump, @headingValues, @frontPing, @rearPing, @frontBump, @rearBump, @pingSpinCount)
    
    



    {{Note that the variables given for ideal and ramp are the addresses: I use it to access the variable in real time}}
    PUB Start(newPinDrive, newPinSteer, newIdealDrive, newIdealSteer, newRampDrive, newRampSteer) 
    
      pinDrive := newPinDrive
      pinSteer := newPinSteer
    
      idealDrive := newIdealDrive
      idealSteer := newIdealSteer
    
      
      rampDrive := newRampDrive
      rampSteer := newRampSteer
    
      realSteer := center
      realDrive := 1500
    
      uS := clkfreq / 1_000_000 
    
      cognew(run, @runStack) 
    
    
    
    PRI run
    
      'this is launced into a new cog, and does three things:
      'Checks the values of variables and updates as needed
      'Pulses the steering servo and motor
      'waits 20 ms
    
    
      repeat
        'getValues
        servoProcess(pinDrive, realDrive, idealDrive, rampDrive)
        centerSteering
        servoProcess(pinSteer, realSteer, @modifiedSteer, rampSteer)
        waitcnt((uS*1000*20) + cnt)
    
    PRI servoProcess(pin, real, ideal, ramp) | w, length, idealHolder, rampHolder
    
    {{
    
    real is the speed/position that the servo is at now
    ideal is where the servo should be
    ramp is the speed at which to go there
     0-set real instantly to ideal
     1-increment in 1 uS
     2-increment in 2 uS
     3-increment in 3 uS
     ...
     n-increment in n*1 uS
    
     }}
       outa[noparse][[/noparse]pin]~
       dira[noparse][[/noparse]pin]~~
    
       idealHolder := LONG[noparse][[/noparse]ideal]
       rampHolder := LONG[noparse][[/noparse]ramp]
    
       if(rampHolder == 0)
         real := idealHolder
       else
          if(real < idealHolder)
             real := real + rampHolder
          elseif( real > idealHolder )
             real := real - rampHolder
          if ( real > (idealHolder - rampHolder) AND real < (idealHolder + rampHolder))
              real := idealHolder
    
       length := real
    
       w := length * uS
       outa[noparse][[/noparse]pin]~~               ' If pulse width is non-zero
       waitcnt(w + cnt)          '  produce the requested pulse
       outa[noparse][[/noparse]pin]~
    
    
    



    Also, note that the ramp ability isn't really implemented yet. It has a bug, and I haven't gotten around to fixing it. However, the inter cog communication is still viable and works well.

    Here is a link where I disscussed propeller general questions, including inter object and cog communication.
    http://forums.parallax.com/showthread.php?p=765086
  • mctriviamctrivia Posts: 3,772
    edited 2009-01-13 07:21
    here is how to comunicate between cogs in assembly

    CON
      _clkmode      = xtal1 + pll16x
      _xinfreq      = 5_000_000
      
    Dat
      var  long  0
    
    PUB start
      ptrToVar := @var                        
      cognew(@TimeKeeper,0)
    
    DAT
                  org       0
                  
                  
    TimeKeeper    rdlong    localVal,ptrToVal
    
    ...do something...
                  wrlong    localVal,ptrToVal
    
    localVal    long    0
    ptrToVar    long     0
    
    
  • StefanL38StefanL38 Posts: 2,292
    edited 2009-01-13 14:38
    Hello,

    variable-access across cogs

    here is a code-example showing access to a variable from different cogs within the same *.SPIN-File
    you simple use the NAME of the variable itself

    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
    
      
    VAR
      long heart_stack[noparse][[/noparse] 20]
      long CogStack1[noparse][[/noparse] 20]
      long CogStack2[noparse][[/noparse] 20]
      
      long MyTestVar
    
    OBJ
      'heart : "heartbeat" 'little object from the obex making an LED blink  
      debug : "FullDuplexSerial"
    
    
    PUB Main
    'the FIRST PUB-Method inside a spinfile is ALWAYS the startpoint where the program starts to run
      'heart.Start(27, 200)
      debug.start(31, 30, 0, 9600)
      
      MyTestVar := 100
      debug.str(string("Start MyTestVar="))
      debug.dec(MyTestVar)
      debug.Tx(13)
    
      cognew(M1,@CogStack1)
      cognew(M2,@CogStack2)
      
      repeat
        waitcnt(clkfreq + cnt)
        debug.str(string("MyTestVar="))
        debug.dec(MyTestVar)
        debug.Tx(13)
    
    
    
    PUB M1
      repeat
        waitcnt(ClkFreq * 3 + cnt)
        MyTestVar := 1
    
    
    PUB M2
      repeat
        waitcnt(ClkFreq * 5 + cnt)
        MyTestVar := 2
          
    
    
    



    with this democode you should get an output to your terminalsoftware similar to this

    Start MyTestVar=100
    MyTestVar=100
    MyTestVar=100
    MyTestVar=1
    MyTestVar=1
    MyTestVar=2
    MyTestVar=1
    MyTestVar=1
    MyTestVar=1
    MyTestVar=1
    MyTestVar=2
    MyTestVar=2
    MyTestVar=1
    MyTestVar=1
    MyTestVar=1
    MyTestVar=2
    MyTestVar=2
    MyTestVar=2
    MyTestVar=1
    MyTestVar=1
    MyTestVar=2
    MyTestVar=1
    MyTestVar=1
    MyTestVar=1
    MyTestVar=1
    MyTestVar=2
    MyTestVar=2
    
    
    



    As you can see from this demo
    as long as you want to use a variable from the SAME *.SPIN-file
    you just use the NAME of the variable

    It is the same as long as you want to access the variable in the SAME object
    (which is defined in another *.SPIN-File)
    therefore the variable has to be defined INSIDE that object (that *.SPIN-file)

    to get access to variables ACROSS OBJECTS the variable is defined in one object
    and the OTHER objects can access this variable through the RAM-Adress of this variable
    you get the RAM-Adress of a variable with the "@"-operator

    best regards

    Stefan
  • jmbertoncelli@USAjmbertoncelli@USA Posts: 48
    edited 2009-01-13 16:31
    Hello,

    remember also that you have to serialize the access to the variable.· Read or Write operations required to use prop lock mechanism.

    jm.
  • Paul BakerPaul Baker Posts: 6,351
    edited 2009-01-13 21:40
    Locks are not always required, if you have a single producer of data and a single consumer of data a lock is not necessary. Even in muliple data items (like a buffer) the pointer to the head of the buffer is only altered by the producer and the tail is only altered by the consumer. Locks are necessary when you have multiple producers or consumers which require multiple accesses (read-modify-write a location, or updating the head or tail pointer which is itself a RMW).

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Paul Baker
  • SRLMSRLM Posts: 5,045
    edited 2009-01-13 23:48
    Paul said...
    Locks are not always required, if you have a single producer of data and a single consumer of data a lock is not necessary.
    That's the way the code snippet above that I posted works. The main program sets the drive variables, and the drive program reads them. The sensing program sets another group of variables, and the main program reads them.
Sign In or Register to comment.