Skip to content

Commit 74b2eef

Browse files
author
Luca Toniolo
committed
Add accurate S-curve jerk output for joint motion commands
Add infrastructure to output precise jerk values from the trajectory planner to joint commands during S-curve (planner_type=1) coordinated motion. Previously, joint jerk values were derived from cubic interpolation, which introduces numerical delays and inaccuracies. This change passes the exact path jerk and direction vector from the TP through emcmotStatus, allowing control.c to compute per-joint jerk as: joint_jerk = path_jerk * direction. Changes: - motion.h: Add current_acc, current_jerk, current_dir fields to emcmot_status_t - tc.c/tc.h: Add tcGetCurrentTangentUnitVector() for direction at current progress - tp.c: Output S-curve motion state in tpUpdateMovementStatus() - control.c: Override joint jerk values for XYZ joints in S-curve mode This improves jerk accuracy for Cartesian machines using S-curve planning, which is important for servo tuning and motion smoothness analysis. ABC-UVW to come in future
1 parent bdcca02 commit 74b2eef

5 files changed

Lines changed: 77 additions & 0 deletions

File tree

src/emc/motion/control.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1396,6 +1396,24 @@ static void get_pos_cmds(long period)
13961396
/* interpolate to get new position and velocity */
13971397
joint->pos_cmd = cubicInterpolate(&(joint->cubic), 0, &(joint->vel_cmd), &(joint->acc_cmd), &(joint->jerk_cmd));
13981398
}
1399+
1400+
/* Use accurate jerk values from TP output (for Cartesian machines only)
1401+
* For standard XYZ machines, joint[0-2] correspond to X, Y, Z axes
1402+
* TP outputs: current_jerk (path jerk) and current_dir (direction unit vector)
1403+
* Per-axis jerk = path_jerk * direction_component
1404+
*/
1405+
if (emcmotStatus->planner_type == 1) {
1406+
// S-curve mode: use accurate jerk values
1407+
double path_jerk = emcmotStatus->current_jerk;
1408+
PmCartesian dir = emcmotStatus->current_dir;
1409+
1410+
// For the first 3 joints (assuming X, Y, Z), use accurate jerk
1411+
if (NO_OF_KINS_JOINTS >= 1) joints[0].jerk_cmd = path_jerk * dir.x;
1412+
if (NO_OF_KINS_JOINTS >= 2) joints[1].jerk_cmd = path_jerk * dir.y;
1413+
if (NO_OF_KINS_JOINTS >= 3) joints[2].jerk_cmd = path_jerk * dir.z;
1414+
// Rotary axes (A, B, C) keep the cubic interpolator values for now
1415+
}
1416+
13991417
/* report motion status */
14001418
SET_MOTION_INPOS_FLAG(0);
14011419
if (tpIsDone(&emcmotInternal->coord_tp)) {

src/emc/motion/motion.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,14 @@ Suggestion: Split this in to an Error and a Status flag register..
648648
double current_vel;
649649
double requested_vel;
650650

651+
/* S-curve motion state - for accurate jerk output */
652+
double current_acc; /* current path acceleration */
653+
double current_jerk; /* current path jerk (accurate value from TP) */
654+
double decel_dist; /* S-curve deceleration distance (dlen1) for debugging */
655+
double tc_finalvel; /* S-curve segment final velocity for debugging */
656+
double tc_maxaccel; /* S-curve segment max tangential accel for debugging */
657+
PmCartesian current_dir; /* current motion direction unit vector */
658+
651659
unsigned int tcqlen;
652660
EmcPose tool_offset;
653661
int atspeed_next_feed; /* at next feed move, wait for spindle to be at speed */

src/emc/tp/tc.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,35 @@ int tcGetEndTangentUnitVector(TC_STRUCT const * const tc, PmCartesian * const ou
326326
return 0;
327327
}
328328

329+
/**
330+
* Calculate the unit tangent vector at the current progress of a move.
331+
* For linear moves, this is constant. For circular moves, it varies with progress.
332+
*/
333+
int tcGetCurrentTangentUnitVector(TC_STRUCT const * const tc, PmCartesian * const out) {
329334

335+
switch (tc->motion_type) {
336+
case TC_LINEAR:
337+
*out = tc->coords.line.xyz.uVec;
338+
break;
339+
case TC_RIGIDTAP:
340+
*out = tc->coords.rigidtap.xyz.uVec;
341+
break;
342+
case TC_CIRCULAR:
343+
{
344+
// Calculate current angle based on progress
345+
double current_angle = 0.0;
346+
if (tc->target > 0.0) {
347+
current_angle = (tc->progress / tc->target) * tc->coords.circle.xyz.angle;
348+
}
349+
pmCircleTangentVector(&tc->coords.circle.xyz, current_angle, out);
350+
}
351+
break;
352+
default:
353+
rtapi_print_msg(RTAPI_MSG_ERR, "Invalid motion type %d!\n", tc->motion_type);
354+
return -1;
355+
}
356+
return 0;
357+
}
330358

331359
/**
332360
* Calculate the distance left in the trajectory segment in the indicated

src/emc/tp/tc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ int tcGetEndAccelUnitVector(TC_STRUCT const * const tc, PmCartesian * const out)
3939
int tcGetStartAccelUnitVector(TC_STRUCT const * const tc, PmCartesian * const out);
4040
int tcGetEndTangentUnitVector(TC_STRUCT const * const tc, PmCartesian * const out);
4141
int tcGetStartTangentUnitVector(TC_STRUCT const * const tc, PmCartesian * const out);
42+
int tcGetCurrentTangentUnitVector(TC_STRUCT const * const tc, PmCartesian * const out);
4243

4344
double tcGetDistanceToGo(TC_STRUCT const * const tc, int direction);
4445
double tcGetTarget(TC_STRUCT const * const tc, int direction);

src/emc/tp/tp.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2980,6 +2980,13 @@ STATIC int tpUpdateMovementStatus(TP_STRUCT * const tp, TC_STRUCT const * const
29802980
emcmotStatus->current_vel = 0;
29812981
emcmotStatus->spindleSync = 0;
29822982

2983+
// Clear S-curve motion state
2984+
emcmotStatus->current_acc = 0;
2985+
emcmotStatus->current_jerk = 0;
2986+
emcmotStatus->current_dir.x = 0;
2987+
emcmotStatus->current_dir.y = 0;
2988+
emcmotStatus->current_dir.z = 0;
2989+
29832990
emcPoseZero(&emcmotStatus->dtg);
29842991

29852992
tp->motionType = 0;
@@ -3001,6 +3008,21 @@ STATIC int tpUpdateMovementStatus(TP_STRUCT * const tp, TC_STRUCT const * const
30013008
emcmotStatus->requested_vel = tc->reqvel;
30023009
emcmotStatus->current_vel = tc->currentvel;
30033010

3011+
// Output accurate S-curve motion state (for accurate jerk calculation)
3012+
emcmotStatus->current_acc = tc->currentacc;
3013+
emcmotStatus->current_jerk = tc->currentjerk;
3014+
3015+
// Get current motion direction unit vector (precise tangent at current progress)
3016+
PmCartesian dir;
3017+
if (tcGetCurrentTangentUnitVector(tc, &dir) == 0) {
3018+
emcmotStatus->current_dir = dir;
3019+
} else {
3020+
// If direction unavailable, use zero vector
3021+
emcmotStatus->current_dir.x = 0;
3022+
emcmotStatus->current_dir.y = 0;
3023+
emcmotStatus->current_dir.z = 0;
3024+
}
3025+
30043026
emcPoseSub(&tc_pos, &tp->currentPos, &emcmotStatus->dtg);
30053027
return TP_ERR_OK;
30063028
}

0 commit comments

Comments
 (0)