RobotC logoAs I’ve mentioned in several posts this summer, our team has switched from easyC to RobotC, and we are finding our way. I thought I’d write up what I’ve learned about jpearman’s Smart Motor Library for use with RobotC.

Back in 2012, the awesome jpearman from the VEX Forum created the “Smart Motor Library” for anyone to use on their VEX robot. It even comes with extensive documentation, which is also completely amazing.

As usual, this is a long post, so here’s a table of contents:

What Does It Do?

From jpearman’s documentation file (available from the library’s GitHub page) the Smart Motor Library is

a series of C code functions and data structures that provide additional functionality to ROBOTC for the VEX cortex.  … [and] provides the following functionality:

  • The automatic calculation of actual motor speed based on encoder value changes.
  • The automatic calculation of motor current based on measured motor speed and motor control value.
  • The estimation of PTC temperature in encoded motors and the cortex or power expander controlling them.
  • Monitoring of PTC temperature and limiting of motor current if the maximum PTC is reached.
  • Monitoring and limiting of average motor current if a preset current threshold is passed.
  • Slew rate control of motors by controlling acceleration and deceleration.

OK, so what exactly does it accomplish? Well, while jpearman points out that this library will not compensate for poor robot design, it will, however help in the following instances:

  • Motor overheating during autonomous periods when unexpected events would cause a motor to stall.
  • Motor overheating when in pushing matches with other robots.
  • Motor overheating caused by enthusiastic driving under competition conditions.

Motors with Encoders: Speed, Current, PTC Temperature, and Putting on the Brakes

For motors that either have integrated motor encoders (IMEs) or quadrature shaft encoders, this library does a lot.

Motor Controller 29The library starts out by using the encoder values combined with a timer to calculate the motor’s speed. It combines that information with what it sees the motor controller is doing to calculate the current flowing to the motor. As a reminder, the motor controller (not to be confused with motor encoder) is the little connector item that goes between the cortex and the motor — a little plastic box with wires coming out of each end, shown in the photo at right. (See my post on this component for more info; motor ports 1 & 10 have this component built into the cortex.)

DC motor inside VEX motorFrom the estimation of current, it next calculates the motor’s PTC temperature. PTCs are the electrical component inside a motor that act as circuit breakers, stopping the motor before it does itself harm (the little yellow tab in the image at left). The PTC is a combination thermostat and resistor. Current flows through it on the way to the motor, and heats the PTC as it does. If the heat generated exceeds the heat lost to the surrounding environment, the PTC doo-dad keeps heating up, causing its resistance to increase, which in turn causes MORE heating. As you can see, this creates a vicious cycle. Less current and less voltage make their way through to the motor itself, and eventually that will drop to zero and the motor will stop working until it can cool down. (See my earlier post on motor overload.)

So, KNOWING what the PTC’s temperature is would be a helpful thing. By knowing the temperature (or even an estimation of it), one could reduce the demand on the motor so that it keeps functioning; this is critical in competition conditions. Having a motor that you can use at all is better than having a motor that is temporarily dead. And that is indeed the next thing that the library does: it will automatically put the brakes on the motor before it gets non-functional. It saves you from yourself, while keeping the robot functional. (The PTC alone also saves you from yourself, but leaves the robot dead.)

Alternately, you can tell your program that you’d like the Smart Motor Library to put the brakes on based on current instead of temperature. See the flow chart below.

Linking Motors

Oftentimes a robot manipulator will use several motors to accomplish its task, where all motors are set to exactly the same power at the same time, such as when moving a lift. (If it were possible or allowed in VEX, these could all be connected via a mega-Y-connector and achieve the same result.) In these situations, in designing the robot, there would be absolutely no reason to put a motor encoder on every single motor. One would typically have a motor encoder on one of the system’s motors (the “master”) and then have all of the other motors follow its lead (as “slaves”).

So how can you make use of the smart motor library if you have 4 motors, but only one has an encoder on it? Linking!

At the start of the program, you specifically tell the library which motors are linked in the format of Link(master, slave). See below for details. Once motors are linked, the library will estimate the current and temperature for the linked slave motors based on the functioning of the master.

All of Those Motors Together

VEX Motor 393As I’ve written previously, the cortex has one internal 4-amp circuit breaker for motor ports 1-5, and a separate one for ports 6-10. The power expander has its own 4-amp circuit breaker for the motors plugged into it. If the circuit breaker for, say, slots 1-5 gets tripped, ALL of the motors plugged into those ports will stop working, until the cortex’s PTC circuit breaker has a chance to recover. YIKES! While we really don’t want to trip a motor PTC in a competition, we really really really really don’t want to trip the cortex or power expander’s circuit breakers.

That’s where the Smart Motor Library comes in. It adds together the information it’s calculated above for all motors combined, and looks at each grouping (cortex 1-5, 6-10, power expander). If one of those groups is getting too near trip-temperature, then it will slow down all of the motors in that group (whether they have encoders on them or not; the program estimates/simulates what’s happening for the non-encoded, per jpearman).

Smart Motor Flow Chart

Here’s a flow chart of what’s happening with the functionality discussed thus far (a simplified version of the flow chart in the Smart Motor Library documentation, page 8):

Smart Motor Library - Flow Chart

Slew Rate for Every Motor

If your robot doesn’t have encoders, why would you want to bother using this library? For the slew rate, that’s why! As described in my earlier post on this topic, slew rate is a set of programming functions that ramps up a motor’s speed over a short period of time. A motor going from 0 power to 127 power will have a lot of current flowing through it. If that motor is under a great load (or, say, a wheel that’s pushing against the field perimeter), then that full-power current will be flowing through the motor for a while before the motor starts to move, increasing the risk of the PTC overheating and the motor stalling.

If one could ramp up the motor’s speed in small increments over, say, one second, then the current going through the PTC will be more reasonable and less likely to trip the motor’s circuit breaker.

In a simple autonomous program, doing such a thing manually would be fairly simple with a teeny for-loop in the places it’s needed. But what about joystick control? How would I know when I’m going from, say, 0 to 127 in arcade drive? (With a joystick button, on the other hand, one could know precisely when this is needed, but not with a joystick lever. Even so, doing this manually in user control means that the cortex is stuck in a for-loop for 1 second, blocking out other instructions; sub-optimal.) The Smart Motor Library has complex code that does this ramping-up automatically, checking all motors, all the time, making use of RobotC’s faux-multi-tasking capabilities. And it’s pathetically easy to use; see below.

The slew rate control in this library operates independently from all of the tasks described above, because it acts on every motor command to every motor, not just the ones with encoders attached to them. So I’ve made a second flow-chart for this task (kinda simple):

Smart Motor Library - Slew Rate Flow Chart

But Wait! There’s More!

There’s always more, here in the Coach’s Corner blog-writing universe. The Smart Motor Library has a large number of parameters that can be used to turn on or off various capabilities. Examples include connecting to the power expander’s status port to get info about its PTC; using LED jumpers in the cortex to signal what’s happening in the code; telling the system that your encoder is at the end of a gear train, and not connected to the motor’s axle directly; using a potentiometer to measure RPM; and more! See the documentation PDF for all of the details and how they apply to your robot design and use.

Using It: Technical Details

All of this information is lovely, but how do I actually *use* this for my robot? Since this blog is aimed at coaches of VEX competition teams, I’m restricting my description here to a competition program.

At the *VERY* Top of Your Program

At the top of the program, immediately after the system-generated #pragma statements, write
#include “Libraries\SmartMotorLib.c”

Note: in the folder where your program is stored in your computer, you must have a sub-folder called “Libraries” with the file “SmartMotorLib.c” inside that folder. You can change the path to the library if needed, but it’s probably easier to go with the recommended format if you’re a newbie at this.

After the line that has #include “Vex_Competition_Includes.c” (automatically included in a competition program), and before the large comment about the Pre-Autonomous section, add this line:
#pragma systemFile
This statement suppresses warnings that you have unused functions when you compile the program.

In the Pre-Autonomous Section

In the Pre-Autonomous portion of the competition file, you’ll include the following commands:

  • bStopTasksBetweenModes = false;
    This line is system-generated in the competition program, and is set to “true” by default. Setting it to “false” allows you to start the Smart Motor Library before the match has even begun, and have it running throughout autonomous and driver-control periods, without having to call it in each section.
      
  • SmartMotorsInit(); 
    This line does just what it claims: it initializes the library
      
  • SmartMotorsAddPowerExtender( motorA, motorB, motorC, motorD );
    where motorA – motorD are the names of the motors plugged into the power expander. The library cannot calculate the power expander’s PTC temperature unless it knows which motors are plugged in there.
      
  • SmartMotorLinkMotors( masterMotor, slaveMotor );
    You’d replace “masterMotor” and “slaveMotor” in the statement above with the names of the motors on your robot.

    • Note: this LinkMotors command only accepts 2 pieces of information, the name of the master motor, and the name of the slave.
    • What to do if you have, say, 3 slave motors to your 1 master? Just be repetitive. You’d write the following:
      SmartMotorLinkMotors( masterMotor, slave1 );
      SmartMotorLinkMotors( masterMotor, slave2 );
      SmartMotorLinkMotors( masterMotor, slave3);
        
  • SmartMotorCurrentMonitorEnable();  
    — OR — 
    SmartMotorPtcMonitorEnable(); 
    You can only use one of these. As described above and shown in the flow chart, you can tell the library to limit motor functions based on its calculation of current or its calculation of a motor’s PTC temperature.
      
  • SmartMotorRun();
    You guessed it, this statement gets the ball rolling.

There are a number of other, more advanced commands available that can be used in the Pre-Autonomous section of the code that override certain default conditions, that would only be needed by advanced users with very specific needs.

In Autonomous & Driver Control

Here’s the beauty of this whole thing. To make the Smart Motor Library do ALL OF THESE THINGS FOR YOU, you simply change how you write your motor commands.

Instead of motor[ myMotor ] = powerLevel;

You will write SetMotor ( myMotor, powerLevel );

Note: RobotC has a natural-language function called setMotor (with a lower-case “s”); the one you want to use is SetMotor (with a capital “S”). When you’re typing in RobotC, the program may try to auto-fill “setMotor” because that’s what it’s expecting. So you will need to be diligent and conscious of your typing when using the Smart Motor Library.

Note also: You cannot mix-and-match motor[myMotor] = power and SetMotor(myMotor, power). Once you have the Library running, you must change all of your motor code to the SetMotor(xx, xx) format. A comment on line 790 of the library says:

This is the only call that should be used to change motor speed 
using motor[] will completely bugger up the code - do not use it

If for some reason you do not want to use slew rate on a certain motor command—say, if you’re applying the breaks and want a hard stop at the end of your robot’s movement—then you can add the third, optional parameter like so: SetMotor(myMotor, power, true).

Sample Program

#pragma config(Sensor, dgtl2, backRightENC, sensorQuadEncoder)
#pragma config(Sensor, dgtl4, backLeftENC, sensorQuadEncoder)
#pragma config(Motor, port2, rightBack, tmotorServoContinuousRotation, openLoop, reversed, encoderPort, dgtl2)
  . . .
#pragma config(Motor, port9, leftFront, tmotorServoContinuousRotation, openLoop)
 //*!!Code automatically generated by 'ROBOTC' configuration wizard !!*//

/*-------------------------------------------------------*/
 /*
 /* Description: Competition template for VEX EDR
 /*
 /*------------------------------------------------------*/

//SmartMotorLibrary by JPearman on the VEX Forum
 #include "Libraries/SmartMotorLib.c"

// This code is for the VEX cortex platform
 #pragma platform(VEX2)

// Select Download method as "competition"
 #pragma competitionControl(Competition)

//Main competition background code...do not modify!
 #include "Vex_Competition_Includes.c"

// Prevents "unused functions" warnings related to Smart
// Motor Library when compiling
 #pragma systemFile

/*--------------------------------------------------------*/
/*              Pre-Autonomous Functions
/*
/* You may want to perform some actions before the competition 
/* starts. Do them in the following function. You must return
/* from this function or the autonomous and usercontrol tasks
/* will not be started. This function is only called once after
/* the cortex has been powered on and not every time that the 
/* robot is disabled.
/*------------------------------------------------------------*/

void pre_auton()
{
   // Set bStopTasksBetweenModes to false if you want to keep
   // user created tasks running between Autonomous and Driver
   // controlled modes. You will need to manage all user created
   // tasks if set to false. 
   bStopTasksBetweenModes = false;

   // Initialize the Smart Motor Library 
   SmartMotorsInit();

   // Define which motors are plugged into the power expander 
   SmartMotorsAddPowerExtender( motorA, motorB, motorC, motorD );

   // Define which motors are linked
   SmartMotorLinkMotors( masterMotor, slaveMotor );

   // Declare that you want the Library to keep a lid on the
   // motors by measuring the temperature of the PTC components
   SmartMotorPtcMonitorEnable();

   // Run smart motors 
   SmartMotorRun();

}

//////////////////////////////////////////////////////////////
// 
// Autonomous Task 
// 
// This task is used to control your robot during the autonomous
// phase of a VEX Competition. You must modify the code to add 
// your own robot specific commands here. 
//
///////////////////////////////////////////////////////////////

task autonomous()
{
   // your autonomous code goes here
   // when you want to turn on motors, use the following format:
   SetMotor( myMotor, power );
}


//////////////////////////////////////////////////////////////
// 
// User Control Task
//
// This task is used to control your robot during the user 
// control phase of a VEX Competition. You must modify the 
// code to add your own robot specific commands here.
// 
/////////////////////////////////////////////////////////////// 

task usercontrol() 
{
   // your joystick/user control code goes here
   // when you want to connect motors to your joystick
   // use the same format: SetMotor( myMotor, power ).
   // Here is an arcade drive example

   while (true) {
      int leftPower = vexRT[Ch3] + vexRT[Ch4]; 
      int rightPower = vexRT[Ch3] + vexRT[Ch4];

      SetMotor(leftBack, leftPower);
      SetMotor(leftFront, leftPower);
      SetMotor(rightBack, rightPower);
      SetMotor(rightFront, rightPower);
   }
}

In the Future: V5 Cortex

Starting in next year’s game (2018-2019), the soon-to-be-released VEX “V5” system—cortex, joysticks, motors—will include many of these functionalities out-of-the-box, and this post will become an interesting historical document (if that). But for now, VEX cortexes and motors have certain limitations that can be mitigated via sophisticated programming.

Wrapping Up

Much gratitude to the awesome jpearman for this and other RobotC and easyC code, and for all the other ways he supports the VEX community.

I hope that this post has made using this library a little more approachable to those who are new to it. Trying to understand all the details via the VEX Forum descriptions, or even from the documentation file itself (the first few times you read it) can be mystifying; it’s easy to come away with the feeling that this is too much work to use, “I’ll never understand it,” or “I’ll use it the wrong way.” As you can see from the sample program here, it turns out that there’s not much to it! To reiterate what I mentioned at the top: programming cannot compensate for deficient power in the design of one’s robot, but it can get you the most of what you have.

For teams that are already using the Smart Motor Library, I hope that this post has made the system less of a “black box.”

Good luck, and happy coding!

Share this post: