View unanswered posts | View active topics It is currently Fri Oct 31, 2014 4:48 am






Reply to topic  [ 7 posts ] 
Why are NXT motors so slow & irregular? 
Author Message
Rookie

Joined: Fri Feb 16, 2007 4:11 pm
Posts: 41
Location: Padanaram, MA
Post Why are NXT motors so slow & irregular?
I have been spending a lot of time testing the NXT motors. Below is the code I am using now. It uses motorA and motorC, and has three choices for the type of motor control: synchronized, unsynchronized but each motor having the same rotation angle and ,finally, using an encoder target. This code is shown below.

Code:
#pragma config(Sensor, S1,     TouchSensor,         sensorTouch)
#pragma config(Sensor, S2,     LightSensor,         sensorLightActive)
#pragma config(Motor,  motorA,          A_Motor,       tmotorNormal, PIDControl)
#pragma config(Motor,  motorC,          C_Motor,       tmotorNormal, PIDControl)
//*!!Code automatically generated by 'ROBOTC' configuration wizard               !!*//

const int kDatalogSize = 4000;

bool more;
bool forward = true;
bool backward = false;
bool saveRunData = true;

int motorPower = 75;            // Set for 750 encoder counts (degrees) per second
int encoderTarget0;             // Reference wheel rotation, degrees
int encoderTarget;              // Acxtual wheel rotation
int motorAEncoderValue;
int motorCEncoderValue;
int elapsedTime1;                // Elapsed time for timer T1(ms)
int lightValue;
int cntr;
int selection;
const int targeted = 1;
const int synchronized = 2;
const int unsynchronized = 3;
int waitTime = 1;

//########################################################################
void runMotorTargeted(bool &direction)
{
   nMotorPIDSpeedCtrl[motorA] = mtrSpeedReg;       // Enable motor-speed regulation
//   nMaxRegulatedSpeedNxt = 750;                    // For consistent speed
  nSyncedMotors = synchAC;                        // Synchronize A & C
   nSyncedTurnRatio = 100;                         // Turn equally
   nPidUpdateIntervalNxt = 20;                     // Recommended by Dick Swan
   nMotorEncoder[motorA]= 0;                       // Initialize encoder to zero
   bFloatDuringInactiveMotorPWM = false;           // Brakes on
  bMotorReflected[motorA] = direction;            // Our positive is Lego's negative
  nMotorEncoderTarget[motorA] = encoderTarget;    // incremental amount to move motor
  motor[motorA] = motorPower;

  while (nMotorRunState[motorA] != runStateIdle)  // wait for action to complete
  {}
  wait1Msec(waitTime); // Need this for reliable behavior

}

//########################################################################
void runMotorSyncd(bool &direction)
{
   bool wait;
   nMotorPIDSpeedCtrl[motorA] = mtrSpeedReg;   // Enable motor-speed regulation
//   nMaxRegulatedSpeedNxt = 750;                // For consistent speed
   nSyncedMotors = synchAC;                    // Synchronize A & C
   nSyncedTurnRatio = 100;                     // Turn equally
   nPidUpdateIntervalNxt = 20;                 // Recommended by Dick Swan
   nMotorEncoder[motorA]= 0;                   // Initialize encoder to zero
   bFloatDuringInactiveMotorPWM = false;       // Brakes on
  bMotorReflected[motorA] = direction;        // Our positive is Lego's negative
  motor[motorA] = motorPower;

  wait = true;
  do  // Wait for encoder to reach desired value
  {
      if (nMotorEncoder[motorA] >= encoderTarget)
      {
       motor[motorA] = 0;  // Stop
         wait = false;
      }
  }
  while(wait);

  wait1Msec(waitTime); // Need this for reliable behavior

}

//########################################################################
void runMotorUnsyncd(bool &direction)
{
   bool wait, motorA_OK, motorC_OK;
   nMotorPIDSpeedCtrl[motorA] = mtrSpeedReg;   // Enable motor-speed regulation
   nMotorPIDSpeedCtrl[motorC] = mtrSpeedReg;   // Enable motor-speed regulation
//   nMaxRegulatedSpeedNxt = 750;                // For consistent speed
   nPidUpdateIntervalNxt = 20;                 // Recommended by Dick Swan
   nMotorEncoder[motorA]= 0;                   // Initialize encoder to zero
   nMotorEncoder[motorC]= 0;                   // Initialize encoder to zero
   bFloatDuringInactiveMotorPWM = false;       // Brakes on
  bMotorReflected[motorA] = direction;        // Our positive is Lego's negative
  bMotorReflected[motorC] = direction;        // Our positive is Lego's negative
  motorA_OK = false;
  motorC_OK = false;
  wait = true;
  motor[motorA] = motorPower;
  motor[motorC] = motorPower;

  do  // Wait for encoder to reach desired value
  {
      if (nMotorEncoder[motorA] >= abs(encoderTarget))
      {
       motor[motorA] = 0;  // Stop
       motorA_OK = true;
      }
      if (nMotorEncoder[motorC] >= abs(encoderTarget))
      {
       motor[motorC] = 0;  // Stop
       motorC_OK = true;
      }
      if (motorA_OK && motorC_OK)
      {
         wait = false;
      }
  }
  while(wait);

  /* This does not work
  while (nMotorRunState[motorA] != runStateIdle)
   {
   //do nothing until motor is at target//
   }
  */

  wait1Msec(waitTime); // Need this for reliable behavior

}

//########################################################################
void runMotor(bool &direction, const int &selection)
{
   switch(selection)
   {
      case targeted: runMotorTargeted(direction);
      case synchronized: runMotorSyncd(direction);
      case unsynchronized: runMotorUnsyncd(direction);
   }
}

//########################################################################
//########################################################################
//########################################################################
//########################################################################
//########################################################################
task main()
{
   selection = targeted;
//   selection = synchronized;
//   selection = unsynchronized;
   nDatalogSize = kDatalogSize;
   encoderTarget0 = 90;
   more = true;
   motor[motorA] = 0;                          // Motors off
   cntr = 0;

   more = true;
   while(more)
   {
     elapsedTime1 = 0;
    time1[T1] = 0;
     lightValue = SensorRaw(LightSensor);   // Get current light reading
      encoderTarget = random(encoderTarget0) - encoderTarget0/2;
    if (encoderTarget != 0)
    {
       if (encoderTarget > 0)
       {
          runMotor(forward, selection);
      }
      else
       {
         encoderTarget = - encoderTarget;
         runMotor(backward, selection);
      }
    }
    elapsedTime1 = time1[T1];
     motorAEncoderValue = nMotorEncoder[motorA]; // Current value of motor encoder (for testing)
     motorCEncoderValue = nMotorEncoder[motorC]; // Current value of motor encoder (for testing)
      if (saveRunData && cntr < kDatalogSize - 5) // Don't try to exceed capacity
    {
       motorAEncoderValue = nMotorEncoder[motorA]; // Current value of motor encoder (for testing)
         AddToDatalog(elapsedTime1);
         AddToDatalog(motorAEncoderValue);
         AddToDatalog(motorCEncoderValue);
         AddToDatalog(encoderTarget);
    }

    cntr = cntr + 5;

    if (SensorValue(TouchSensor) == 1)  // If button is pressed
    {
        PlaySound(soundBeepBeep);             //  Sound warning
        eraseDisplay();
       more = false; // Exit loop & do calibration
       wait1Msec(1000);  // Give them time to release button
    }

   }

   SaveNxtDatalog(); // Move DataLog data from RAM to Flash memory

}


The main task randomly selects a rotation angle and then runs the motors,over and over again. Pushing the button on the TouchSensor on S! saves the datalog and stops the program.

I have stored elapsed time and motor-rotation data in the datalog. I then saved the datalog as an MS Excel file (a .csv file) and used my Process Datalogs program (see mightor's Datalogging topic) to put the data in separate columns. I saved this processed data as another .csv file and opened it with MS Excel. That enabled me to plot the encoder angle vs elapsed time. I have attached the MS Excel file,now converted into a .txt file so I could attach it here. To open it in MS Excel you should change the ending from .txt to .xls.

Several things are striking. First, although the relation between encoder angle and elapsed time is approximately linear, there are two such lines, one starting at time equal zero and a second starting at time approximately equal to 200 milliseconds. I used timers at various places in the program and concluded that virtually all the time is spent running the motors. I cannot understand where the 200 ms delay is coming from. Secondly, although the motors are running at 75% power which is supposed to turn the motors at 750 degrees per second, the actual rate from the slopes of the two lines I actually got is only about 150 degrees per second! Why are the motors so slow?

Can anyone shed some light on this?

Thank you and best regards,

Ted


Attachments:
File comment: An MS Excel file.
NXT Motor Test 9Jan09 4-45PM.txt [32 KiB]
Downloaded 130 times


Last edited by tedkurtz on Sun Jan 11, 2009 5:23 pm, edited 3 times in total.

Fri Jan 09, 2009 6:33 pm
Profile WWW
Expert
User avatar

Joined: Mon Oct 06, 2008 6:30 pm
Posts: 176
Location: Netherlands
Post Re: Why are NXT motors so slow & irregular?
Quote:
the actual rate from the slopes of the two lines I actually got is only about 150 degrees per second! Why are the motors so slow?


If you look at your motors, are they realy turning less than a full circle every two seconds?

_________________
My most recent blog: A grain of sugar


Fri Jan 09, 2009 7:21 pm
Profile WWW
Rookie

Joined: Fri Feb 16, 2007 4:11 pm
Posts: 41
Location: Padanaram, MA
Post Re: Why are NXT motors so slow & irregular?
Hi Aswin,

Yes. They turn approximately the angles commanded.

Regards,

Ted


Fri Jan 09, 2009 10:21 pm
Profile WWW
Expert
User avatar

Joined: Fri Nov 09, 2007 4:51 am
Posts: 121
Location: Hungary, Europe
Post Re: Why are NXT motors so slow & irregular?
tedkurtz,

it is really strange.
I have six NXT motors and they are almost the same and they much faster (5-6 rotations per second)


Sat Jan 10, 2009 8:38 am
Profile
Rookie

Joined: Fri Feb 16, 2007 4:11 pm
Posts: 41
Location: Padanaram, MA
Post Re: Why are NXT motors so slow & irregular?
Hi elemes,

I have gotten the same results with two sets of motors, one set fairly old but lightly used and the second set brand new with less that 15 minutes on them.

Have you tried running my program? I'd be interested in hearing what you find. You could comment out the light-sensor line without effecting the times at all. I included it because I do use a light sensor in the project I'm working on, and I wanted to see if it was the cause for the 200 ms delay. By putting timers before and after various statements, I've concluded that virtually all the time is being consumed by the motors, less than 1 ms by the rest of the program.

Also, is there anything I'm doing wrong in the runMotor functions?

I'm using ROBOTC ver 1.46, and the motors are running with no load, off the ground.

Regards,

Ted


Sat Jan 10, 2009 12:06 pm
Profile WWW
Rookie

Joined: Fri Feb 16, 2007 4:11 pm
Posts: 41
Location: Padanaram, MA
Post Re: Why are NXT motors so slow & irregular?
Greetings,

I've gleaned some interesting if not illumunating results by putting timers before and after certain statements in my Code. Time T1 shows the total time per loop. Time T2 shows the time measuring the light value. Time T3 shows the time in random() calculating the encoder target. Time T4 shows the time used by the motors. I have attached an MS Excel spread sheet showing the results.

Time T1 should be approximately equal to T2 + T3 + T4, but T2 and T3 are shown as being zero and T4, the time running the motors, is much less than T1! Where is the lost time being consumed?

The good part is that there is a nice linear relation between the motor angle and the motor time with a slope of approximately 682 deg/sec with a motor power of 75% and a battery voltage of 8.1 volts.

Regards,

Ted


Attachments:
File comment: MS Excel spread sheet. Change .txt ending too .xls to open in MS Excel.
TestMotorsGeneral-Targeted 11jan09 12-11pm.txt [42.5 KiB]
Downloaded 123 times


Last edited by tedkurtz on Sun Jan 11, 2009 5:25 pm, edited 2 times in total.

Sun Jan 11, 2009 12:06 pm
Profile WWW
Rookie

Joined: Fri Feb 16, 2007 4:11 pm
Posts: 41
Location: Padanaram, MA
Post Re: Why are NXT motors so slow & irregular?
Greetings,

I'm trying to learn more about where the lost time is being consumed. To eliminate any possibility of it occurring in random() I have altered the code slightly. In the new code I calculate a table of random encoder-target values. Then, in the motor-control loop, I use this table of encoder-target values to control the motor. Thus, random() is not called all in the motor-control loop. I've put timers T1, T2, T3 and T4, at various locations to measure where time is being consumed. This code is as follows:

Code:
#pragma config(Sensor, S1,     TouchSensor,         sensorTouch)
#pragma config(Sensor, S2,     LightSensor,         sensorLightActive)
#pragma config(Motor,  motorA,          A_Motor,       tmotorNormal, PIDControl)
#pragma config(Motor,  motorC,          C_Motor,       tmotorNormal, PIDControl)
//*!!Code automatically generated by 'ROBOTC' configuration wizard               !!*//

const int kDatalogSize = 4000;

bool forward = true;
bool backward = false;
bool saveRunData = true;

int i;
int target[151];
int motorPower = 75;            // Set for 750 encoder counts (degrees) per second
int encoderTarget0;             // Reference wheel rotation, degrees
int encoderTarget;              // Acxtual wheel rotation
int motorAEncoderValue;
int motorCEncoderValue;
int elapsedTime1;                // Elapsed time for timer T1(ms)
int elapsedTime2;                // Elapsed time for timer T2(ms)
int elapsedTime3;                // Elapsed time for timer T3(ms)
int elapsedTime4;                // Elapsed time for timer T4(ms)
int lightValue;
int cntr;
int selection;
const int targeted = 1;
const int synchronized = 2;
const int unsynchronized = 3;
int waitTime = 100;

//########################################################################
void runMotorTargeted(bool &direction)
{
    time1[T4] = 0;
   nMotorPIDSpeedCtrl[motorA] = mtrSpeedReg;       // Enable motor-speed regulation
//   nMaxRegulatedSpeedNxt = 750;                    // For consistent speed
  nSyncedMotors = synchAC;                        // Synchronize A & C
   nSyncedTurnRatio = 100;                         // Turn equally
   nPidUpdateIntervalNxt = 20;                     // Recommended by Dick Swan
   nMotorEncoder[motorA]= 0;                       // Initialize encoder to zero
   bFloatDuringInactiveMotorPWM = false;           // Brakes on
  bMotorReflected[motorA] = direction;            // Our positive is Lego's negative
  nMotorEncoderTarget[motorA] = encoderTarget;    // incremental amount to move motor
  motor[motorA] = motorPower;

  while (nMotorRunState[motorA] != runStateIdle)  // wait for action to complete
  {}
  wait1Msec(waitTime); // Need this for reliable behavior
    elapsedTime4 = time1[T4];

}

//########################################################################
void runMotorSyncd(bool &direction)
{
   bool wait;
    time1[T4] = 0;
   nMotorPIDSpeedCtrl[motorA] = mtrSpeedReg;   // Enable motor-speed regulation
//   nMaxRegulatedSpeedNxt = 750;                // For consistent speed
   nSyncedMotors = synchAC;                    // Synchronize A & C
   nSyncedTurnRatio = 100;                     // Turn equally
   nPidUpdateIntervalNxt = 20;                 // Recommended by Dick Swan
   nMotorEncoder[motorA]= 0;                   // Initialize encoder to zero
   bFloatDuringInactiveMotorPWM = false;       // Brakes on
  bMotorReflected[motorA] = direction;        // Our positive is Lego's negative
  motor[motorA] = motorPower;

  wait = true;
  do  // Wait for encoder to reach desired value
  {
      if (nMotorEncoder[motorA] >= encoderTarget)
      {
       motor[motorA] = 0;  // Stop
         wait = false;
      }
  }
  while(wait);

  wait1Msec(waitTime); // Need this for reliable behavior
    elapsedTime4 = time1[T4];

}

//########################################################################
void runMotorUnsyncd(bool &direction)
{
   bool wait, motorA_OK, motorC_OK;
    time1[T4] = 0;
   nMotorPIDSpeedCtrl[motorA] = mtrSpeedReg;   // Enable motor-speed regulation
   nMotorPIDSpeedCtrl[motorC] = mtrSpeedReg;   // Enable motor-speed regulation
//   nMaxRegulatedSpeedNxt = 750;                // For consistent speed
   nPidUpdateIntervalNxt = 20;                 // Recommended by Dick Swan
   nMotorEncoder[motorA]= 0;                   // Initialize encoder to zero
   nMotorEncoder[motorC]= 0;                   // Initialize encoder to zero
   bFloatDuringInactiveMotorPWM = false;       // Brakes on
  bMotorReflected[motorA] = direction;        // Our positive is Lego's negative
  bMotorReflected[motorC] = direction;        // Our positive is Lego's negative
  motorA_OK = false;
  motorC_OK = false;
  wait = true;
  motor[motorA] = motorPower;
  motor[motorC] = motorPower;

  do  // Wait for encoder to reach desired value
  {
      if (nMotorEncoder[motorA] >= abs(encoderTarget))
      {
       motor[motorA] = 0;  // Stop
       motorA_OK = true;
      }
      if (nMotorEncoder[motorC] >= abs(encoderTarget))
      {
       motor[motorC] = 0;  // Stop
       motorC_OK = true;
      }
      if (motorA_OK && motorC_OK)
      {
         wait = false;
      }
  }
  while(wait);

  /* This does not work
  while (nMotorRunState[motorA] != runStateIdle)
   {
   //do nothing until motor is at target//
   }
  */

  wait1Msec(waitTime); // Need this for reliable behavior
    elapsedTime4 = time1[T4];

}

//########################################################################
void runMotor(bool &direction, const int &selection)
{
   switch(selection)
   {
      case targeted:
      {
      runMotorTargeted(direction);
   }
      case synchronized:
      {
         runMotorSyncd(direction);
    }
      case unsynchronized:
      {
        runMotorUnsyncd(direction);
      }
   }
}

//########################################################################
//########################################################################
//########################################################################
//########################################################################
//########################################################################
task main()
{
   hogCPU(); // I don't know what this does, but it sounds interesting
   selection = targeted;
//   selection = synchronized;
//   selection = unsynchronized;
//  wait1Msec(2000);  // Use for a breakpoint
   nDatalogSize = kDatalogSize;
   encoderTarget0 = 90;
   cntr = 0;

   for (i = 1; i <= 150; i++)  // Set up encoder target table
   {
      target[i] = random(encoderTarget0) - encoderTarget0/2;
   }

   for (i = 1; i <= 150; i++)  // Motor control loop
   {
    time1[T1] = 0;
//    time1[T3] = 0;
//    time1[T4] = 0;
    time1[T2] = 0;
     lightValue = SensorRaw(LightSensor);   // Get current light reading
    elapsedTime2 = time1[T2];
      encoderTarget = target[i];
    if (encoderTarget != 0)
    {
       if (encoderTarget > 0)
       {
        time1[T3] = 0;
          runMotor(forward, selection);
        elapsedTime3 = time1[T3];
      }
      else
       {
        time1[T3] = 0;
         encoderTarget = - encoderTarget;
         runMotor(backward, selection);
        elapsedTime3 = time1[T3];
      }
    }
//    elapsedTime4 = time1[T4];
//    elapsedTime2 = time1[T2];
    elapsedTime1 = time1[T1];
//  wait1Msec(2000);  // Use for a breakpoint
     motorAEncoderValue = nMotorEncoder[motorA]; // Current value of motor encoder (for testing)
     motorCEncoderValue = nMotorEncoder[motorC]; // Current value of motor encoder (for testing)
      if (saveRunData && cntr < kDatalogSize - 7) // Don't try to exceed capacity
    {
       motorAEncoderValue = nMotorEncoder[motorA]; // Current value of motor encoder (for testing)
         AddToDatalog(1,elapsedTime1);
         AddToDatalog(2,motorAEncoderValue);
         AddToDatalog(3,motorCEncoderValue);
         AddToDatalog(4,encoderTarget);
         AddToDatalog(5,elapsedTime2);
         AddToDatalog(6,elapsedTime3);
         AddToDatalog(7,elapsedTime4);
      cntr = cntr + 7;
    }

   }

   SaveNxtDatalog(); // Move DataLog data from RAM to Flash memory
  StopAllTasks(); // we're finished.
   return;
}


I've run this code for two values of waitTime, 1 ms and 100 ms. This is the time runMotor() waits before returning to the main task.

I've attached two MS Excel spreadsheets, one for each value of waitTime. Time T3 is measured immediately before and after the motors are run. Time T4 is also measured before and after the motors are run. I'd expect them to be nearly identical, and yet they are wildly different. Also, the motors do a good job of going to their targets when waitTime = 1 ms, but a poor job when the waitTime = 100 ms.

Interesting thing to note is that random() produces exactly the same series of numbers each time it is run. The seed is the same each time. This is useful here because it permits comparison of results.

I am frustrated by this unexplained computer-time problem. The only reason I'm running these tests is to find out what is causing the big useless hunk of computer time. Something weird is going on in ROBOTC. Does anyone have any ideas about what is causing this?

Regards,

Ted


Attachments:
File comment: MS Excel file. Change ending .txt to .xls before opening in Excel
TestMotorsGeneral-Targeted 11jan09 2-54pm.txt [52.5 KiB]
Downloaded 134 times
File comment: MS Excel file. Change ending .txt to .xls before opening in Excel
TestMotorsGeneral-Targeted 11jan09 2-26pm.txt [52.5 KiB]
Downloaded 121 times
Sun Jan 11, 2009 5:12 pm
Profile WWW
Display posts from previous:  Sort by  
Reply to topic   [ 7 posts ] 

Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  



Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software for PTF.