[NXC]Motor-control-functions

Discussion specific to NXT-G, NXC, NBC, RobotC, Lejos, and more.
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: [NXC]Motor-control-functions

Post by HaWe »

indeed I'm also curious what mazzn tried , but anyway -
IMHO the PosReg functions are far too complicated to handle and have lots of issues concerning intern tacho counters and internally stored targeting errors which add up to increasing error values over the time, especially when passive shifting happens intermediately.
So I'm not surprised that those functions might have led to suboptimal usage.

the same it's about this code: far too hard to understand and far too complicated to modify:

Code: Select all

void RotateMotorRURD(byte output, char pwr, long angle, bool UseSpeedControl = true)
{
  long l1, l2, l3;
  char power = sign(angle);
  angle = abs(angle);
  power *= pwr;

  if (angle > 720)
    l1 = angle*0.10;
  else
    l1 = angle*0.20;
  l3 = l1;
  l2 = angle-(l1+l3);
  byte om = OUT_MODE_MOTORON|OUT_MODE_BRAKE;
  byte rm = OUT_REGMODE_IDLE;
  if (UseSpeedControl) {
    om += OUT_MODE_REGULATED;
    rm = OUT_REGMODE_SPEED;
  }
  // we want to rotate a total of <angle> degrees
  // we'll rampup from 0 power to specified power through 20% of the angle
  // then run at the specified power for 60% of the angle
  SetOutput(output, OutputModeField, om,
                    TachoLimitField, l1,
                    PowerField, power,
                    RegModeField, rm,
                    RunStateField, OUT_RUNSTATE_RAMPUP,
                    UpdateFlagsField, UF_UPDATE_MODE|UF_UPDATE_SPEED|UF_UPDATE_TACHO_LIMIT);
  Yield(); // give firmware a chance to process this request to update motor state
  // monitor runstate
  while(MotorRunState(output) <> OUT_RUNSTATE_IDLE)
    Yield();
  // as soon as it goes idle put the motor into the running state
  SetOutput(output, OutputModeField, om,
                    TachoLimitField, l2,
                    PowerField, power,
                    RegModeField, rm,
                    RunStateField, OUT_RUNSTATE_RUNNING,
                    UpdateFlagsField, UF_UPDATE_MODE|UF_UPDATE_SPEED|UF_UPDATE_TACHO_LIMIT);
  Yield(); // give firmware a chance to process this request to update motor state
  // monitor runstate
  while(MotorRunState(output) <> OUT_RUNSTATE_IDLE)
    Yield();
  // as soon as the runstate goes idle we rampdown to zero power
  SetOutput(output, OutputModeField, om,
                    TachoLimitField, l3,
                    PowerField, 0,
                    RegModeField, rm,
                    RunStateField, OUT_RUNSTATE_RAMPDOWN,
                    UpdateFlagsField, UF_UPDATE_MODE|UF_UPDATE_SPEED|UF_UPDATE_TACHO_LIMIT);
  Yield(); // give firmware a chance to process this request to update motor state
  // monitor runstate
  while(MotorRunState(output) <> OUT_RUNSTATE_IDLE)
    Yield();
  // now apply powered braking for a little while
  SetOutput(output, OutputModeField, OUT_MODE_MOTORON+OUT_MODE_BRAKE+OUT_MODE_REGULATED,
                    TachoLimitField, 0,
                    PowerField, 0,
                    RegModeField, OUT_REGMODE_SPEED,
                    RunStateField, OUT_RUNSTATE_RUNNING,
                    UpdateFlagsField, UF_UPDATE_MODE|UF_UPDATE_SPEED|UF_UPDATE_TACHO_LIMIT);
  Yield(); // give firmware a chance to process this request to update motor state
  long rc = MotorRotationCount(output);
  long oldrc = rc+1;
  while (oldrc <> rc) {
    oldrc = rc;
    Wait(100);  // adjust this wait time to see what impact it has on accuracy.
    rc = MotorRotationCount(output);
  }
  // finally, go idle
  SetOutput(output, OutputModeField, OUT_MODE_COAST+OUT_MODE_REGULATED,
                    TachoLimitField, 0,
                    PowerField, 0,
                    RegModeField, OUT_REGMODE_SPEED,
                    RunStateField, OUT_RUNSTATE_IDLE,
                    UpdateFlagsField, UF_UPDATE_MODE);
  Yield(); // give firmware a chance to process this request to update motor state
}

bool bDone = false;

task MoveMotors()
{
  RotateMotorRURD(OUT_A, 75, 2520);
  Wait(2000);
  RotateMotorRURD(OUT_A, 75, -2520);
  Wait(2000);
/*
  RotateMotorRURD(OUT_A, 75, 720, false);
  Wait(500);
  RotateMotorRURD(OUT_A, 75, -720, false);
  Wait(500);
*/
  RotateMotorRURD(OUT_A, 75, 2520);
  Wait(2000);
  RotateMotorRURD(OUT_A, 75, -2520);
  Wait(2000);
/*
  RotateMotorRURD(OUT_A, 75, 720, false);
  Wait(500);
  RotateMotorRURD(OUT_A, 75, -720, false);
  Wait(500);
*/
  bDone = true;
}

task MonitorMotors()
{
  while (!bDone) {
    ClearScreen();
    NumOut(0, LCD_LINE1, MotorRunState(OUT_A));
    NumOut(0, LCD_LINE2, MotorMode(OUT_A));
    NumOut(0, LCD_LINE3, MotorRotationCount(OUT_A));
    NumOut(0, LCD_LINE4, MotorTachoCount(OUT_A));
    NumOut(0, LCD_LINE5, MotorBlockTachoCount(OUT_A));
    Wait(10);
  }
}

task main()
{
  Precedes(MoveMotors, MonitorMotors);
  ResetRotationCount(OUT_A);
  Wait(5);
}
IMO, an absolute targeting function should have the following simple syntax - all additonal adjustment must be managed by FW or API functions, maybe userinvention possible by adjusting seperate global motor variables (P, I, D, ramp/up/down) but no compulsion of being passed at every function call which makes the handling much more convenient:

Code: Select all

MotorTarget [OUT_x] = ZZZ;             // set Encoder-Target MotorTarget[OUT_x] internally used by a  PID control, automatically setting of ramp up/down
MoveMotorTo(MotorTarget[OUT_x]) {     // PID-Control takes motorcontrol ; MotorRunState set to "busy"; interruptable by user at any time,
  while (MotorRunState(OUT_x) != idle) } // while movement is not finished and target has not been reached finally;
BreakMotor(OUT_x);                      // after target has been reached perfectly: break or coast, switch off PID-Control, MotorRunstate set to "idle"
Post Reply

Who is online

Users browsing this forum: No registered users and 2 guests