cortex motor speed testing

When testing motors to determine their speed-torque curves in this thread, it has been noticed that motors are reaching their maximum unloaded speed before the maximum possible control value. This can be seen in this post where there is a graph of control values to output speed.

These tests above were done using port 9 on the cortex and an external motor controller 29. This port (as we know) is different to ports 1 & 10 as the output is a RC style servo control signal that has a nominal pulse width of 1.5mS when a motor speed of 0 is requested. The spec for this type of signal usually has the width of the pulse varying between 1.0mS and 2.0mS to move a servo from one end of it’s range to the other.

Using an oscilloscope the pulse width on the input to the motor controller 29 was measured and the following results found.

control value		pulse width
-127			864uS
-100			1.0mS
   0			1.5mS
 100			2.0mS
 127			2.14mS

Here are the same pulses on the oscilloscope (a composite image)

RCpwm_comp.jpg

I also looked at the output of the motor controller 29 and observed that as the control value passed 84 the output reached maximum duration. This is easiest done with a resistive load rather than a real motor. (ie. replace the motor with a suitable resistor).

This is illustrated in this scope composite.

RCpwm_out_comp.jpg

**So from the above we conclude the following.

  1. A control value of 100 corresponds to a pulse width of 1.5mS on the inout to the motor controller, this is nominally the maximum motor speed.

  2. The motor controller 29 has a maximum output with slightly less than the theoretical 1.5mS pulse input, somewhere around 1.42mS or a control value of 84.**

While I was doing this I also wanted to compare the difference between a resistive load and the motor (which is both inductive and resistive) as the load. Here is a scope composite with both shown. The control value here is only 20 but this causes the motor to run at about half speed (no load). The lower trace shows a back emf voltage that could theoretically be measured to determine motor speed.

RCpwm_bemf_comp.jpg

One final test was done to compare the speed for a given control value on port 10 to the speed from port 9. A control value of 20 was sent and the rpm of the unloaded motor measured. port 10 was found to be at 44rpm, port9 was at 56rpm, a significant difference.

**So the final conclusion from these tests is that a motor on a 3 wire port will not run at the same speed as a motor on a 2 wire port.
**

All of the previous tests were done with master firmware 3.21 and ROBOTC V3.08. EasyC V4.1.0.3 was spot checked and produced the same results. I also reverted back to both 3.16 firmware and 2.81 firmware (not a good idea, what a pain) and everything was the same as far as I could tell.

2 Likes

Was this the same motor?
Did I miss the slide showing the pwm is the same for ports 9,10 with the same control value sent?

A motor on a #9 3-wire port will run the same speed as
a motor on a #10 2-wire port if they are mechanically linked.

Performance under load may be more similar, or may not be.

I maintain that any two motors (unlinked, openloop) will not run the same speed, even if you run them off a Y cable from the same port.
This is either trivially true (insignificantly difference), or significantly true.
Corollary 1: If you want two motors to run at same speed, close the loop or link them.

1 Like

Yes, all testing was done with the same motor.

There was not a slide for the 2 wire port, I only reference the motor speed, although I have looked at it with the scope and verified that it changes up to the maximum control value of 127.

This may be true, I don’t have a suitable setup to be able to test this yet.

So port9+mc#29 vs port10 motor speeds are different primarily because the PWM are different.
Is it likely that this is an abberation in your example mc#29?
Probably not, since there was another similar non-linearity report.

The MC29 is definitely non-linear in the same way the Victor Speed controller is non-linear. Similar PWM-to-Duty Cycle code was used for both controllers.

1 Like

ports 1 & 10 are driven from the user processor by EasyC or ROBOTC, a value of 64 is converted to a pwm waveform with a 50% duty cycle. They use a hardware timer for this purpose (timer4 if anyone cares).

ports 2 through 9 have two characteristics that are different. First the scale for neutral RC pwm to full speed pwm is 0 to 100 control values so 64 is mapping to somewhere around 1.82mS instead of a theoretically correct value of 1.75mS (halfway between 1.5 and 2.0). Secondly, the MC29 has a deadband so that full speed motor output occurs with an input pulse width somewhere around 1.92mS rather than 2.0mS. This means that overall a control value of 64 will give a pwm duty cycle nearer to 76%. (all this is theory, I did not actually measure). Looks like I do need to compare speed vs control for port 10 after all.

Please bear in mind that this is mostly an academic discussion, we have all been mixing motors on different ports with no side effects and controlling speeds without knowledge (except for a select few) that the control to speed mapping is non linear. A lot of student code I see even has digital motor control, either full speed or off :slight_smile:

It seems unlikely.

1 Like

I realized that I did not actually post a graph of the difference between unloaded motor speed for a cortex 2 wire port vs a servo port, so here it is, same motor tested on port 9 using a MC29 and then port 10.

1 Like

Are you planning on creating a similar graph for the 2-Wire Motor 393? I was going to create one myself, but yours look very pretty and I was simply wondering what your plan was.

~Jordan

I don’t really have a plan, I can repeat the test sometime when I get my hands on a 393 (they are all at the school, I only have 269’s at home) but I’m not expecting any significant difference as the speed profile is determined by the MC29 and internal H-Bridge control far more than the motor.

If you want I can post the test code I used and you can do your own tests. More significant will be repeating with the motor under various loads but that is on the back burner as well.

1 Like

Okay, thank you. The code would be great to have and yes, I was planning on trying the test with various loads, as well.

Thanks!
~Jordan

1 Like

Here, to do with as you like.

#pragma config(UART_Usage, UART1, VEX_2x16_LCD, baudRate19200, IOPins, None, None)
#pragma config(I2C_Usage, I2C1, i2cSensors)
#pragma config(Sensor, I2C_1,  ,sensorQuadEncoderOnI2CPort,, AutoAssign)
#pragma config(Motor,  port9,  ,tmotorVex269, openLoop, encoder, encoderPort, I2C_1, 1000)
#pragma config(Motor,  port10, ,tmotorVex269, openLoop)
//*!!Code automatically generated by 'ROBOTC' configuration wizard               !!*//

/*-----------------------------------------------------------------------------*/
/*  Code to ramp motor values from -128 to 128 while measuring speed with an   */
/*  IME.                                                                       */
/*  James Pearman, May 2012                                                    */
/*-----------------------------------------------------------------------------*/

// global for measured motor rpm
float   rpm;

// delay between new speeds sent to the motor in units of 50mS
#define TESTDELAY      40

// encoder counts depending on motor
#define TICKS_PER_REV_269  240.448
#define TICKS_PER_REV_393S 392
#define TICKS_PER_REV_393T 627.2

// uncomment as necessary depending on the motor
#define TICKS_PER_REV      TICKS_PER_REV_269
//#define TICKS_PER_REV      TICKS_PER_REV_393S
//#define TICKS_PER_REV      TICKS_PER_REV_393T

// calculate motor rpm for motor
task calcSpeed()
{
    static  int delayTimeMs = 500;

    long enc;
    long oldenc;
    float delta;

    while(1)
        {
        // Get encoder value
        enc = nMotorEncoder[port9];

        // calculate encoder delta
        delta  = enc-oldenc;
        oldenc = enc;

        // calculate the rpm for a 269 motor
        rpm = (1000.0/delayTimeMs) * delta * 60.0 / TICKS_PER_REV;

        // wait
        wait1Msec(delayTimeMs);
        }
}

// check a joystick button
int CheckJoystickButton(TVexJoysticks button)
{
    if( vexRT button ] == 1 )
        {
        // wait for button release
        while( vexRT button ] == 1 )
            wait1Msec(10);
        // action
        return(1);
        }
    return(0);
}

// button check for full speed
int speedFull()
{
    return( CheckJoystickButton( Btn8U ));
}
// button check for starting the test
int startTest()
{
    return( CheckJoystickButton( Btn8D ));
}
// Button check for all stop
int AllStop()
{
    return( CheckJoystickButton( Btn8R ));
}

// set speed for motors on port9 and port10
void SetMotor( int speed )
{
    motor[port9]  = (abs(speed) > 127) ? sgn(speed) * 127 : speed;
    motor[port10] = (abs(speed) > 127) ? sgn(speed) * 127 : speed;
}

// main entry point
task main()
{
    int    testRunning = 0;
    int    testSpeed   = 0;
    int    testCounter;
    int    speed;
    string str;
    
    // LCD backlight on
    bLCDBacklight = true;
 
    // start motor rpm calculation task
    StartTask( calcSpeed );
    
    clearLCDLine(0);

    // run forever.
    while(1)
        {
        // run full speed for testing
        if( speedFull() )
            {
            speed = 128;
            SetMotor( speed );
            }
            
        // stop everything
        if( AllStop() )
            {
            speed = 0;
            SetMotor( speed );
            testRunning = 0;
            }

        // start gathering data
        if( startTest() )
            {
            testCounter = TESTDELAY;   // send first value immeadiately
            testSpeed   = -128; // will be truncated to -127 by ROBOTC
            testRunning = 1;    // start test
            }

        // Is the test running ?
        if( testRunning )
            {
            // New speed every 2 seconds
            if( testCounter++ >= TESTDELAY )              
                {      
                // reset delay counter
                testCounter = 0;
                
                // use test speed
                speed = testSpeed;               
                
                // are we done ?
                if(testSpeed > 128 )
                    {
                    testRunning = 0;
                    speed = 0;
                    }
                else
                    // inc test speed
                    testSpeed += 4;
                }
            }
        else
            {
            // use 128 to override joystick
            if( speed < 128 )
                speed = vexRT Ch1 ];
            }
          
        // update motors
        SetMotor( speed );

        // display what's going on
        sprintf(str, "%4d , %6.2f", speed, rpm);
        displayLCDString(0, 0, str);

        // display results just before we send a new value
        if( testRunning && testCounter == (TESTDELAY-1) )
            writeDebugStreamLine(str);
          
        // wait 50mS
        wait1Msec(50);
        }
}
1 Like