Penta Axis (PAX) support
-
@joergs5 thanks for participating
M203 B20000 is 333 degree/second, which is quite high*)
RRF all speeds are mm or degrees per minutes. Also,
G1 A20
performs ok (doesn't not involve X/Y/Z if B=0).I have lowered it earlier to
M203 A10000 B10000
(the info on my blog isn't up-to-date as I change it a lot), but as you perhaps read on my above experience, it's not so much tuning min/max speed the problem as such, the click/blocked motor indicates way out of range speed or acel/decel, there is miscalculation somewhere on DDA/DDARing level, which my debug info I posted today confirms or hints to. I currently try to comprehend Move/DDA/DDARing functionality better, perhaps I'm missing an important config which leads to thed=nan
(deceleration) line (see my other post on this thread). -
@xyzdims unfortunately I won't have time to look at this in detail for the next couple of weeks. But the following may be useful:
- Acceleration and speed limits set by M201 and M203 apply to the movements of axes as specified on the command line. So if e.g. you command X to move and your kinematics causes B to move as well, the acceleration and speed B won't be limited by the M201/M203 B values, only by the M201/203 X values and the ration of B movement to X movement.
- If you get NaNs in the calculations, this normally means that somewhere you have taken the square root of a negative number, or taken an arcsin or arccos of a number outside the range -1.0..1.0.
- This bit of your debug looks odd:
pr 1 ts=43851297 DDA: start=[0.000000 0.000000 0.000000 0.000000 20.000000] end=[0.000000 0.000000 0.000000 0.000000 20.000000] s=0.000000 vec=[0.000000 0.000000 0.000000 0.000000 20.000000] a=40.000000 d=nan reqv=4.166667 startv=0.000000 topv=0.000000 endv=0.000000 cks=0 sstcda=0 tstcddpdsc=0 exac=0
Assuming you created extra axes A B only in that order, this means that your kinematics command a move of total distance NaN after segmentation, and B was moving 20 times as much as the distance specified in the G1 command. That's not right, only axes that are moving implicitly should have have a 'vec' component greater than 1. You need to find out where that NaN is coming from. Check that you haven't accidentally set the segmentation distance to zero.
-
PS - you might want to try the same move using regulator Cartesian kinematics + your A and B axes, to check that the code outside your kinematics is behaving properly in the same configuration.
-
The "pr" comes from
void DDA::Prepare()
in DDA.cpp, thered
or decelaration is NAN.G1 B20
: DDA "pr": a=40.0 (aceleration), d=NAN (deceleration), s=0.0 (distance)G1 X0.1 B20
: DDA "pr": a=4.0, d=4.0, s=0.1I need to dive deeper into the DDA.cpp to find out, I suspect the main problem could be s=0.0; just after
if(delta!=0)
in DDA::Prepare() the debug is printed out with tag "pr", it determined there is change, but distance is 0 (=> contradiction), and if any value is divided by s (=0.0) before we get NAN. -
-
So, DDA.cpp: DDA::Prepare() calls https://github.com/Duet3D/RepRapFirmware/blob/3.3-dev/src/Movement/DriveMovement.cpp#L59
PrepareCartesianAxis()
just before the debug, and thereconst float stepsPerMm = (float)totalSteps/dda.totalDistance;
and
dda.totalDistance
is 0.0 . . . and other calculations follow about acceleration / deceleration, there the NAN is created.The problem starts somewhere in DDA.cpp
DDA::InitStandardMove()
, theretotalDistance
is calculated, which should be non-zero and it looks it is 0.0 there too.if (linearAxesMoving) { // There is some linear axis movement, so normalise the direction vector so that the total linear movement has unit length and 'totalDistance' is the linear distance moved. // This means that the user gets the feed rate that he asked for. It also makes the delta calculations simpler. // First do the bed tilt compensation for deltas. directionVector[Z_AXIS] += (directionVector[X_AXIS] * k.GetTiltCorrection(X_AXIS)) + (directionVector[Y_AXIS] * k.GetTiltCorrection(Y_AXIS)); totalDistance = NormaliseLinearMotion(reprap.GetPlatform().GetLinearAxes()); debugPrintf("DDA::InitStandardMove.1: %f totalDistance\n",totalDistance); } else if (rotationalAxesMoving) { // Some axes are moving, but not axes that X or Y are mapped to. Normalise the movement to the vector sum of the axes that are moving. totalDistance = Normalise(directionVector, reprap.GetPlatform().GetRotationalAxes()); debugPrintf("DDA::InitStandardMove.2: %f totalDistance\n",totalDistance); } else { // Extruder-only movement. Normalise so that the magnitude is the total absolute movement. This gives the correct feed rate for mixing extruders. totalDistance = 0.0; for (size_t d = 0; d < MaxAxesPlusExtruders; d++) { totalDistance += fabsf(directionVector[d]); } if (totalDistance > 0.0) // should always be true { Scale(directionVector, 1.0/totalDistance); } } debugPrintf("DDA::InitStandardMove.3: %f totalDistance\n",totalDistance);
linearAxesMoving
androtationalAxesMoving
are bothtrue
when I doG1 B20
, so which gives strange debug results:DDA::InitStandardMove.1: 0.000000 totalDistance DDA::InitStandardMove.3: 0.000000 totalDistance
As reminder:
G1 B20
, causing Y, Z and B motors to move by request ofPAXKinematics::CartesianToMotorSteps()
.That both
linearAxesMoving
androtationalAxesMoving
aretrue
makes sense, given they mean motor axes.I think there is a bug in the logic of the code I quoted above:
if(linearAxesMoving)
code block needs to considerrotationalAxesMoving
case too, it's both, not "either or" as withelse if(rotationalAxesMoving)
I disabled
if(0 && linearAxesMoving)
case forG1 B20
, and I had correct mechanical movement! [Update: https://www.youtube.com/watch?v=2x_rOThE_Ns doingG1 B45
andG1 B0
again, the nozzle tip is supposed to stay in place in relation to bed (hence Y, Z and B movement) ].@dc42 Let me know if there is someone else I should address this in case you don't have the time/capacity. I think we are close to resolve this.
-
@xyzdims thanks for looking into this. I think the bug is that if you have declared B to be a rotational axis (the default), then linearAxesMoving should not be set for a G1 B20 move. It should be set if any only if there is motion of the tool head in Cartesian space. The fact that your kinematics has to move X, Y or Z when moving B should not cause linearAxesMoving to be set.
Looking into this some more, I think the linear or rotational axis moving flag should be set as moving if positionDelta is nonzero, not if delta is nonzero as at present.
-
@dc42
doMotorMapping
istrue
inDDA::InitStandardMove()
; not sure what the flag actually means, I inserted some moredebugPrintf
in the relevant loop:if (doMotorMapping) { delta = endPoint[drive] - positionNow[drive]; debugPrintf("axis #%d: posN %d -> endP %d => delta=%d\n",drive,positionNow[drive],endPoint[drive],delta); const float positionDelta = endCoordinates[drive] - prev->GetEndCoordinate(drive, false); debugPrintf(" positionDelta=%f\n",positionDelta); directionVector[drive] = positionDelta; if (positionDelta != 0.0 && (Tool::GetXAxes(nextMove.tool).IsBitSet(drive) || Tool::GetYAxes(nextMove.tool).IsBitSet(drive))) { flags.xyMoving = true; // this move has XY movement in user space, before axis were mapped } }
G1 B20
requested:doMotorMapping=1, numVisibleAxes=5 axis #0: posN 0 -> endP 0 => delta=0 positionDelta=0.000000 axis #1: posN 0 -> endP -1539 => delta=-1539 positionDelta=0.000000 axis #2: posN 0 -> endP -1085 => delta=-1085 positionDelta=0.000000 axis #3: posN 0 -> endP 0 => delta=0 positionDelta=0.000000 axis #4: posN 0 -> endP 45 => delta=45 positionDelta=20.000000 linearAxesMoving=1, rotationAxesMoving=1 DDA::InitStandardMove.1: totalDistance=0.000000 DDA::InitStandardMove.3: totalDistance=0.000000
Hope this helps.
-
@xyzdims this is the current code (I am looking at 3.4beta1 so it might be slightly different in 3.3):
for (size_t drive = 0; drive < MaxAxesPlusExtruders; drive++) { accelerations[drive] = normalAccelerations[drive]; endCoordinates[drive] = nextMove.coords[drive]; if (drive < numVisibleAxes) { int32_t delta; if (doMotorMapping) { delta = endPoint[drive] - positionNow[drive]; const float positionDelta = endCoordinates[drive] - prev->GetEndCoordinate(drive, false); directionVector[drive] = positionDelta; if (positionDelta != 0.0 && (Tool::GetXAxes(nextMove.tool).IsBitSet(drive) || Tool::GetYAxes(nextMove.tool).IsBitSet(drive))) { flags.xyMoving = true; // this move has XY movement in user space, before axis were mapped } } else { // Raw motor move on a visible axis endPoint[drive] = Move::MotorMovementToSteps(drive, nextMove.coords[drive]); delta = endPoint[drive] - positionNow[drive]; directionVector[drive] = (float)delta/reprap.GetPlatform().DriveStepsPerUnit(drive); } if (delta != 0) { #if 0 // debug only stepsRequested[drive] += labs(delta); #endif if (reprap.GetPlatform().IsAxisRotational(drive)) { rotationalAxesMoving = true; } else { linearAxesMoving = true; } } } else if (LogicalDriveToExtruder(drive) < reprap.GetGCodes().GetNumExtruders())
This is what I think it should be:
for (size_t drive = 0; drive < MaxAxesPlusExtruders; drive++) { accelerations[drive] = normalAccelerations[drive]; endCoordinates[drive] = nextMove.coords[drive]; if (drive < numVisibleAxes) { const float positionDelta = endCoordinates[drive] - prev->GetEndCoordinate(drive, false); if (positionDelta != 0.0) { if (reprap.GetPlatform().IsAxisRotational(drive)) { rotationalAxesMoving = true; } else { linearAxesMoving = true; } } int32_t delta; if (doMotorMapping) { delta = endPoint[drive] - positionNow[drive]; directionVector[drive] = positionDelta; if (positionDelta != 0.0 && (Tool::GetXAxes(nextMove.tool).IsBitSet(drive) || Tool::GetYAxes(nextMove.tool).IsBitSet(drive))) { flags.xyMoving = true; // this move has XY movement in user space, before axis were mapped } } else { // Raw motor move on a visible axis endPoint[drive] = Move::MotorMovementToSteps(drive, nextMove.coords[drive]); delta = endPoint[drive] - positionNow[drive]; directionVector[drive] = (float)delta/reprap.GetPlatform().DriveStepsPerUnit(drive); } #if 0 // debug only if (delta != 0) { stepsRequested[drive] += labs(delta); } #endif } else if (LogicalDriveToExtruder(drive) < reprap.GetGCodes().GetNumExtruders())
-
@dc42 I copied it, thanks! It works but give me a day or so to confirm some edge cases as well.