Wait inside a function in robotc?

If I have code that looks something like this,


void functionOne() {
  doSomething;
  wait1Msec(1000);
  doSomethingElse;
}

void functionTwo() {
  doSomething;
}

task main() {
  functionOne();
  functionTwo();
}

I am wondering if the program will wait for the completion of fucntionOne before calling functionTwo, or if it will just run the second function while the first one is waiting. If it does the latter by default, is there anyway to wait for completion before moving on to the next function?

Thanks in advance.

Yes, the main program will wait for the completion of functionOne before calling functionTwo.

If you wanted the two functions to run at the same time, then you could use a task.

Okay, thanks for the quick reply!

What you are describing is blocking behavior.

Blocking basically means that a code block must finish before the next command is executed.

Not everything blocks. Some calls, like say setting the value of a motor are non-blocking. That is they return immediately without necessarily having done their job. Another process comes along, and reads data set by the call and uses it to set the motors periodically.

There are languages that are designed to be completely non-blocking. Node.js for example. There are advantages, namely speed but this is far beyond the scope of the current state of robotics here in VEX.

TL | DR : Yes.

I understand what you mean about setting a motor. Once a motor is set, it will keep running unless something somewhere in the program shuts it down. But what do you mean about some calls return “without necessarily having done their job”? I’m relatively new to RobotC, so I’m just curious/worried I don’t understand how all of these functions might work. Can you give an example of what you mean by the called function not having done its job?

If you call the function that prints to the debug stream, it will place the data into the buffer of the stream. The program will continue on. The firmware will then output the buffer to the stream. In this way, the function is not directly calling the action of printing to the stream because it is only writing to the buffer.

An analogy,

Your teacher makes a homework assignment due at a certain time.

The day of class comes and she asks everyone to turnInTheirWork().

So the students start to turnInTheirWork(), forming a little loop like so…

for(int i = numStudents; i > 1; --i) {

	turnInTheirWork(assignment);

}

What does the teacher do?

If she blocked and fully did the work that would mean that she would have to…

// Receive the work
takeAssignment(assignment);

// Grade it on the spot
grade(assignment);

// Mark the grade in the gradebook
record(assignment);

and hand it back to the student.
return assignment;

So the loop would look like so…

for(int i = numStudents; i > 1; --i) {

	// BEGIN INSIDE OF turnInTheirWork

	// Receive the work
	takeAssignment(assignment);

	// Grade it on the spot
	grade(assignment);

	// Mark the grade in the gradebook
	record(assignment);

	//and hand it back to the student.
	return assignment;

	// END INSIDE OF turnInTheirWork

}

But wait what if it takes the teacher 5 minutes to grade each assignment? 30 students x 5 minutes is two and a half hours.

Sure the teacher HAS to spend that much time on the work anyway, but now you have a line of students waiting aswell for this work to be done. They could be doing “more productive” things.

So instead let’s tweak this a bit.

Instead of doing ALL the work immediately, the teacher will just take the assignments and put them into a pile. She’ll later get around to actually grading the work and students can check back with her at a later time to get the status of their assignment and/or receive their grade if theirs has been graded.

TO BE CLEAR HERE, the teacher still has to do the work. This means that another computer, thread, task, process, etc. must regularly check the pile for work and when work is present begin processing said work in the background (relative to the program we’re running with the students all queued up).

So lets say it takes all of 2 seconds to just hand in an assignment. 2s x 30 = 1 minute.

So the students only need to wait in line at most one minute vs 2.5 hours thanks to a non-blocking or asynchronous model.

Believe me this is exactly how computers work. The times are usually in uS and mS but the same kind of 1m vs 2.5h savings does happen when you architect non-trivial programs in better ways.

For a computer things that normally take a while are disk I/O, reaching out to the network or kicking off a large loop.

A slightly more complex example would be what my calculus dept. did to grade our finals. All the students handed in their work to one large pile and more than one teacher graded the work. This is a form of parallel processing as all three teachers worked on the grading at the same time. As you can imagine this not only feed the students of having to wait, but it also had the effect of getting the work done much faster. Instead of the students having to ultimately go without their grades for 2.5 hours if there were 5 teachers to grade work they’d only have to wait 30 minutes.

Now say there are 1,500 teachers. We call that a GPU and it grades very quickly.

-Cody

I was just wondering how many specific RobotC features display that kind of behavior, for example the debug stream that Eric pointed out.

James will know better.

At least setting motors works this way. The values are written somewhere and later read by the master process thing at regular intervals of 20ms.

So basically what I meant was, you tell a motor to run now.

Your code doesn’t block, it returns immediately.

That DOES NOT mean that you can assume that the motors instantly get power. They don’t. Somewhere in the next 0-20ms the master process thing comes around, reads your request to set the motors to a certain power and does it.

In fact you really can’t assume they’ll get power at all. The master process will not power your motors if the competition controller has disabled your robot.

It’s also why you don’t have to clamp the motor values. The master process does it for you.

I can’t think of any functions in ROBOTC that are truly blocking. Even wait1Msec isn’t really a blocking function, it asks the real time kernel to put the current task to sleep so other tasks can run. When I think of a blocking function it usually involves some kind of IO operation, waiting for a character to be typed on a keyboard or communication on a serial port, things like that.

Motor control in ROBOTC (and the other languages for the cortex) needs a whole bunch of cascaded operations. As Cody explained, in ROBOTC when you use Motor[port] = value; all this does is change an internal variable. A supervisor task reads this variable periodically and, in the case of ports 2 through 9, sends it off to the other micro-controller contained within the cortex. This in turn creates a variable width pulse that occurs about once every 18mS. The motor controller MC29 decodes this pulse and then creates a different type of control pulse for the motor itself. The timing of this is hard to determine, all these things are happening asynchronously, when you command a motor the best case delay is probably about 5mS, the worse case is greater than 30mS.
Some old analysis in this post.
https://vexforum.com/showpost.php?p=217690&postcount=1

This is one reason (well, perhaps the only) that PID control using ports 2 through 9 is not as good as ports 1 and 10.

That’s interesting. Thanks Cody, Eric, and jpearman. :slight_smile: