Adding Commands During Execution

Additional interpolation commands can be dynamically appended to the end of the path as the path interpolation executes. This allows paths with a large number of interpolation segments or samples to be executed without requiring a large buffer (as memory occupied by interpolation commands that have finished executing can be overwritten by new commands).

Whenever commands are added to the path, the velocity profile along the path will be recalculated including the new commands. This calculation may take some time, so the profile along the path will be fixed for the next 8 milliseconds or 1 millisecond per 2000 points remaining in the path, whichever is larger. If the calculation does not complete in this time, the command position or velocity of the axis may suddenly change.

To allow more time for the recalculation of the velocity profile, the setOverrideTime parameter can be set to TRUE, and the overrideTimePointsPerMillisecond parameter can be set to a value less than the default 2000. For example, by setting overrideTimePointsPerMillisecond to 1000, the amount of time allocated will be twice the default value.

The overrideTimePointsPerMillisecond parameter can be set to a value larger than the default 2000 to allocate less time for the recalculation. This can reduce the time between when points are added and the time when the velocity and acceleration along the path can be affected by the appended points, but will require a fast CPU for the calculation to complete in time.

The minimum calculation time is 8ms, even when the overrideTimePointsPerMillisecond parameter is changed.

The above parameters are only applicable when appending interpolation commands while the path interpolation is executing. If the path interpolation is stopped, the velocity profile will be recalculated for the entire path, including the current point.

The above parameters usually do not need to be modified unless the CPU is unusually slow. The number of points that were processed per millisecond can be obtained from the lastOverridePointsPerMillisecond status after adding points to the path while path interpolation is executing. A larger value indicates that more points were processed per millisecond. If this value is less than 4000, performance might improve by setting overrideTimePointsPerMillisecond to a smaller value (such as around 1/4 of lastOverridePointsPerMillisecond). The setOverrideTime parameter should be set to TRUE for overrideTimePointsPerMillisecond to have an effect.

When commands are added to the path, the shape of the existing path will not be modified. The smoothRadius will not cause the transition between the end of the existing path and the first new command to be smoothed. If the angle between the transition is large, the axes will decelerate to a stop at the transition before continuing execution.

The addition of commands to the path will fail if there is not enough space in the buffer to store all of the new commands (including additional sample points if sampleDistance is set). When the addition of commands fails, no commands are added to the buffer.

Adding Commands During Execution Example

The following sample code executes a path with a short sample distance. The buffer is too small to hold all of the interpolation commands at once, so they are dynamically added as the path executes and buffer space is freed.

//Create the path interpolation with look ahead buffer
wmxlib_AdvancedMotion->advMotion->CreatePathIntplLookaheadBuffer(0, 1000);

//Configure the path interpolation with look ahead channel
AdvMotion::PathIntplLookaheadConfiguration conf;

conf.axisCount = 2;
conf.axis[0] = 0;
conf.axis[1] = 1;
conf.compositeVel = 1000;
conf.compositeAcc = 4000;
conf.sampleDistance = 2;

wmxlib_AdvancedMotion->advMotion->SetPathIntplLookaheadConfiguration(0, &conf);

//Add the path interpolation with look ahead commands
AdvMotion::PathIntplLookaheadCommand path;

path.numPoints = 2;

path.point[0].type = AdvMotion::PathIntplLookaheadSegmentType::Linear;
path.point[0].data.linear.axisCount = 2;
path.point[0].data.linear.axis[0] = 0;
path.point[0].data.linear.axis[1] = 1;
path.point[0].data.linear.smoothRadius = 100;

path.point[1].type = AdvMotion::PathIntplLookaheadSegmentType::Linear;
path.point[1].data.linear.axisCount = 2;
path.point[1].data.linear.axis[0] = 0;
path.point[1].data.linear.axis[1] = 1;

int step = 0;
int err = 0;

//Add first command
path.point[0].data.linear.target[0] = 500;
path.point[0].data.linear.target[1] = 0;
path.point[1].data.linear.target[0] = 500;
path.point[1].data.linear.target[1] = 500;
wmxlib_AdvancedMotion->advMotion->AddPathIntplLookaheadCommand(0, &path);

//Start path interpolation with look ahead
wmxlib_AdvancedMotion->advMotion->StartPathIntplLookahead(0);

//Add the remaining commands as the buffer space is freed
while (step < 11) {

    //Set the target position for this command
    switch (step) {
    case 0:
        path.point[0].data.linear.target[0] = 500;
        path.point[0].data.linear.target[1] = 1000;
        path.point[1].data.linear.target[0] = 1000;
        path.point[1].data.linear.target[1] = 1000;
        break;
    case 1:
        path.point[0].data.linear.target[0] = 1500;
        path.point[0].data.linear.target[1] = 1000;
        path.point[1].data.linear.target[0] = 1500;
        path.point[1].data.linear.target[1] = 1500;
        break;
    case 2:
        path.point[0].data.linear.target[0] = 1500;
        path.point[0].data.linear.target[1] = 2000;
        path.point[1].data.linear.target[0] = 1000;
        path.point[1].data.linear.target[1] = 2000;
        break;
    case 3:
        path.point[0].data.linear.target[0] = 500;
        path.point[0].data.linear.target[1] = 2000;
        path.point[1].data.linear.target[0] = 500;
        path.point[1].data.linear.target[1] = 2500;
        break;
    case 4:
        path.point[0].data.linear.target[0] = 500;
        path.point[0].data.linear.target[1] = 3000;
        path.point[1].data.linear.target[0] = 0;
        path.point[1].data.linear.target[1] = 3000;
        break;
    case 5:
        path.point[0].data.linear.target[0] = -500;
        path.point[0].data.linear.target[1] = 3000;
        path.point[1].data.linear.target[0] = -500;
        path.point[1].data.linear.target[1] = 2500;
        break;
    case 6:
        path.point[0].data.linear.target[0] = -500;
        path.point[0].data.linear.target[1] = 2000;
        path.point[1].data.linear.target[0] = -1000;
        path.point[1].data.linear.target[1] = 2000;
        break;
    case 7:
        path.point[0].data.linear.target[0] = -1500;
        path.point[0].data.linear.target[1] = 2000;
        path.point[1].data.linear.target[0] = -1500;
        path.point[1].data.linear.target[1] = 1500;
        break;
    case 8:
        path.point[0].data.linear.target[0] = -1500;
        path.point[0].data.linear.target[1] = 1000;
        path.point[1].data.linear.target[0] = -1000;
        path.point[1].data.linear.target[1] = 1000;
        break;
    case 9:
        path.point[0].data.linear.target[0] = -500;
        path.point[0].data.linear.target[1] = 1000;
        path.point[1].data.linear.target[0] = -500;
        path.point[1].data.linear.target[1] = 500;
        break;
    case 10:
        path.point[0].data.linear.target[0] = -500;
        path.point[0].data.linear.target[1] = 0;
        path.point[1].data.linear.target[0] = 0;
        path.point[1].data.linear.target[1] = 0;
        break;
    }

    //Dynamically add the command when there is enough free space in the buffer
    do {
        err = wmxlib_AdvancedMotion->advMotion->AddPathIntplLookaheadCommand(0, &path);
        Sleep(100); //Wait before attempting to add command again
    } while (err != ErrorCode::None);

    //Execute next command
    step++;
}

//Wait for the path interpolation with look ahead to complete
AdvMotion::PathIntplLookaheadStatus pathStatus;
wmxlib_AdvancedMotion->advMotion->GetPathIntplLookaheadStatus(0, &pathStatus);
while(pathStatus.remainCommandCount > 0) {
    Sleep(10);
    wmxlib_AdvancedMotion->advMotion->GetPathIntplLookaheadStatus(0, &pathStatus);
}

//Move the axes to Idle state
wmxlib_AdvancedMotion->advMotion->StopPathIntplLookahead(0);

//Wait until the path interpolation with look ahead is in Stopped state
wmxlib_AdvancedMotion->advMotion->GetPathIntplLookaheadStatus(0, &pathStatus);
while(pathStatus.state != AdvMotion::PathIntplLookaheadState::Stopped) {
    Sleep(10);
    wmxlib_AdvancedMotion->advMotion->GetPathIntplLookaheadStatus(0, &pathStatus);
}

//Free the path interpolation with look ahead buffer (normally, the buffer should only be freed at the end of the application)
wmxlib_AdvancedMotion->advMotion->FreePathIntplLookaheadBuffer(0);

The following plots show the two-dimensional trajectory and the velocity of each axis when the above sequence is executed from position (0, 0).

../_images/WMXDOC_FUNC_PLA_SEC1_image11.png