Has anyone figured out how to multitask on vex c++? Our coder can’t figure it out, and I’ve looked up tutorials and only found one on how to change your background in vcs.
To multitask on vex c++, I am pretty sure you must perform a “non-blocking” function. In the “Drive for Distance” Template provided by vex there is an example of a non-blocking function. It looks something like this.
LeftMotor.rotateFor(howmanydegrees, vex::rotationUnits::deg, false); //This command must be non blocking
RightMotor.rotateFor(howmanydegrees, vex::rotationUnits::deg);
I believe false is what allows for non-blocking in like autonomous scenarios. For basic user button control for like motor speed I think it works similarly to robotc.
I might be wrong though but doesn’t hurt to give it a go lol.
EDIT: In Vex C++ Pro you can give task priority as well.
http://help.vexcodingstudio.com
look for vex::task and vex::thread.
They have the same internal functionality, vex::task is most similar to ROBOTC.
Thanks! I’ll have our lead coder take a look at it
I’m not positive I fully understand this, so correct me if i’m wrong.
this robotc code:
task armtask()
{
while(true)
{
motor[arm]=127*(vexRT[Btn5U]-vexRT[Btn5D]);
}
}
task main()
{
startTask(armtask);
//more code
}
could be replaced with this vex robot c++ code(?)
void armtask()
{
while(true)
{
Arm.setVelocity(100*(Controller1.ButtonR1.pressing()-Controller1.ButtonR2.pressing()), velocityUnits::rpm);
}
}
int main()
{
vex::task(armtask(), 1);
while(true)
{
vex::task::sleep(1);
}
}
or in other words, instead of creating a separate task, I instead create a void, and then when I call it, I call it as a task rather then a function in my int main?
pretty close.
example using vex::task class.
vex::brain Brain;
int myTask() {
int count = 0;
while(1) {
Brain.Screen.printAt( 10, 60, "I am the other task %d", count++ );
// don't hog the cpu :)
vex::task::sleep( 25 );
}
return(0);
}
int main() {
int count = 0;
// this is similar to startTask
vex::task t( myTask );
while(1) {
Brain.Screen.printAt( 10, 30, "Hello from main %d", count++ );
// Allow other tasks to run
vex::task::sleep(10);
}
}
example using vex::thread class
vex::brain Brain;
int myThread() {
int count = 0;
while(1) {
Brain.Screen.printAt( 10, 60, "I am the other task %d", count++ );
// don't hog the cpu :)
vex::this_thread::sleep_for( 25 );
}
return(0);
}
int main() {
int count = 0;
// this is similar to startTask
vex::thread t( myThread );
while(1) {
Brain.Screen.printAt( 10, 30, "Hello from main %d", count++ );
// Allow other tasks to run
vex::this_thread::sleep_for(10);
}
}
So why do we have two different versions of the same thing.
vex::task has methods that will be familiar to ROBOTC users. methods such as setPriority and stop.
vex::thread has methods that will be familiar to users of the C++ standard library. methods such as join.
threads can also take more the complex parameters that the C++ standard library uses.
vex::this_thread::sleep_for( std::chrono::seconds(1) );
(although we will be sticking to using milliseconds in most examples as that is what ROBOTC used)
Can you replace the “t” with start/stop? I tried it in VCS and it didn’t show any errors.
So the “t” is the name of the task.
vex::task t( myTask );
is the object version of
int count;
What determines the name of the task? And how would you stop the task? I tried the
vex::task.stop( task name? );
and it gives back an error saying that the period shouldn’t be there. If I take out the period, it doesn’t give an error but then I can put
vex::task hgsvbndskjffdsh( task name? );
and it also doesn’t give back an error.
Thanks @jpearman . I’ve been debating how to approach some of this with my students, and I think seeing comparisons like this along with style choices will help.
Also, when I went back and forth between this thread and the documentation I noticed that the vex::thread.thread page is broken.
To me that sounds risky. I don’t really love “t,” either, but it’s not so risky and it’s just a quick example. If you use “start” or “stop,” you are creating an object of the class task with the name “start” or “stop.” So later you may be typing things like “start.stop” when stopping the task you’ve named “start.”
I get the feeling from what you’re asking that you’re thinking of tasks like they were before in RobotC. Not long ago people spent some time explaining why I was so wrong about wanting to pass arguments to tasks. Of course, their very statements could have been made just as well about passing arguments to functions, and we know that is handy. Anyway, I think people will soon start seeing the value of what I was pointing out. Now you can start multiple instances of identical tasks that do not all use the same information. For example, consider creating a PID task inside a new class you design for any motor system (could have multiple motor or just one). Any one use of the PID task will use the information from within and apply to its own motor system, and you could have one for the drivetrain, one for an arm, etc. all working off of the one written task.
So here, what would you like to name this particular object so you will recognize it? Do you really want to call it “start” or “stop”? Consider this variant on what @jpearman wrote:
vex::brain Brain;
int myTask() {
int count = 0;
while(1) {
Brain.Screen.printAt( 10, 60, "I am another task %d", count++ );
// don't hog the cpu :)
vex::task::sleep( 25 );
}
return(0);
}
int main() {
int count = 0;
// this is similar to startTask
vex::task t1( myTask );
vex::task t2( myTask );
while(1) {
Brain.Screen.printAt( 10, 30, "Hello from main %d", count++ );
// Allow other tasks to run
vex::task::sleep(10);
}
}
I wasn’t clear. You are creating a “task” object and giving it a function to call. What you name the task object is up to you. Just like when I create an integer named count. It could have been named anything else, like “counter” or just the letter “a” or the letter “t”.
You really should read an introduction to object oriented programming so you follow how I am using the word “object”.
I understand now! Thank you for the explanation. I will be sure to read up more on object oriented programming.
Yes, I was about to ask similarly about this. Do read up on OOP. It doesn’t take long to pick up the difference. But without knowing, the style is quite different enough to be very confusing.
As for your other question:
Did you notice these two parts of @jpearman 's code:
vex::brain Brain;
Brain.Screen.printAt( 10, 60, “I am another task %d”, count++ );
So “Brain” is what he has named an object of the class vex::brain. Then he uses “Brain” followed by “.” and whatever the rest of it is to do things. So if you look up vex::brain, you’ll see vex::brain.Screen, which itself is of the type vex::lcd. When we look at that we find vex::lcd.printAt. So you see Brain.Screen.printAt(parameters).
As for this particular one: t.stop() will do it.
Some slightly more familiar syntax that might make it easier to understand what’s happening would look like this:
// instead of
vex::task t1(myTask);
// you could also write
vex::task t1 = vex::task(myTask);
// or if you want to be more modern then you can use the auto specifier instead
auto t1 = vex::task(myTask);
However, autocomplete in Vex Coding Studio doesn’t seem to be able to deduce types when using auto, which is a bit disappointing considering that it’s becoming standard practice to use it.
Is it necessary to call the thread to sleep, or will the schedular allot a certain amount of CPU time to each task and alternate automatically? Am I correct in thinking that if I had an infinite loop and created a thread separate from the main thread, the main thread would continue to run, while the separate infinite loop in the thread would also continue, with CPU time being shared with both, or do i need to manually sleep each thread so the other can run?
Thanks
The scheduler in VCS is cooperative, that means that threads should try and yield time to the others if they have no immediate processing to do. Loops that are using API functions, things like setting motors or checking the controller, will automatically be forced to yield if they run for too long. Loops that do not use API functions would block all other threads from running so this…
while(1) {
;
}
Would not be good idea.
ROBOTC could handle loops like that as it used a virtual machine. As code compiled for the V5 is native that’s much harder to achieve.
Okay, that makes sense, thank you!
So, @jpearman how would you recommend continuous checking of buttons/something rather than a while(true) loop?
He means the loop needs a delay at the end. Just like has been common practice in ROBOTC for years.