PDA

View Full Version : Inter-Cog Communication



ReiserificK
01-13-2009, 10:09 AM
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

mctrivia
01-13-2009, 10:42 AM
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

SRLM
01-13-2009, 11:22 AM
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[pin]~
dira[pin]~~

idealHolder := LONG[ideal]
rampHolder := LONG[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[pin]~~ ' If pulse width is non-zero
waitcnt(w + cnt) ' produce the requested pulse
outa[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

mctrivia
01-13-2009, 02:21 PM
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

StefanL38
01-13-2009, 09:38 PM
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[ 20]
long CogStack1[ 20]
long CogStack2[ 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@USA
01-13-2009, 11:31 PM
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 Baker
01-14-2009, 04:40 AM
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 (mailto:pbaker@parallax.com)

SRLM
01-14-2009, 06:48 AM
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.