I see that the 21 point move is supposed to end on positions 0, 0.
But the function seems to indicate that you are starting from position
0.0779877, -0.00151062.
You always want your first point passed to PT to be your current position. Otherwise you will be trying an instantaneous jump to that position. While I would be it is the ErrorLimit which triggering an error, it could also be safety features within a drive.
Although, in this particular instance, going from 0.077987 to 0 for Axis X and from -0.00151062 to 0 should not trigger error limit with delta of 0.2 seconds. It should then also trigger the same when I am not sending data in chunks.
But nevertheless, Let me modify the code to accept current position as the first array item and see if it solves.
My ErrorLimitTriggerValue is 0.1 * User units or 0.1 * 65536
Here is the result with current position as the first 2 elements of the points array. No motiondonewait function is used.
There is a slight mismatch with user units data read before homing and what is being passed in the array. This is because brake is disengadged which shifts the values slightly.
This one is after modification where I am enabling the motors first and then taking the current position values and passing along the same. Eliminating the braking positional mismatch.
I believe it is the empty count that you are setting. Since you are setting the empty count equal to the number of frames you are sending out, you are immediately triggering the Estop event to protect your system.
You want the empty count to be sufficient for EStopTime to complete within your profile, but not large enough that you should ever be in a situation where youâve starved the buffer of loaded points to that point. It is your failsafe emergency buffer that you donât want to get into.
Use the following as a seed function for the behavior you needed:
int DetermineEmptyCountFramesBasedOnTimes(const std::vector<double>& timeDelta, double requiredEStopTime) {
double accumulatedTime = 0.0;
int count = 0;
for (double time : timeDelta) {
accumulatedTime += time;
++count;
if (accumulatedTime >= requiredEStopTime) {
break;
}
}
const int THERE_ARE_TWO_FRAMES_PER_POINT = 2;
return count * THERE_ARE_TWO_FRAMES_PER_POINT;
}
Update your EMPTY_COUNT definition as follows: const int EMPTY_COUNT = DetermineEmptyCountFramesBasedOnTimes(timeDelta, axis->EStopTimeGet());
Note, axis is the variable name of the MultiAxis parameter passed to the function example above.
MotionDoneWait() function declared right after the PT motion command inside my iteration loop. This time the motion did execute for the first iteration but I got âState Errorâ for iteration 2.
First state error is slightly different than this time. In the first one its called RSIStataSTOPPING_ERROR while the second scenario says RSIStateERROR
But looks like in both situations its failing at 2nd iteration.
Can you also include Axis::SourceGet() when you are in the error state? I believe weâve been looking at Motion Out of Frames errors but Iâd like to know for sure. Something is triggering the error and we need to find out what is causing it.
MotionDoneWait() shouldnât be used with streaming motion until a final point has been sent. Otherwise youâll always run Out of Frames. Case 2 is doomed.
The last line of Output âAxis State X: Motion: RSIStateSTOPPING_ERROR :: {motion.c, line 1398} (Error 3850) (Axis::ClearFaults) (Object 0) (File axis.cpp) (Line 5872) (Version 10.6.2.0)â is a weird one as it does not display the actual message I had put in the function call when it encounters this case but rather displays the message above !
Youâre getting the error message for RSISourceUNKNOWN (which isnât helpful in your case).
Also it seems like you may be calling ClearFaults() when you shouldnât be clearing yet.
Youâll only want to print the source if/when the state is not MOVING or IDLE. Also, for the most information, youâll want to check axisX, axisY and your MultiAxis (as each could have a different source)
Overall it seems like youâre not calling the final MovePT in time.
Thanks for jumping in. I believe I am not clearing faults when trying to determine the cause of error.
This is the function I am using to determine the axis state.
std::string axisState(Axis *axis)
{
const int secondsToMilliseconds = 1000;
switch (axis->StateGet())
{
case RSIState::RSIStateMOVING:
axis->Abort();
axis->ClearFaults();
//std::cout << "in RSI Moving state"<< std::endl;
return "In Moving State";
//Wait standard stop time
case RSIState::RSIStateSTOPPING:
//std::cout << "in RSI Stopping"<< std::endl;
return "At Stopping State";
case RSIState::RSIStateSTOPPING_ERROR:
std::cout << "in RSI Moving error state"<< std::endl;
std::cout << "Source Stopping Error: "<< axis->SourceNameGet(axis->SourceGet()) << std::endl;
//Assuming that Stop Time is greater than EStop Time.
//std::this_thread::sleep_for((axis->StopTimeGet() * secondsToMilliseconds));
std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<int>(axis->StopTimeGet() * secondsToMilliseconds)));
//You may still be stopping if you have bad settings.
if (axis->StateGet() == RSIState::RSIStateSTOPPING || axis->StateGet() == RSIState::RSIStateSTOPPING_ERROR)
{
//Abort the axis. You should stopped but likely have bad settling criteria.
axis->Abort();
}
//axis->ClearFaults();
return "Stopping Error State";
break;
case RSIState::RSIStateERROR:
std::cout << "Source State Error: "<< axis->SourceNameGet(axis->SourceGet()) << std::endl;
return "State Error";
case RSIState::RSIStateSTOPPED:
//axis->ClearFaults();
return "Stopped State";
break;
case RSIState::RSIStateIDLE:
//std::cout << "in Idle State"<< std::endl;
return "IDLE State";
default:
//std::cout << "in default state"<< std::endl;
return "Default State";
break;
}
}
My clear faults line is commented in one of the cases.
In my main code, where I am calling a custom MovePT function I am just sending out commands to execute the motion without any declaration of clear faults. And I am printing these values on console before every iteration.
// Visualization: Print the position and time data
std::cout << "Iteration " << i / POINTS_PER_CALL + 1 << â\nâ;
std::cout << "Raw Encoder X: " << axisX->EncoderPositionGet(RSIMotorFeedback::RSIMotorFeedbackPRIMARY) << â\nâ;
std::cout << "Source State Error X: "<< axisX->SourceNameGet(axisX->SourceGet()) << std::endl;
std::cout << "Axis State X: " << axisState(axisX) << â\n\nâ;
std::cout << "Raw Encoder Y: " << axisY->EncoderPositionGet(RSIMotorFeedback::RSIMotorFeedbackPRIMARY) << â\nâ;
std::cout << "Source State Error Y: "<< axisY->SourceNameGet(axisY->SourceGet()) << std::endl;
std::cout << "Axis State Y: " << axisState(axisY) << â\n\nâ;
std::cout << "Empty Count " << EMPTY_COUNT << â\nâ;
std::cout << âProcessing " << pointsThisIteration << " points\nâ;
std::cout << "Positions: [ ";
for (double p : positions)
{
std::cout << p << " ";
}
std::cout << â]\nâ
<< "Positions Array Size: " << positions.size() << â\nâ;
But rather than displaying one of the return messages declared in axisState function, it just displays this error message.
Motion: RSIStateSTOPPING_ERROR :: {motion.c, line 1398} (Error 3850) (Axis::ClearFaults) (Object 0) (File axis.cpp) (Line 5872) (Version 10.6.2.0)
Maybe this error is one of the cases I have NOT setup in the axisState function?
This is an exception method coming from the Axis::ClearFaults() method and itâs trying to tell you that you canât clear faults while the Axis is in the STOPPING_ERROR state.
Do you have some calls to ClearFaults() in your code? Maybe more context would help us troubleshoot.