Page 1 of 4

Ramp Up / Ramp Down

Posted: 20 Feb 2012, 18:11
by mcsummation
Re: https://sourceforge.net/apps/phpbb/mind ... =10#p12513

(I decided to break this out into its own thread, I've hijacked that other thread too much.)

After freshly downloading your code and running it on my NXT with fresh batteries, I'm seeing proper completion of the ramps.

Because I want one motor to brake at the end and one to coast, I added another parameter to the function call.

Code removed on edit.

I now get +/- 1 for the residual angles, which should be close enough.

Edit: I posted this just after you posted additions for "BrakeAtEnd". I'll redo my code based on your suggestion.

Re: Ramp Up / Ramp Down

Posted: 20 Feb 2012, 19:11
by mcsummation
What I would like is for the motor to come to a precise stop at the target. Then, either stay locked or float. One motor needs to stay braked, to hold it's position so the robot won't roll. The other will soon have the "foot" it controls lifted off the floor, so "float" works for it. Actually, I guess, it needs to stay braked until it's lifted up, then it can coast.

But, anyway, please explain what the difference is between these 3 code blocks. (Thank you for writing that routine, it is helping me understand how the motor control works.)

What I did:

Code: Select all

      // finally, go idle
      om = OUT_MODE_REGULATED;
      if (BrakeAtEnd)
        om |= OUT_MODE_BRAKE;
      else
        om |= OUT_MODE_COAST;
      SetOutput(output, OutputModeField, om,
                        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
Your first suggestion where you said, "If you want to optionally idle the motors at the end of the routine based on a boolean value passed in then just wrap the last little bit of code in an if statement."

Code: Select all

      if (!BrakeAtEnd)
      {
      // 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
      }
And your second suggestion where you said, "If you want this BrakeAtEnd parameter to stop the powered braking also then wrap that bit in an if statement as well.

Code: Select all

      if (BrakeAtEnd)
      {
      // 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

Re: Ramp Up / Ramp Down

Posted: 20 Feb 2012, 19:37
by afanofosc
To apply active braking (i.e., to hold the motor stopped at a specific position) you need to have the motor on (OUT_MODE_MOTORON), the run state running (OUT_RUNSTATE_RUNNING), the regulation mode set to speed (OUT_REGMODE_SPEED), the speed set to 0, and the motor has to have regulation enabled (OUT_MODE_REGULATED).

In your proposed code change you did not have OUT_MODE_MOTORON and you did not have OUT_RUNSTATE_RUNNING when the BrakeAtEnd parameter was true. Technically, if either the runstate is IDLE or the mode is missing the MOTORON bit then the motor is idle.

John Hansen

Re: Ramp Up / Ramp Down

Posted: 20 Feb 2012, 21:03
by mcsummation
Ah, I think I've got the BrakeAtEnd part now. Since the motor(s) had already had active braking on and the rotation had stopped, all that has to be done is decide on whether or not to coast the motor(s).

Thanks.

Re: Ramp Up / Ramp Down

Posted: 28 Feb 2012, 19:23
by mcsummation
Something I've noticed with this routine is that there seems to be a discontinuity when moving between ramp up and constant speed, as well as between constant speed and ramp down. It's as if the ramp up/down parts are using different power settings than the constant speed part.

Re: Ramp Up / Ramp Down

Posted: 28 Feb 2012, 22:53
by afanofosc
This should not be the case since the power level is specified as part of the ramp operation. I.e., you have a current power level and you tell the firmware that you want to adjust to a new higher power level using RAMPUP across a tachometer limit or vice versa, you have a current power level and you tell the firmware you want to adjust to a new lower power level using RAMPDOWN across a tachometer limit. At the end of the specified tachometer limit you should be at the new power level that is either lower or higher than the previous power level. Are you specifying speed regulation with the constant speed command and not specifying it with the ramp operation? I would closely inspect what motor commands you are using for the constant speed portion and make sure you aren't changing other settings that are causing the discontinuity that you are experiencing.

John Hansen

Re: Ramp Up / Ramp Down

Posted: 28 Feb 2012, 23:42
by mcsummation
Here's the ramp up/ramp down code. I think it is the same as what you posted further up the thread.

Code: Select all

void RotateMotorRURD(byte output,
                     char pwr,
                     long angle,
                     bool UseSpeedControl = true,
                     bool BrakeAtEnd = 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
    
    // Wait until the motor has stopped turning.
    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);
    }
    
    if (!BrakeAtEnd) {
        // 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
    }
}
And, here's the code I use to invoke it:

Code: Select all

RotateMotorRURD(OUT_B, 75, -lDistance);
(The lDistance is negated because the motor is running "backwards".)

If I messed it up when I copied it into my code, or if I modified it inadvertently, just let me know and I will fix what I messed up.

Other than the "jerk" on either side of the "constant speed", this sure smooths out the start and stop of a robot that sometimes is running on paper taped to the floor.

Re: Ramp Up / Ramp Down

Posted: 29 Feb 2012, 03:31
by afanofosc
I didn't understand what you were talking about, sadly. I thought you were talking about a rampup and then a call to OnFwd or something like that.

I can't see anything about the code that would explain a seemingly higher or lower power level when switching from a rampup to running or from running to rampdown. What happens if you comment out the running phase and make the rampup 50% and the rampdown 50% of the total - or divide the total duration into two rampup phases followed by two rampdown phases. The two middle phases could rampup/down from 80% of the specified power to 100% of the specified power (and back down again during the middle rampdown phase with the two phases combining to cover the tachometer limit previously allocated to the running phase.

John Hansen

Re: Ramp Up / Ramp Down

Posted: 29 Feb 2012, 03:53
by mcsummation
I'll do some more experiments tomorrow and let you know what I find.

Re: Ramp Up / Ramp Down

Posted: 29 Feb 2012, 23:23
by mcsummation
John, where can I find detailed information about each of the parameters used in the SetOutput call that you've used. I'm working my way through what's happening with the ramp up/down code and find I don't understand part of what I'm seeing. I'm instrumenting the ramp up/down, trying to understand all it's doing.

I'm also working my way through a set of experiments trying to get the ramp down to get to zero power/speed at the same time the rotation error goes to zero. Right now, the robot is still moving at a considerable speed when it should be stopped, so it overshoots and has to correct backwards, which causes some oscillation. I'm working on a multi-step ramp down to address this issue.

Also, what are the units returned on the MotorActualSpeed function? Is it the same as "power"?