Smart Motor Library

I posted an update to the SmartMotorLibrary today, V1.03.

Change log

Due to the imminent release of ROBOTC V3.60 I had to change some conditional compilation that was based on the version number. V3.60 and greater was originally going to be a version that included PID, the motor types changed in that version to differentiate between port 1 & 10 motors and those on the MC29. ROBOTC with PID is delayed until later this year (although still available as a beta download), however, CMU is probably going to bump the next non-PID version to 3.60 as 3.59 beta has been out for a while now.

I added the ability (although it’s mostly untested) to use a potentiometer as feedback for the rpm calculation. A new function was added, this is from the documentation.

[FONT=“Courier New”]void SmartMotorSetRpmSensor( tMotor index, tSensors port, float ticks_per_rev, bool reversed = false )[/FONT]

This function can be used to assign any sensor to a motor for calculating rpm, the most likely situation would be a potentiometer. The parameter ticks_per_rev is the sensor change for one revolution of the motor, for example, a potentiometer with 1:1 gearing has about 6000 ticks_per_rev, if the gearing was 7:1 then this would be reduced to about 857. Set reversed to true if the potentiometer value decreases with positive motor command values.

it might be used something like this.

    // Init the speed and current functions
    SmartMotorsInit();
    SmartMotorCurrentMonitorEnable();

    // set pot1 as sensor for port4
    SmartMotorSetRpmSensor( port4, pot1, SMLIB_TPR_POT/8.33, true );

    // Run smart motors
    SmartMotorRun();

This sets the potentiometer I had called “pot1” to be the rpm sensor for the motor on port4. Ticks per rev were set to SMLIB_TPR_POT/8.33 (SMLIB_TPR_POT is defined as 6000 and 8.33:1 was my gear ratio). I had the pot reversed so set that flag true. Again, this feature is mostly untested so if anyone tries it and it works let me know. You will have to tweak the ticks_per_rev to get accurate results.

version 1.03 include file is here SmartMotorLib.c

updated documentation (it very minor) is here SmartMotorLib_Ed1rev2.pdf

I notice that occasionally the original v1.00 is being downloaded, it has minor bugs so try and avoid using it, I will kill the links sometime but for now they are still valid.

1 Like

Thanks for the update! I look forward to trying it out.

I’ve moved this project to github.

https://github.com/jpearman/smartMotorLib

Nothing has changed since V1.03 but I did bump the version to 1.04 as it’s now released under the Apache license which means you can do whatever you like with it as long as the original copyright stays in the code.

I notice that some students are still downloading the original V1.00 that had a couple of small bugs, I will probably delete the old versions soon.

1 Like

Fixed bug where if a motor was being limited and a command sent that was the opposite sign (ie. direction) and larger then the limited speed, the motor would not change direction. This would happen, for example, if the joystick was quickly moved from +127 to -127 whilst the motor was speed limited.

Bumped version to V1.05.

Here is the diff

diff --git a/SmartMotorLib.c b/SmartMotorLib.c
index c101efd8f4579902892186fc865519118b3a53d1..f9706f1d7efaf1786494829831827643fb90ba44 100644
--- a/SmartMotorLib.c
+++ b/SmartMotorLib.c
@@ -33,6 +33,9 @@
 /*                      want to add a new variable so reused encoder_id        */
 /*               V1.04  27 June 2013                                           */
 /*                      Change license (added) to the Apache License           */
+/*               V1.05  11 Nov 2013                                            */
+/*                      Fix bug when speed limited and changing directions     */
+/*                      quickly.                                               */
 /*-----------------------------------------------------------------------------*/
 /*                                                                             */
 /*    The author is supplying this software for use with the VEX cortex        */
@@ -104,8 +107,8 @@
 #ifndef __SMARTMOTORLIB__
 #define __SMARTMOTORLIB__
 
-// Version 1.03
-#define kSmartMotorLibVersion   104
+// Version 1.05
+#define kSmartMotorLibVersion   105
 
 // We make extensive use of pointers so need recent versions of ROBOTC
 #include "FirmwareVersion.h"
@@ -1793,8 +1796,13 @@ task SmartMotorSlewRateTask()
             // check for limiting
             if( (PtcLimitEnabled || CurrentLimitEnabled) && (m->limit_cmd != SMLIB_MOTOR_MAX_CMD_UNDEFINED) )
                 {
-                if( abs(m->motor_cmd) > abs(m->limit_cmd) )
-                    m->motor_req = m->limit_cmd;
+                if( abs(m->motor_cmd) > abs(m->limit_cmd) ) {
+                    // don't limit if we are reversing direction
+                    if( sgn(m->motor_cmd) == sgn(m->limit_cmd) )
+                        m->motor_req = m->limit_cmd;
+                    else
+                        m->motor_req = m->motor_cmd;
+                    }
                 else
                     m->motor_req = m->motor_cmd;
                 }

The same fix was applied to the ConVEX version.

1 Like

Hello im new to the robotc but have been able to work with it fairly well. I’ve heard great things about the smart motor library so i decided to check it out and downloaded version 1.03 off of the Box link you gave. Reading the documentation I found all the functions that needed to be called to run the program, however right off the bat it tells me the Error:Undefined procedure ‘SmartMotorInit’ so im not quite sure what to do right now. any help is welcome, thanks in advance.
P.S. im running Robotc 4.03.

It sounds like your code is not including the library correctly or perhaps is not saved in the same location as the library.

If you include the library as follows.


#include "SmartMotorLib.c"

you will need to save your code in the same folder as the library.

Some of the examples include the library as follows.


#include "Libraries/SmartMotorLib.c"

Then the library would need to be in the sub-folder “Libraries”.

The most current version is V1.05 and is available from github.
https://github.com/jpearman/smartMotorLib

I assume you have ROBOTC V4.06, that is the latest, be aware the smart motor library will not work if you are using the built in PID functionality included with that version.

1 Like

Ok so I now have another problem. I am using the 4 IMEs on my Drive since it is holonimic and each wheel works independently. The motor to ime configuration is Front right motor-I2C-1, rear Right motor to I2C-2, Rear left motor-I2C-3, and Front left motor-I2C-4. The first and second IME seem to work with the library just fine but the third and fourth seem to be cut out by the Ptc monitor much mor quickly even when they were brand new motors. So if you have any suggestions they would be greatly appreciated.

A quick review of how this library works.

  1. The motor speed is calculated using feedback from an encoder, usually an IME but it can also be a quadrature encoder or potentiometer (in special circumstances).

  2. Using the calculated motor speed and the commanded speed value an estimate of the instantaneous current is calculated.

  3. The estimated motor current is used as part of an algorithm to calculate a theoretical PTC temperature based on a model of an “ideal” PTC.

  4. Users of the library can either use the estimated motor current or PTC temperature to limit motor speed and stop the actual PTC tripping.

The calculation of motor speed is accurate, the calculation of estimated current is quite accurate but as actual motor specifications have a tolerance of up to 20% the estimated current may also have an error. The calculation of PTC temperature is less accurate. PTC performance can vary wildly and the starting and ambient temperatures may not be knows. ie. if you turn off and on the robot when the PTCs are already hot the software does (and can not) know what these temperatures are.

The most important thing to get correct is the calculation of motor speed, things that will make this incorrect are as follows.

  1. Selection of the wrong motor type and gearing, ie. make sure 393 torque, 393 speed and 269 are correctly set in the motor and sensors setup.
  2. Incorrect wiring, the software must assume that positive commands will create increasing encoder counts. If the motor wiring is reversed by connecting red to black in the motor wiring the motor will turn the wrong way and the speed calculation will be wrong.
  3. The wrong encoder assigned to the wrong motor. IMEs must be correctly assigned, quad encoders must be assigned in the motors and sensors setup window.

This can all be checked using the ROBOTC motors debug window, run the motors forward and check the encoder count is increasing. Ignore the encoder counts in the sensors debug window, these may be reversed, the encoder counts in the motors debug window take into account the reverse flag on the motor. Make sure the correct encoder changes with each motor, if necessary move them by hand to check this.

If you feel everything is correctly connected then the results you are seeing may in fact be accurate. The software is not a “magic bullet”, if there is friction on the drive or the motors are in fact working too hard, the software will step in and reduce power. If the drive was overheating without using the library then it will continue to overheat except the software should stop you loosing control altogether by reducing motor power.

The most useful way I have found to use this code is as protection when in unexpected drive conditions. I usually use the current limit feature rather then the PTC trip detect feature. This helps in situations where the motors may be stalled unexpectedly, for example, the autonomous is set incorrectly and the robot drives into the field perimeter, a student gets into a pushing match with another powerful robot, a lift gets stuck on a field element. In these situations motors usually stall and trip the PTCs, the software current limit stops this from happening.

So I’m not sure what to tell you, the code that you sent me last week seemed to be working properly so perhaps it’s the robot drive which really does have problems. Post some pictures (in another thread) so we can see how it’s built and perhaps identify other issues.

1 Like

I did a bit of housekeeping on the links in this thread to the different versions of the smart motor library.

The best place to download the library is from github.

V105 on Github

Here is a direct link for a zip file of the source.

V105 zip archive

As everyone seems intent on downloading the original version (with had some bugs) from the link in the very first post in this thread, that has now been updated to also point at the latest version (which means that V1.00 is now unavailable).

The links for the interim versions, V1.01, V1.02 and V1.03 have been removed.

The smart motor library is not yet compatible with the new “Turbo” gear set for the 393 motor. More specifically, ROBOTC has not been updated to be compatible so I don’t know how they will define that new motor type. When ROBOTC is updated then I will update the library.

1 Like

Thanks very much! :slight_smile:

1 Like

I did a small update to the smart motor library to support the new turbo gears which are now available as an option in ROBOTC V4.26.

New smart motor version is V1.06

I don’t have any turbo gears so it’s only been tested with standard motors, should be ok though. It is becoming harder to maintain compatibility with older versions of ROBOTC but I did check with V3.63 and V4.10, let me know if there are any issues.

download from the same place as usual.
V106 on Github

1 Like

Hi jpearman, I was checking the library, and was thinking in implementing some of it to know which motors I have connected.

I saw that when you initialize the values for constant values it depended whether KRobotCHasPid was defined. What does bSmartMotorswithEncoders define affect the behaviour in initializing the values for each type of motor and also what else should I take in account for initializing values depending on the type of motor and version of RobotC.


// ROBOTC with PID changed motor definitions - I used to use version number
// but 3.60 broke that and we don't know what version it will be now
// This will have to do for now until it's released after worlds
#ifdef bSmartMotorsWithEncoders
#define kRobotCHasPid
#endif

     switch( m->type )
            {
            // 393 set for high torque
#ifndef kRobotCHasPid
            case    tmotorVex393:
#else
            case    tmotorVex393_HBridge:
            case    tmotorVex393_MC29:
#endif.....
}

I wrote the first version of the smartmotor library right around the time that ROBOTC 3.5 was released. The library uses pointers and (IIRC) that was the first version that supported them. When you setup the motors for your code in the motors & sensors dialog box, you will notice a series of statements right at the top that define all the motor types (the #pragma lines). The motors use enumerated types such as tmotorVex393 and tmotorVex269, I use these same types in the smartmotor library. By the time ROBOTC V3.54 was released the developers were working on a major update that would have PID control built in as a standard feature, this was originally planned to be released as V3.60 but was delayed by several months. The new PID feature needed to differentiate between motors on ports 1 & 10 (the 2 wire ports) and those on ports 2 through 9 (the 3 wire ports). They decided to do this by changing the motor enumerated types, tmotorVex393 now became either tmotorVex393_HBridge or tmotorVex393_MC29. The PID code was finally released in ROBOTC version 4.0, I needed a way to distinguish between the two versions of ROBOTC that were now in use, originally I was simply going to use the ROBOTC version number, however, due to the fact that there was a mixup in the versioning (there was a V3.61 beta that had PID code and also a V3.6 that did not have PID code) I picked up on another definition that was present in V4 but not in V3, my choice was to use bSmartMotorsWithEncoders which was first introduced in V4. All of this was to allow one code base that was compatible with all versions on ROBOTC from 3.51 through the latest 4.26.

You don’t need to worry about any of this if you are writing code for your own use. Pull out the code that’s relevant to the version you are using, for example, if you have V4.26 then use the code that compares motor types to tmotorVex393_HBridge etc. you can ignore the conditional compile parts, things like

// Fix for versions of ROBOTC earlier than 4.26
#if kRobotCVersionNumeric < 426
#define tmotorVex393TurboSpeed_HBridge   9998
#define tmotorVex393TurboSpeed_MC29      9999
#endif

are only in the code to try and maintain forwards and backwards compatibility.

Unfortunately this does make the code a little more complicated to read.

1 Like

Thank you very much, I asked you about the version of RobotC since we have some computers with v3 and others that have installed v4

Our team is using a Y-cable to power two motors from the same Convex Motor Port. Is there a function to indicate that that port should get twice the current?

There’s nothing that directly helps with that. The code will not know there are two motors, however, assuming that one of the two motors is encoded, the current and estimated PTC temperature will be the same for both so when power for one is cut the power for both will be cut. The estimates for the internal cortex PTC will be wrong, but it’s far more likely to trip a motor PTC anyway.

btw, did you mean “Convex Motor Port” or cortex motor port.

1 Like

Thanks. I think I understand now. We don’t have to tell the smart motor library that there are two motors since it is not actually measuring the current at that port, it is estimating the current draw and temperature based on RPM and it will regulate power to that port based on that estimate. Since the RPM of these two motors will be more or less the same, it all works out.

On the other hand the estimate for the Cortex (yes, I did mean Cortex and not Convex – thanks!) bank (or Expander) will be off because the smart motor library doesn’t know that there are actually two motors connected to one port. But no big deal since usually it is the motors’ PTC that trips.

That’s all correct. As the smartMotorLibrary is distributed as source you can always hack the code and make it specific to your application, ie. if you know port3 has two motors then add the current for that port twice, not pretty, but it would work. Also, if you have an unused port you could always pretend there is a motor plugged in (perhaps you have the Y cable on port3 and port4 is empty) and link the two ports together.

1 Like

Wow thanks! We’re going to try your second suggestion – just tell the smart motor library that some unused port is connected to a motor. Then the Cortex estimate will also be correct. That will only work if indeed there are unused ports on a given Bank corresponding to a motor powered by a Y-cable on that Bank (e.g. if there are more than 5 motors connected to a bank then it won’t work). For our robot though, it does work! Cool.

1 Like

I just read the documentation and I’m trying to understand how a function works.


long nMotorEncoderOffsets 10 ] = {0,0,0,0,0,0,0,0,0,0};
void
EncoderSetValue( tMotor index, float value )
{
 // note, we pass value as float due to bug in ROBOTC V3.51

 // bounds check index
 if((index < 0) || (index >= kNumbOfTotalMotors))
 return;
 // calculate and save offset
 nMotorEncoderOffsets index ] = nMotorEncoder index ] - value;
}
long
EncoderGetValue(tMotor index)
{
 // bounds check index
 if((index < 0) || (index >= kNumbOfTotalMotors))
 return(0);
 return( nMotorEncoder index ] - nMotorEncoderOffsets index ] );
}

first of all I realize this is just example code on how I would go about reading the value of and encoder without messing up the function of the library, but I still would like to know what it does.
my understanding these would be called when I want to read/change the value of encoder. I’m just confused about how it works.

I’m mostly confused about long nMotorEncoderOffsets 10 ] = {0,0,0,0,0,0,0,0,0,0}; I though a long was just an integer but it an be lower or higher than a integer.