skuleguy

Hi all,

I'm trying to activate an array of port<RaycastResult>, please first take a look at the Start method below. I realized, through tracing/ printing stuff out, that the highlighted for loop has already run 3 times without even running the Activate() block. Like the Activate() block is completely ignored. I didn't put any constraints on this.

The output of the service also be seen here:

http://farm2.static.flickr.com/1335/1244239654_d66f6515f3_o.jpg

Thanks a lot guys,

Code Snippet

protected override void Start()

{

InitializeState();

_laserResultPort = new Port<RaycastResult>[_state.NumberOfRover];

for (int j = 0; j < _state.NumberOfRover; j++)

{

_laserResultPort[j] = new Port<RaycastResult>();

}

base.Start();

SetupCamera();

PopulateWorld();

_timerPort.Post(DateTime.Now);

Activate(Arbiter.Receive(true, _timerPort, TimerHandler));

_state.DistanceMeasurements = new int[_state.NumberOfRover, 361];

_state.AngularRange = new int[_state.NumberOfRover];

_state.AngularResolution = new double[_state.NumberOfRover];

for (int roverID = 0; roverID < _state.NumberOfRover; roverID++)

{

System.Console.WriteLine("roverID outside Activate() = " + roverID.ToString());

Activate(Arbiter.Receive<RaycastResult>(

true,

_laserResultPort[roverID],

delegate(RaycastResult latestResult)

{

int initValue = (int)(LASER_RANGE * 1000f);

for (int pointCount = 0; pointCount < (latestResult.SampleCount + 1); pointCount++)

{

System.Console.WriteLine("roverID inside Activate() = " + roverID.ToString());

//THE ABOVE LINE GIVES 3

_state.DistanceMeasurements[roverID, pointCount] = initValue;

//_state.DistanceMeasurements[pointCount, roverID ] = initValue;

System.Console.WriteLine("point count value " + pointCount.ToString());

}

foreach (RaycastImpactPoint pt in latestResult.ImpactPoints)

{

_state.DistanceMeasurements[roverID, pt.ReadingIndex] = (int)(pt.Position.W * 1000f);

}

_state.AngularRange[roverID] = (int)Math.Abs(rover[roverID].RoversLaser.RaycastProperties.EndAngle

- rover[roverID].RoversLaser.RaycastProperties.StartAngle);

_state.AngularResolution[roverID] = rover[roverID].RoversLaser.RaycastProperties.AngleIncrement;

LogInfo("rover " + roverID.ToString() + " receives " + _state.DistanceMeasurements[roverID, 150].ToString());

}));

}

}



Re: Microsoft Robotics - Decentralized Software Services (DSS) Problem Activating an array of ports

skuleguy

Oh, by the way,

I have tried replacing "roverID" (the count in the strange For loop) with 0,1,2 (copy and paste the same code more times). And it works great. But that's not programming.

Please someone tell me what is going on with the FOR loop and Activate() method describe in the post above.

Thanks,





Re: Microsoft Robotics - Decentralized Software Services (DSS) Problem Activating an array of ports

George Chrysanthakopoulos

Hi please review the CCR User guide. In there you will see that Activate is a non-blocking call. This means it will return instantly.

In your code example you activate on a Receiver that is *persisted*. You only need to activate ONCE on a persisted receiver since it will stay attached to the port and consume any message. So your for-loop right now is attaching *3* receivers, all competing with others, which is not what you want.

Example sin the simulated laser range finder service show how to listen for ray cast messages the proper way. And once again, i recommend a carefull review of the CCR user guide since it will answer lots of future questions Smile

thanx

g





Re: Microsoft Robotics - Decentralized Software Services (DSS) Problem Activating an array of ports

skuleguy

hi George,

Pardon me if you didn't understand you well. But what I wanted was to activate 3 receivers on 3 different ports.

Each of them gets his own unique message. Because I had done this earlier:

Code Snippet

rover[0].RoversLaser.Register(_laserResultPort[0]);

rover[1].RoversLaser.Register(_laserResultPort[1]);

rover[2].RoversLaser.Register(_laserResultPort[2]);

So when i tried to use the for loop, the desired effect is the following snippet. I tried this snippet, and it worked correctly.

Code Snippet

Activate(Arbiter.Receive<RaycastResult>(

true,

_laserResultPort[0],

delegate(RaycastResult latestResult)

{

}));

Activate(Arbiter.Receive<RaycastResult>(

true,

_laserResultPort[1],

delegate(RaycastResult latestResult)

{

}));

Activate(Arbiter.Receive<RaycastResult>(

true,

_laserResultPort[2],

delegate(RaycastResult latestResult)

{

}));

Thanks again for your help,





Re: Microsoft Robotics - Decentralized Software Services (DSS) Problem Activating an array of ports

Rob Sim -- Braintech

Let me make sure I understand correctly, and then give my guess as to what the problem is.

You are activating three handlers using a for loop. As George points out, because you're using Activate rather than yield return, the Activate calls will return immediately, and so it is perfectly reasonable that you'll see the output of the first WriteLine for all three loop iterations before any of the activated receivers get cpu cycles (they will run concurrently).

You also note that unrolling the loop solves the problem.

Your screenshot holds a big clue (next time cut and paste the output!). It shows the loop running three times but then the first receiver to get activated is spitting out an ID of 3, rather than 0, 1 or 2. My guess is that an exception is thrown or the thread crashes and that's why you don't see the other receivers return.

So, why 3 This has to do with the scoping of variables in delegates, and it's not something I'm an expert in, although I've run into this problem before and I'll try to give my best shot at an explanation. The 'roverID' variable lives inside the Start() method, and each time the loop iterates it gets incremented. When the delegate executes, it looks to that same location for the value of roverID, but by the time it executes it's 3 and not 0, 1, or 2. You can think of it as passing a value type by reference whenever you instantiate a delegate that references variables outside it's body. Or another way to say it is that the location, not the value, of roverID is what gets bound to the delegate.

I think Aaron Lahman posted some comments on this issue a while back. Take a look at the end of this thread:
http://forums.microsoft.com/MSDN/ShowPost.aspx PostID=1544632&SiteID=1


Hope this helps!





Re: Microsoft Robotics - Decentralized Software Services (DSS) Problem Activating an array of ports

Rob Sim -- Braintech

Just a follow-up to my post. Here's a link to the msdn page on anonymous delegates. See the remarks section for the treatment of outer variables. The key point is that any outer variables are captured by reference, rather than value:
http://msdn2.microsoft.com/en-us/library/0yw3tz5k(VS.80).aspx







Re: Microsoft Robotics - Decentralized Software Services (DSS) Problem Activating an array of ports

skuleguy

Thanks Rob for your reply,

It looks like the problem is much bigger than I thought... So in short, isnt there a way to repetitively pass an increment variable into an activate block

Please let me know if what i was trying to do is possible (activating 3 ports, each of which is part of an array of ports).

Thanks so much, Rob, and George,





Re: Microsoft Robotics - Decentralized Software Services (DSS) Problem Activating an array of ports

George Chrysanthakopoulos

Hi, you should not be using activate since you are trying to block on something happening.

Use an Iterator, and yield return. But if you do use an iterator *make sure* you yield to one time (persist = false) receivers.

This way when each loop iteration executes, the previous one has finished.

But before attempting to work around your current code block think about what you are trying to do: DO you want to receiver laser notifications and react to them then why the loop Just activate a presisted handler and as notification come in, do something. Again, please review the simulated laser finder service code, it has examples of exactly this.

I strongly urge you to spend the time reading through the CCR user guide since in the end you will actually be able to finish your project faster and you will have the right knowledge to approach many of these situations.

thanx

g





Re: Microsoft Robotics - Decentralized Software Services (DSS) Problem Activating an array of ports

Rob Sim -- Braintech

Argh. Firefox just ate my reply for lunch. Let's try again. Sorry for the formatting, but the 'mark code block' button is broken for me.

It's reasonably straightforward to fix this. Declare a function that takes an int roverID and returns a delegate. The int gets bound to the local scope of the function and isn't affected by changes to roverID outside its scope:

IteratorHandler<RaycastResult> MakeRaycastResultHandler(int roverID)
{
int local=roverID;
return delegate(RaycastResult r) {
// the body of your delegate. Note, you want to reference 'local' when you need roverID.
};
}

Your activate block now looks like this (nb, I switched to ReceiveWithIterator but the basic idea still applies with Receive, off the top of my head I don't know how that changes the return value of MakeRaycastResultHandler.

for (int roverID = 0; roverID < _state.NumberOfRover; roverID++)

{

System.Console.WriteLine("roverID outside Activate() = " + roverID.ToString());

Activate(Arbiter.ReceiveWithIterator<RaycastResult>(

true,

_laserResultPort[roverID],

MakeRaycastResultHandler(roverID)));


}






Re: Microsoft Robotics - Decentralized Software Services (DSS) Problem Activating an array of ports

skuleguy

to George: With all due respect, I will read the whole CCR Guide thoroughly before starting to work on anything else today. I hope my posts did not make it look like I constantly disregard your advice. If it did, by any chance, please excuse me. I really appreciate your help all along, man.

to Rob: Thank you Rob, I really appreciate your help. I will try it out and let you know the outcome as soon as I can.

Have a nice day, guys





Re: Microsoft Robotics - Decentralized Software Services (DSS) Problem Activating an array of ports

Rob Sim -- Braintech

George, just to make sure we're all on the same page- he's trying to activate a set of persistent receivers from the Start() method- no chance of using yield return unless you spawn an iterator to do the work (in which case we still have this scoping bug). Likewise, any approach like Interleave.CombineWith will run into the same problem if you're passing delegates. It's perfectly reasonable here to spawn the activations as concurrent tasks, provided the delegates can eventually run truly concurrently.

That said I haven't looked at how the MSRS examples approach the laser stuff and there may be a better overall approach.


My $0.02.
R





Re: Microsoft Robotics - Decentralized Software Services (DSS) Problem Activating an array of ports

George Chrysanthakopoulos

Then i need to improve the user guide since it did not answer your question Smile

Did you get a chance to review the sim laser service it talks to the laser entity and registers for notifications (with just a few lines of code).