Introducing the Purdue Robotics OS (PROS) for Cortex

[Warning: Long post]

The Purdue VEX Robotics College Challenge team BLRS would like to introduce one of our biggest achievements this year. Our history as a CS team means that our club membership is almost 75% Computer Science majors itching to write code for the extended 60-second college Autonomous Period. However, neither of the available programming options (easyC or ROBOTC) satisfied us, as the choices were limited at the time to a drag-and-drop language with a slow runtime library or an interpreted bytecode system that wasn’t true C.

We created the Purdue Robotics Operating System (PROS) to move beyond these limitations and allow us to leverage our advantage. Its features include:

  • Develop on Windows, Linux, or Mac OS X using an Eclipse-based environment with one-click download and integrated source control for collaboration between our eight primary programmers
  • Unparalleled runtime library written from scratch that takes full advantage of the Cortex Microcontroller’s power (microsecond-resolution timers, full priority-based multitasking, interrupt control)
  • Direct compilation to native C allows use of structures, pointers, standard I/O, dynamic memory allocation, and functions familiar to CS students
  • Use of standard tools (GCC), coding standards (ISO C99), and function names (libc, Arduino) minimizes learning curve
  • Direct access to hardware allows interfacing the Cortex Microcontroller with a wide variety of third-party sensors to fully utilize the rules of the College Division

https://vexforum.com/gallery/files/3/8/6/1/4/pros_development.jpg

While benchmarks aren’t always the best way to describe our system’s performance, these timing and benchmark results should provide a general idea of our new system. Some of these benchmarks were taken from jpearman’s benchmarking thread. The latest versions of PROS (1r09), easyC (4.1.0.5), and ROBOTC (3.60) were tested. All tests, unless otherwise noted, were performed using a direct USB tether connection to a joystick and a VEX Programming Kit wired to the computer.

Test 1: Toggle digital output
The most accurate way to get an indication of how long something takes on the Cortex is to set an external digital port to “1”, perform the operation, set the digital port back to “0”, and measure the length of the resulting pulse with an oscilloscope. We measured how long each environment takes to simply toggle the pin on and off.


void operatorControl() {
	// Naive method of toggling pins
	pinMode(1, OUTPUT);
	while (1) {
		digitalWrite(1, HIGH);
		digitalWrite(1, LOW);
	}
}

Results:

  • ROBOTC: 3 us
  • easyC: 1.5 us
  • PROS: 1.15 us (1.3x easyC and 2.61x ROBOTC)

For actually toggling a pin in real-world scenarios, PROS features PWM drivers using the Timer units on the Cortex Microcontroller that run without any intervention on the user’s part. These timers can go as fast as 27.8 ns, but in reality only a 0.8 us period can be achieved before the signal gets garbled by capacitive load.

Test 2: Set all motors to the value of joystick channel 1
This test does not actually measure the responsiveness of each environment to operator control! As jpearman explains, motor ports update every 15 ms in easyC or ROBOTC, and the servo control signal updates every 18 ms, so the command will only reach the motor when one of these occurs.


void operatorControl() {
	// Set all motors to joystick 1
	pinMode(1, OUTPUT);
	while (1) {
		int8_t value;
		digitalWrite(1, HIGH);
		value = joystickGetAnalog(1, 1);
		for (int i = 1; i <= 10; i++)
			motorSet(i, value);
		digitalWrite(1, LOW);
	}
}

Results:

  • ROBOTC: 124 us
  • easyC: 70 us
  • PROS: 18 us (3.89x easyC and 6.89x ROBOTC)

PROS also allows synchronization with the motor update to the slave processor, as the nearly jitter-free timing system can easily be synchronized to update motors just before communication occurs. This reduces the worst-case motor update delay from 34 ms to 18 ms, giving PROS an edge in the real-world department too.

Test 3: Send a string to the debug console
To send the string “Hello\n” (6 characters) to the VEXnet system at 230400 baud, it takes 260 us. EasyC always takes this long to send a string. RobotC and PROS only take this long if many characters have been sent quickly and their internal output buffers are full.


void operatorControl() {
	// Send a string
	pinMode(1, OUTPUT);
	while (1) {
		digitalWrite(1, HIGH);
		printf("Hello\n");
		digitalWrite(1, LOW);
	}
}

Results:

  • ROBOTC: 12 us
  • easyC: 260 us
  • PROS: 12 us (21.67x easyC and 1.0x ROBOTC)

Now for our own benchmarks which we believe really demonstrate the efficiency improvements of the library and threading system of PROS.

Test 4: Serial port torture test
We programmed our vision system to send tracking updates (30 frames/second, 24 bytes/update) to the Cortex serial port UART1. A simple reader program in each language reads in the packets and counts the number of drops (packets with failed checksums).


typedef struct {
	// Packet information
} Packet;

void operatorControl() {
	// Serial port torture test
	usartInit(uart1, 115200, SERIAL_8N1);
	int failures = 0; Packet pkt;
	for (int i = 0; i < 255; i++) {
		// readPacket() returns 1 if checksum OK and 0 if checksum failed
		if (!readPacket(uart1, &pkt))
			failures++;
	}
	printf("Drops: %d\n", failures);
	while (1);
}

Results:

  • ROBOTC: 200/255 correct (78%)
  • easyC: 225/255 correct (88%)
  • PROS: 255/255 correct (100%)

Our high-speed vision system would clearly be much more difficult without PROS.

Test 5: IME blaster test
We hooked up two Integrated Motor Encoders (IMEs) to the Cortex I2C port and requested updates as fast as possible. ROBOTC and easyC poll the IMEs in the background (update rates shown in this post); PROS requires updating in a user thread. While this might seem like a hassle, it means that if a loose cable disrupts communication, only that thread will lock and the PROS kernel (and field control) will keep working. We have not had a single IME-related full lock on PROS.

User-controlled updates of IMEs also increases flexibility by allowing other I2C sensors to share the bus with VEX Motor Encoders. This gives us another port to interface third-party hardware directly to the Cortex.


void operatorControl() {
	// Poll an IME as quickly as possible
	long int x;
	pinMode(1, OUTPUT);
	imeInitializeAll();
	while (1) {
		digitalWrite(1, HIGH);
		imeGet(IME_ADDR_MIN, &x);
		digitalWrite(1, LOW);
	}
}

Results:

  • ROBOTC: 2 ms
  • easyC: 20 ms
  • PROS: 500 us (40x easyC and 4x ROBOTC)

Even if another code mistake (null pointer access, stack overflow, watchdog timer) occurs, PROS will stop all motors and automatically reboot for fail-safe behavior that has saved many VEX parts.

Test 6: Analog sampling
We attached a VEX Line Tracker to analog port 1 and timed both the average and worst case sampling time. Uniform rate sampling with low jitter is one of the most crucial parts of making a good PID controller and performing Digital Signal Processing on analog inputs.


void operatorControl() {
	// Read an analog port
	// NOT equal to the analog "Sampling Rate"; PROS samples internally at 50 KSPS, easyC at 26 KSPS, ROBOTC unknown
	pinMode(1, OUTPUT);
	while (1) {
		digitalWrite(1, HIGH);
		analogRead(1);
		digitalWrite(1, LOW);
	}
}

Results (average case):

  • ROBOTC: 6.64 us
  • easyC: 2.54 us
  • PROS: 1.11 us (2.29x easyC and 5.98x ROBOTC)

Results (worst case):

  • ROBOTC: 66 us (9.94x average case)
  • easyC: 1.4 ms (551x average case)
  • PROS: 4.5 us (4.05x average case)

Signal processing like a Kalman filter has been tested to run much more consistently on PROS.

Test 7: Threaded workload
Three threads were started in each language - one thread toggles a motor forward and reverse every 20ms, one thread prints text to the screen once a second, and one thread toggles a pin high and low with 1ms in between. We measured the maximum length of a high pulse in a 16,384 pulse batch to get an idea of threading performance and jitter. EasyC has no threads, so we used RegisterRepeatingTimer instead.


void printData(void *ignore) {
	// Print data every second
	while (1) {
		printf("Hello\n");
		delay(1000);
	}
}

void flipMotors(void *ignore) {
	// Toggle motors every 20ms
	while (1) {
		motorSet(2, 127);
		delay(20);
		motorSet(2, -127);
		delay(20);
	}
}

void operatorControl() {
	// Jitter test with threaded workload
	taskCreateSimple(flipMotors);
	taskCreateSimple(printData);
	// Flip pin again
	pinMode(1, OUTPUT);
	while (1) {
		digitalWrite(1, HIGH);
		delay(1);
		digitalWrite(1, LOW);
		delay(1);
	}
}

Results:

  • ROBOTC: 1.83 ms (83% long)
  • easyC: 2.42 ms (142% long)
  • PROS: 1.01 ms (1% long)

PROS is capable of handling threaded workloads with ease.

I could explain much more, but there’s a 10K post limit so I can’t do it now. If you have more questions, feel free to stop by the BLRS booth (college division) at Worlds. Do you think that PROS could forever change VEX programming? We believe it can.

We (the programers on our team) are getting super excited looking at this. Eclipse is something we’re familiar with, and we were already looking for an excuse to stop using EasyC. The improved multithreding and working on Linux is going to be it.

We can’t find a download link to the plugin, though. Are you going to be selling this? And are there any special instructions for installing it?

If you’re ready to distribute this, we’re ready to switch. Or at the very least, we’d like to use this next year.

Oh, and someone on my team would like to know if the VEX Speaker works with this. Kind of minor, but he wants to do something with one.

if you need any help with programming, alex michael from 278D should be able to help. he is our best programmer.

Also, assuming you are planning a release: what aout documentation or an API?

I am definitey interested in trying PROS out.

I have been a huge sceptic of many things like this that have come along, the most recent was the whole Virtual Worlds thing. I tend to go against the grain, I enjoy taking the counterpoint here and there just for game, and I’m regularly called an opinionated person. My ego is also the size of an SUV.

That being said, this… oh this is amazing. I have to know, please tell me how did you do this? What were the challenges, please tell us your story!

Where did this start, what was your first move, how do you interface with the Cortex user-processor at such a low level? The best my team was able to do was use an old MPlab lib for the PIC that we compiled against to create a hex dump that we could then upload using the driver. But this seems different. It seems like you created a library of sorts and also highly modified eclipse to accept it, maybe more…

Just… bravo!
-Cody

This is awesome, I have always wanted a actual C implementation for the Vex.

Is this legal for VRCC? I don’t remember seeing any rules about allowed programming tools, but I am not sure if there was any in the high school manual either.

Also if you won’t mind elaborating on how you developed this and what tools you used to access the low level functionality of the cortex? I won’t be able to make it to championships this year so I won’t be able to visit your pit to ask about it.

In a recent Q&A, Karthik said that you could use any coding software you chose, assuming that it did not inhibit anything being done by the competition switch (no joystick control during Autonomous, Enable/Diabale works), and you took full responsibility for any errors that might occur.

So first of all, congratulations on achieving this, I’ve thought about doing the same type of thing but always decided that it wasn’t worth the effort or potential ramifications if I then released it. Some of my thoughts from last year are here.
https://vexforum.com/showpost.php?p=297253&postcount=1

I do have a couple of questions for you.

Did you get help from VEX on the low level interface to the master processor and other peripherals like the H-bridges?

Looks like you may be running the I2C at a faster speed than the 100KHz that the ROBOTC and EasyC developers use, ROBOTC recently increased the poll rate from the post you linked to but it still takes 1mS to receive the full data packet from an encoder, moving to 400KHz would give the time you reported. I had tried this back when the IMEs first came out but did see some unreliability running at that speed.

I am surprised you see errors in the serial communication, 24 bytes at 115.2K only takes 2mS to transmit and there is a 50 byte receive buffer in ROBOTC so it should be possible to receive all packets with no errors.

Control of motor port 1 and port 10 can be tricky as these use timer4 and some digital IO to drive the pwm directly (remember the problems with ROBOTC 2.16), are you comfortable that there’s no chance of burning out the H-bridges?

Did you base the multitasking on something like FreeRTOS or roll your own?

Do you plan to release this publicly? If so would it be closed or open source?

Anyway, way cool and I will try and stop by next week to get a demo.

Edit:
More questions
What did you do for downloading code? Did you base something on the open source STM32 loader code that’s floating around?

How much support for the Mac do you plan, I wrote a driver (well not a real driver but code to access the USB from a user application) for the VEX comms port under OSX, perhaps you could finish that off for me.

Any plans for a debugger?

This is amazing. If it were to be released publically and fully legal for competition use I would definitely switch.

WOW

Have to say this looks pretty awesome. I didn’t think one team alone would be able to take this so far as to have it working.
How did you find the time for this? Did some of your team members do this as a uni project or was it done all in your teams spare time?

If you plan release it open source do you think you would be accepting contributions? I’m sure AURA would look at using it and contributing back if we ran up against any limitations/bugs.

Awesome work though, disappointed I wont be at worlds to see it in action.

I would love to use this.
Can it write to the flash memory of the cortex, so data could be saved when the cortex is turned off.

I am glad everyone is liking what they see with PROS I know it has been a fantastic experience working with it. I promise I will get back with more details later today but in the mean time I have to prep for my senior design presentation later today :confused:

Just wanted to say good luck, great work and BOILER UP!

  • Ryan, Purdue Alum 2009

Sure it can, I can do that in ROBOTC and EasyC, but understanding how and when to use that feature is important so I’ve never released the code.

Wow I am extremely impressed and really look forward to being able to use this (I hope you’re planning on releasing it?)

It would be truly amazing if you put it out open source so others could collaborate and hack further on it.

Well, legally, the GCC related stuff(frontends, backends) will have to be released as free software under the GNU GPLv3 or a compatible license. Release the rest, along with an EBNF under the GPLv3 and all Documentation under the FDL, CC licenses are designed for creative works, the FDL is better for technical works such as documentation.

very excited for the release. It looks sooo much better than either robot c or easy c!

look forward to using it!

Oh, oh… now you’ve done it! You’ve gone and gotten us all excited and will be getting requests for documentation, additional features, bug fixes, and all that sort of stuff for years to come. :smiley:

Honestly, though, it sounds pretty awesome. I’ll join the line of those who are excited to find out more…

Jason

For a release, we have to work out several details, including improved documentation, further testing, and issues with Purdue University IP regulations. Any announcements about a release will most likely come next fall (August or so). Sorry for the delay, but we want to make sure that we do it right the first time.

We do not own a VEX Speaker and so have not yet developed VEX Speaker support. It should not be too difficult to add support for simple tones and possibly sampled audio from the expansive 350+ K of Flash memory left. We really tried to make the kernel as small as possible and managed to fit the core functionality in only 12 K.

We did not get any help from the VEX staff, however we found much useful information lurking this forum. We don’t have the space here to answer all of your questions - would you be OK with waiting a week and having them answered at the World Championship? We will be there on Wednesday afternoon before matches heat up.

The PROS system has a file system based on similar principles to eLua’s WOFS, featuring a primitive wear leveling mechanism, multiple named files, and persistence through downloads. However, due to some of the very same issues that jpearman mentioned, we have currently disabled it in the kernel as we have not found a use requiring files. These issues include the very limited 10,000 flash reprogramming endurance cycles and long interrupt latency inflicted when erasing a page. Someone writing to files in a loop could easily kill a cortex or cause a runaway robot.

As a result, if we need data logging, we hook up VEXNet and use CoolTerm to log the serial output from printf() statements to a file on a PC. We might explore a method to fight these issues and allow flash writes after the World Championships. Out of curiosity, what objectives do teams want to accomplish by storing data after the cortex powers off?

I can not wait to be able to use this.