tp.c
来自「CNC 的开放码,EMC2 V2.2.8版」· C语言 代码 · 共 1,046 行 · 第 1/3 页
C
1,046 行
end_uvw.tran.x = end.u; end_uvw.tran.y = end.v; end_uvw.tran.z = end.w; start_abc.tran.x = tp->goalPos.a; start_abc.tran.y = tp->goalPos.b; start_abc.tran.z = tp->goalPos.c; end_abc.tran.x = end.a; end_abc.tran.y = end.b; end_abc.tran.z = end.c; start_xyz.rot = identity_quat; end_xyz.rot = identity_quat; start_uvw.rot = identity_quat; end_uvw.rot = identity_quat; start_abc.rot = identity_quat; end_abc.rot = identity_quat; pmLineInit(&line_xyz, start_xyz, end_xyz); pmLineInit(&line_uvw, start_uvw, end_uvw); pmLineInit(&line_abc, start_abc, end_abc); tc.cycle_time = tp->cycleTime; if (!line_xyz.tmag_zero) tc.target = line_xyz.tmag; else if (!line_uvw.tmag_zero) tc.target = line_uvw.tmag; else tc.target = line_abc.tmag; tc.progress = 0.0; tc.reqvel = vel; tc.maxaccel = acc; tc.feed_override = 0.0; tc.maxvel = ini_maxvel; tc.id = tp->nextId; tc.active = 0; tc.coords.line.xyz = line_xyz; tc.coords.line.uvw = line_uvw; tc.coords.line.abc = line_abc; tc.motion_type = TC_LINEAR; tc.canon_motion_type = type; tc.blend_with_next = tp->termCond == TC_TERM_COND_BLEND; tc.tolerance = tp->tolerance; tc.synchronized = tp->synchronized; tc.velocity_mode = tp->velocity_mode; tc.uu_per_rev = tp->uu_per_rev; tc.enables = enables; if (tcqPut(&tp->queue, tc) == -1) { rtapi_print_msg(RTAPI_MSG_ERR, "tcqPut failed.\n"); return -1; } tp->goalPos = end; // remember the end of this move, as it's // the start of the next one. tp->done = 0; tp->depth = tcqLen(&tp->queue); tp->nextId++; return 0;}// likewise, this adds a circular (circle, arc, helix) move from// the end of the last move to this new position. end is the// xyzabc of the destination, center/normal/turn specify the arc// in a way that makes sense to pmCircleInit (we don't care about// the details here.) Note that degenerate arcs/circles are not// allowed; we are guaranteed to have a move in xyz so target is// always the circle/arc/helical length.int tpAddCircle(TP_STRUCT * tp, EmcPose end, PmCartesian center, PmCartesian normal, int turn, int type, double vel, double ini_maxvel, double acc, unsigned char enables){ TC_STRUCT tc; PmCircle circle; PmLine line_uvw, line_abc; PmPose start_xyz, end_xyz; PmPose start_uvw, end_uvw; PmPose start_abc, end_abc; double helix_z_component; // z of the helix's cylindrical coord system double helix_length; PmQuaternion identity_quat = { 1.0, 0.0, 0.0, 0.0 }; if (!tp || tp->aborting) return -1; start_xyz.tran = tp->goalPos.tran; end_xyz.tran = end.tran; start_abc.tran.x = tp->goalPos.a; start_abc.tran.y = tp->goalPos.b; start_abc.tran.z = tp->goalPos.c; end_abc.tran.x = end.a; end_abc.tran.y = end.b; end_abc.tran.z = end.c; start_uvw.tran.x = tp->goalPos.u; start_uvw.tran.y = tp->goalPos.v; start_uvw.tran.z = tp->goalPos.w; end_uvw.tran.x = end.u; end_uvw.tran.y = end.v; end_uvw.tran.z = end.w; start_xyz.rot = identity_quat; end_xyz.rot = identity_quat; start_uvw.rot = identity_quat; end_uvw.rot = identity_quat; start_abc.rot = identity_quat; end_abc.rot = identity_quat; pmCircleInit(&circle, start_xyz, end_xyz, center, normal, turn); pmLineInit(&line_uvw, start_uvw, end_uvw); pmLineInit(&line_abc, start_abc, end_abc); // find helix length pmCartMag(circle.rHelix, &helix_z_component); helix_length = pmSqrt(pmSq(circle.angle * circle.radius) + pmSq(helix_z_component)); tc.cycle_time = tp->cycleTime; tc.target = helix_length; tc.progress = 0.0; tc.reqvel = vel; tc.maxaccel = acc; tc.feed_override = 0.0; tc.maxvel = ini_maxvel; tc.id = tp->nextId; tc.active = 0; tc.coords.circle.xyz = circle; tc.coords.circle.uvw = line_uvw; tc.coords.circle.abc = line_abc; tc.motion_type = TC_CIRCULAR; tc.canon_motion_type = type; tc.blend_with_next = tp->termCond == TC_TERM_COND_BLEND; tc.tolerance = tp->tolerance; tc.synchronized = tp->synchronized; tc.velocity_mode = tp->velocity_mode; tc.uu_per_rev = tp->uu_per_rev; tc.enables = enables; if (tcqPut(&tp->queue, tc) == -1) { return -1; } tp->goalPos = end; tp->done = 0; tp->depth = tcqLen(&tp->queue); tp->nextId++; return 0;}void tcRunCycle(TC_STRUCT *tc, double *v, int *on_final_decel) { double discr, maxnewvel, newvel, newaccel=0; if(!tc->blending) tc->vel_at_blend_start = tc->currentvel; discr = 0.5 * tc->cycle_time * tc->currentvel - (tc->target - tc->progress); if(discr > 0.0) { // should never happen: means we've overshot the target newvel = maxnewvel = 0.0; } else { discr = 0.25 * pmSq(tc->cycle_time) - 2.0 / tc->maxaccel * discr; newvel = maxnewvel = -0.5 * tc->maxaccel * tc->cycle_time + tc->maxaccel * pmSqrt(discr); } if(newvel <= 0.0) { // also should never happen - if we already finished this tc, it was // caught above newvel = newaccel = 0.0; tc->progress = tc->target; } else { // constrain velocity if(newvel > tc->reqvel * tc->feed_override) newvel = tc->reqvel * tc->feed_override; if(newvel > tc->maxvel) newvel = tc->maxvel; // get resulting acceleration newaccel = (newvel - tc->currentvel) / tc->cycle_time; // constrain acceleration and get resulting velocity if(newaccel > 0.0 && newaccel > tc->maxaccel) { newaccel = tc->maxaccel; newvel = tc->currentvel + newaccel * tc->cycle_time; } if(newaccel < 0.0 && newaccel < -tc->maxaccel) { newaccel = -tc->maxaccel; newvel = tc->currentvel + newaccel * tc->cycle_time; } // update position in this tc tc->progress += (newvel + tc->currentvel) * 0.5 * tc->cycle_time; } tc->currentvel = newvel; if(v) *v = newvel; if(on_final_decel) *on_final_decel = fabs(maxnewvel - newvel) < 0.001;}// This is the brains of the operation. It's called every TRAJ period// and is expected to set tp->currentPos to the new machine position.// Lots of other tp fields (depth, done, etc) have to be twiddled to// communicate the status; I think those are spelled out here correctly// and I can't clean it up without breaking the API that the TP presents// to motion. It's not THAT bad and in the interest of not touching// stuff outside this directory, I'm going to leave it for now.int tpRunCycle(TP_STRUCT * tp, long period){ // vel = (new position - old position) / cycle time // (two position points required) // // acc = (new vel - old vel) / cycle time // (three position points required) TC_STRUCT *tc, *nexttc; double primary_vel; int on_final_decel; EmcPose primary_before, primary_after; EmcPose secondary_before, secondary_after; EmcPose primary_displacement, secondary_displacement; static double spindleoffset; static int waiting = 0; double save_vel; emcmotStatus->tcqlen = tcqLen(&tp->queue); tc = tcqItem(&tp->queue, 0, period); if(!tc) { // this means the motion queue is empty. This can represent // the end of the program OR QUEUE STARVATION. In either case, // I want to stop. Some may not agree that's what it should do. tcqInit(&tp->queue); tp->goalPos = tp->currentPos; tp->done = 1; tp->depth = tp->activeDepth = 0; tp->aborting = 0; tp->execId = 0; tp->motionType = 0; tpResume(tp); // when not executing a move, use the current enable flags emcmotStatus->enables_queued = emcmotStatus->enables_new; return 0; } if (tc->target == tc->progress) { // if we're synced, and this move is ending, save the // spindle position so the next synced move can be in // the right place. if(tc->synchronized) spindleoffset += tc->target/tc->uu_per_rev; else spindleoffset = 0.0; // done with this move tcqRemove(&tp->queue, 1); // so get next move tc = tcqItem(&tp->queue, 0, period); if(!tc) return 0; } if (tc->motion_type == TC_RIGIDTAP) { switch (tc->coords.rigidtap.state) { case TAPPING: if (tc->progress >= tc->coords.rigidtap.reversal_target) { // command reversal emcmotStatus->spindle.speed *= -1; tc->coords.rigidtap.state = REVERSING; } break; case REVERSING: if (tc->reqvel == 0.0) { PmPose start, end; PmLine *aux = &tc->coords.rigidtap.aux_xyz; // we've stopped, so set a new target at the original position tc->coords.rigidtap.spindlerevs_at_reversal = emcmotStatus->spindleRevs; pmLinePoint(&tc->coords.rigidtap.xyz, tc->progress, &start); end = tc->coords.rigidtap.xyz.start; pmLineInit(aux, start, end); tc->coords.rigidtap.reversal_target = aux->tmag; tc->target = aux->tmag + 10. * tc->uu_per_rev; tc->progress = 0.0; tc->coords.rigidtap.state = RETRACTION; } break; case RETRACTION: if (tc->progress >= tc->coords.rigidtap.reversal_target) { emcmotStatus->spindle.speed *= -1; tc->coords.rigidtap.state = FINAL_REVERSAL; } break; case FINAL_REVERSAL: if (tc->reqvel == 0.0) { PmPose start, end; PmLine *aux = &tc->coords.rigidtap.aux_xyz; pmLinePoint(aux, tc->progress, &start); end = tc->coords.rigidtap.xyz.start; pmLineInit(aux, start, end); tc->target = aux->tmag; tc->progress = 0.0; tc->synchronized = 0; tc->reqvel = tc->maxvel; tc->coords.rigidtap.state = FINAL_PLACEMENT; } break; case FINAL_PLACEMENT: // this is a regular move now, it'll stop at target above. break; } } // this is no longer the segment we were waiting for if(waiting && waiting != tc->id) waiting = 0; if(waiting) { if(emcmotStatus->spindle_index_enable) { /* haven't passed index yet */ return 0; } else { /* passed index, start the move */ emcmotStatus->spindleSync = 1; waiting=0; } } if(!tc->synchronized) emcmotStatus->spindleSync = 0; // now we have the active tc. get the upcoming one, if there is one. // it's not an error if there isn't another one - we just don't // do blending. This happens in MDI for instance. if(!emcmotDebug->stepping && tc->blend_with_next) nexttc = tcqItem(&tp->queue, 1, period); else nexttc = NULL; if(!tc->synchronized && nexttc && nexttc->synchronized && !nexttc->velocity_mode) { // we'll have to wait for spindle sync; might as well // stop at the right place (don't blend) tc->blend_with_next = 0; nexttc = NULL;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?