/* Do the averaving */ int mu_stats( vect_n * torques, vect_n * positions ) { int n; int j; vect_n * torque_vars; vect_n * position_vars; int dof; dof = len_vn(torques); torque_vars = new_vn(dof); position_vars = new_vn(dof); /* Zero the values */ fill_vn(torques,0.0); fill_vn(positions,0.0); fill_vn(torque_vars,0.0); fill_vn(position_vars,0.0); /* Calculate the average */ for (n = 0; n < NUM_POINTS; n++) { for (j=0; j<dof; j++) { torques->q[j] += mu_jts[j][n]; positions->q[j] += mu_jps[j][n]; } } set_vn(torques, scale_vn( 1.0/NUM_POINTS, torques )); set_vn(positions, scale_vn( 1.0/NUM_POINTS, positions )); /* Calculate the variance */ for (n = 0; n < NUM_POINTS; n++) { for (j=0; j<dof; j++) { torque_vars->q[j] += (mu_jts[j][n] - torques->q[j]) * (mu_jts[j][n] - torques->q[j]); position_vars->q[j] += (mu_jps[j][n] - positions->q[j]) * (mu_jps[j][n] - positions->q[j]); } } set_vn(torque_vars, scale_vn( 1.0/NUM_POINTS, torque_vars )); set_vn(position_vars, scale_vn( 1.0/NUM_POINTS, position_vars )); /* Print positions */ mvprintw(12,0, " Positions:"); mvprintw(13,0, " (std-dev):"); mvprintw(14,0, " Torques:"); mvprintw(15,0, " (std-dev):"); for (j=0; j<dof; j++) { mvprintw(12, 13 + 9*j, "% 08.5f ",positions->q[j]); mvprintw(13, 13 + 9*j, "% 08.5f ",sqrt(position_vars->q[j])); mvprintw(14, 13 + 9*j, "% 08.5f ",torques->q[j]); mvprintw(15, 13 + 9*j, "% 08.5f ",sqrt(torque_vars->q[j])); } destroy_vn(&torque_vars); destroy_vn(&position_vars); return 0; }
struct fuse * fuse_new(struct fuse_chan *fc, unused struct fuse_args *args, const struct fuse_operations *ops, unused size_t size, unused void *userdata) { struct fuse *fuse; struct fuse_vnode *root; if ((fuse = calloc(1, sizeof(*fuse))) == NULL) return (NULL); /* copy fuse ops to their own structure */ memcpy(&fuse->op, ops, sizeof(fuse->op)); fuse->fc = fc; fuse->max_ino = FUSE_ROOT_INO; fuse->se.args = fuse; fuse->private_data = userdata; if ((root = alloc_vn(fuse, "/", FUSE_ROOT_INO, 0)) == NULL) { free(fuse); return (NULL); } tree_init(&fuse->vnode_tree); tree_init(&fuse->name_tree); if (!set_vn(fuse, root)) { free(fuse); return (NULL); } return (fuse); }
/** Implements the reset interface for bttrajectory_interface_struct. See bttrajectory_interface_struct \internal chk'd TH 051103 */ vect_n* bttrajectory_interface_reset_vt(struct bttrajectory_interface_struct *btt) { double ret; int cnt; via_trj_array* vt; vt = (via_trj_array*)btt->dat; #ifdef BT_NULL_PTR_GUARD if(!btptr_ok(vt,"bttrajectory_interface_reset_vt")) return btt->qref; #endif if (numrows_vr(vt->vr) <= 0) return NULL; /* Get rid of the old pavn */ destroy_pavn(&vt->pavn); vt->pavn = vr2pararray(vt->vr, vt->acc); set_vn(btt->qref, reset_pavn(vt->pavn)); /* for (cnt = 0;cnt<vt->elements;cnt++) { setval_vn(btt->qref,cnt,start_via_trj(&(vt->trj[cnt]),cnt)); }*/ return btt->qref; }
/** Copy the point at the present idx to dest. \internal chk'd TH 051103 */ void get_current_point_vta(via_trj_array* vt, vect_n *dest) { vectray *vr; if (vt == NULL) return; vr = vt->vr; set_vn(dest,edit_vr(vr)); }
/** See TH#7 pp 15 for a sketch */ vect_n* calc_cseg(cseg *csg,btreal s) //Given an arclength find point { btreal R; // s = rho*omega csg->omega = s/csg->rho; R = pi - (csg->beta + csg->omega); csg->w = csg->rho*sin(csg->omega)/sin(R); set_vn(csg->last_result,add_vn(csg->C,scale_vn(csg->rho,unit_vn(sub_vn(add_vn(csg->x0,scale_vn(csg->w,csg->A)),csg->C))))); //printf("omega:%f R:%f w:%f\n",csg->omega,R,csg->w); return csg->last_result; }
vect_n* eval_vta(via_trj_array* vt,double dt,vect_n* qref) { double ret; int cnt; if (vt == NULL) return qref; /* for (cnt = 0;cnt<vt->elements;cnt++) { setval_vn(qref,cnt,eval_via_trj(&(vt->trj[cnt]),dt)); }*/ set_vn(qref,eval_pavn(vt->pavn,dt)); return qref; }
/** Implements the eval interface for bttrajectory_interface_struct. See bttrajectory_interface_struct \return NULL if trajectory has no points. \internal chk'd TH 051103 */ vect_n* bttrajectory_interface_eval_vt(struct bttrajectory_interface_struct *btt) { double ret; int cnt; via_trj_array* vt; vt = (via_trj_array*)btt->dat; #ifdef BT_NULL_PTR_GUARD if(!btptr_ok(vt,"bttrajectory_interface_eval_vt")) return btt->qref; #endif /* for (cnt = 0;cnt<vt->elements;cnt++) { setval_vn(btt->qref,cnt,eval_via_trj(&(vt->trj[cnt]),*(btt->dt))); }*/ set_vn(btt->qref,eval_pavn(vt->pavn,*(btt->dt))); return btt->qref; }
vect_n* reset_vta(via_trj_array* vt,double dt,vect_n* qref) { double ret; int cnt; if (vt == NULL) return qref; destroy_pavn(&vt->pavn); vt->pavn = vr2pararray(vt->vr,vt->acc); /* for (cnt = 0;cnt<vt->elements;cnt++) { setval_vn(qref,cnt,start_via_trj(&(vt->trj[cnt]),cnt)); }*/ set_vn(qref,reset_pavn(vt->pavn)); return qref; }
/* The registerWAMcallback() function registers this special function to be * called from the WAMControlThread() after the positions have been received * from the WAM (and after all the kinematics are calculated) but before torques * are sent to the WAM. * NOTE 1: Since this function becomes part of the control loop, it must execute * quickly to support the strict realtime periodic scheduler requirements. * NOTE 2: For proper operation, you must avoid using any system calls that * cause this thread to drop out of realtime mode. Avoid syslog, printf, and * most other forms of I/O. */ int WAMcallback(wam_struct *w) { /* Declare two timing variables */ RTIME start, end; /* Set a damping factor. * If you make this positive, you have a poor-man's (unstable) friction * compensation algorithm. Have fun, but be careful! */ btreal Kscale = -30.0; /* Get the time in nanoseconds */ start = btrt_get_time(); /* Differentiate the Cartesian end position to get velocity and acceleration */ eval_state_btg(&pstate, w->Cpos); /* Apply velocity damping. * Here is what happens with our math library: * scale_vn() Scale a vector: pstate.vel->ret = Kscale * pstate.vel * add_vn() Add two vectors: wam->Cforce->ret = wam->Cforce + pstate.vel->ret * set_vn() Copy a vector: wam->Cforce = wam->Cforce->ret */ set_vn((vect_n*)wam->Cforce, add_vn((vect_n*)wam->Cforce, scale_vn(Kscale, (vect_n*)pstate.vel))); /* Apply the calculated force vector to the robot */ apply_tool_force_bot(&(w->robot), w->Cpoint, w->Cforce, w->Ctrq); /* Get the time in nanoseconds */ end = btrt_get_time(); /* NOTE: Be careful what you do with RTIMEs. They exhibit odd behavior unless * you stick to simple addition and subtraction. And if you print them, * use %lld (they are 64-bits). */ callbackTime = end - start; return 0; }
/** Convert a vectray of time/points to a piecewise parabolic function. Time in the first value; Time values must be monotonically increasing. Results are otherwize undefined. */ pararray_vn* vr2pararray(vectray* vr,btreal acceleration) { pararray_vn* pavn; parabolic pa; int cnt,idx; btreal t1,t2,t3,x1,x2,x3; btreal v1,v2,v3,tacc,t1p2,t2p3,tmax; btreal tf,a,s0,sf; btreal sv0,svf,sa0,saf,sa0_last,v1_last,saf_last; btreal s0_prev,tf_prev; btreal acc,min_acc; btreal dt,dx,t_last; vect_n *p0, *pf; //store first and last points of vr p0 = new_vn(numelements_vr(vr)); // numelements_vr() returns vr->n (columns) pf = new_vn(numelements_vr(vr)); set_vn(p0, idx_vr(vr, 0)); set_vn(pf, idx_vr(vr, numrows_vr(vr)-1)); //new pararray of size (Viapoints - 1)*2 + 1 pavn = new_pavn(2*numrows_vr(vr) -1 +5, numelements_vr(vr)-1); tmax = 0; // For each column of pavn for (cnt = 0; cnt < pavn->elements; cnt ++) { acc = fabs(acceleration); /* First acceleration segment calcs*/ t1 = getval_vn(idx_vr(vr,0),0); t2 = getval_vn(idx_vr(vr,1),0); x1 = getval_vn(idx_vr(vr,0),cnt+1); x2 = getval_vn(idx_vr(vr,1),cnt+1); dt = t2-t1; dx = x2-x1; v1 = 0.0; if(dt == 0.0) syslog(LOG_ERR, "vr2pararray(): about to divide by dt = 0.0"); v2 = dx/dt; min_acc = 8.0 * fabs(dx) / (3.0 * dt*dt); if(isnan(min_acc)) syslog(LOG_ERR, "vr2pararray(): min_acc is NaN (bad)"); //Make sure initial acceleration is fast enough if (acc < min_acc) { //syslog(LOG_ERR,"vr2pararray: Boosting initial acc (%f) to %f", acc, min_acc); acc = min_acc; } tacc = dt - sqrt(dt*dt - 2*fabs(dx)/acc); saf = x1 + 0.5*acc*tacc*tacc*Sgn(dx); //Final x v2 = (x2-saf)/(dt-tacc); //final velocity if(isnan(v2)) syslog(LOG_ERR, "vr2pararray: v2 is NaN (bad)"); sa0 = x1; tf_prev = s0sfspftf_pb(&pa, 0.0, sa0, saf, v2, tacc); //acc seg starting at time 0.0 add_bseg_pa(pavn->pa[cnt],&pa); setval_vn(idx_vr(vr,0),cnt+1,x2-dt*v2); idx = numrows_vr(vr)-1; /* Last velocity and acceleration segment calcs */ acc = fabs(acceleration); t1 = getval_vn(idx_vr(vr,idx-1),0); t2 = getval_vn(idx_vr(vr,idx),0); x1 = getval_vn(idx_vr(vr,idx-1),cnt+1); x2 = getval_vn(idx_vr(vr,idx),cnt+1); dt = t2-t1; dx = x2-x1; v1 = dx/dt; v2 = 0.0; min_acc = 8.0*fabs(dx)/(3.0*dt*dt); //Make sure final acceleration is fast enough if (acc < min_acc) { acc = min_acc; //syslog(LOG_ERR,"vr2pararray: Boosting final acc to %f",acc); } tacc = dt - sqrt(dt*dt - 2*fabs(dx)/acc); sa0_last = x2 - 0.5*acc*tacc*tacc*Sgn(dx); //Final x v1_last = (sa0_last-x1)/(dt-tacc); //final velocity saf_last = x2; t_last = tacc; setval_vn(idx_vr(vr,idx),cnt+1,x1+dt*v1_last); /*Internal (remaining) segments calcs*/ acc = fabs(acceleration); for(idx = 1; idx < numrows_vr(vr)-1; idx++) { /* Extract info */ t1 = getval_vn(idx_vr(vr,idx-1),0); t2 = getval_vn(idx_vr(vr,idx),0); t3 = getval_vn(idx_vr(vr,idx+1),0); x1 = getval_vn(idx_vr(vr,idx-1),cnt+1); x2 = getval_vn(idx_vr(vr,idx),cnt+1); x3 = getval_vn(idx_vr(vr,idx+1),cnt+1); /* Calc some useful values */ //if ((t2-t1) <= 0.0 || (t3-t2) <= 0.0) //syslog(LOG_ERR,"vr2pararray: Equal time points and unsortet times are not supported.",tacc,idx); v1 = (x2-x1)/(t2-t1); v2 = (x3-x2)/(t3-t2); t1p2 = (t1 + t2)/2; t2p3 = (t2 + t3)/2; /* Shrink acceleration if necessary */ tmax = min_bt(2*(t2-t1p2),2*(t2p3-t2)); //vf = v0 + at => t = (vf-v0)/a tacc = fabs(v2-v1)/acc; if (tmax < tacc) { //Need to increase acceleration to make corner tacc = tmax; //syslog(LOG_ERR,"vr2pararray: Forcing acc time decrease to %f at point %d.",tacc,idx); } /* Calc : tf_prev & saf carry history from prev loops */ sa0 = x2 - v1*(tacc/2); //acc start pos tf_prev = s0sfspftf_pb(&pa,tf_prev,saf,sa0,v1,t2-tacc/2); //velocity seg add_bseg_pa(pavn->pa[cnt],&pa); saf = x2 + v2*(tacc/2); //acc end pos tf_prev = s0sfspftf_pb(&pa,tf_prev,sa0,saf,v2,t2+tacc/2); //acc seg add_bseg_pa(pavn->pa[cnt],&pa); //usleep(1); } v2 = 0.0; tf_prev = s0sfspftf_pb(&pa,tf_prev,saf,sa0_last,v1_last,t3-t_last); //last velocity seg add_bseg_pa(pavn->pa[cnt],&pa); tf_prev = s0sfspftf_pb(&pa,tf_prev,sa0_last,saf_last,v2,t3); //acc seg ending at tf add_bseg_pa(pavn->pa[cnt],&pa); } set_vn(idx_vr(vr,0),p0); set_vn(idx_vr(vr,numrows_vr(vr)-1),pf); return pavn; }
/** Handles inner (theta) angles of pi. Explodes on angles of 0.0 */ btreal init_cseg(cseg *csg,btreal rho, vect_n *a, vect_n *b, vect_n *c) { int vsz; local_vn(tmpa,10); local_vn(tmpb,10); btreal div,churl; vsz = len_vn(a); init_vn(tmpa,vsz); init_vn(tmpb,vsz); csg->a = new_vn(vsz); csg->b = new_vn(vsz); csg->c = new_vn(vsz); csg->C = new_vn(vsz); csg->W = new_vn(vsz); csg->A = new_vn(vsz); csg->x0 = new_vn(vsz); csg->x0p = new_vn(vsz); csg->xf = new_vn(vsz); csg->xfp = new_vn(vsz); csg->last_result = new_vn(vsz); csg->rho = rho; set_vn(csg->a,a); set_vn(csg->b,b); set_vn(csg->c,c); set_vn(tmpa,unit_vn(sub_vn(a,b))); set_vn(csg->x0p,neg_vn(tmpa)); set_vn(tmpb,unit_vn(sub_vn(c,b))); set_vn(csg->xfp,tmpb); printf("\n"); print_vn(tmpa);printf("\n"); print_vn(tmpb);printf("\n"); csg->theta = angle_vn(tmpa,tmpb)/2; //Half the angle between the two line segments csg->phi = pi/2.0 - csg->theta; //The other angle in the triangle (TH #7, pp12) div = sin(csg->theta)/cos(csg->theta); csg->ptlen = csg->rho/div; csg->hlen = sqrt(csg->rho*csg->rho + csg->ptlen*csg->ptlen); set_vn(csg->x0,add_vn(csg->b,scale_vn(csg->ptlen,tmpa))); set_vn(csg->xf,add_vn(csg->b,scale_vn(csg->ptlen,tmpb))); set_vn(csg->C,add_vn(csg->b,scale_vn(csg->hlen,unit_vn(add_vn(scale_vn(0.5,sub_vn(tmpb,tmpa)),tmpa))))); set_vn(csg->A,unit_vn(sub_vn(csg->xf,csg->x0))); csg->beta = pi/2 - angle_vn(csg->x0p,csg->A); return csg->phi*csg->rho*2.0; }
int do_mode_mu() { int err; /* Generic error variable for function calls */ int busCount; /* Number of WAMs defined in the configuration file */ int j; /* Stuff that's filled in once */ vect_n ** poses; int num_poses; int pose; vect_n * angle_diff; /* Stuff that's used once for each pose in measure mode */ vect_n * torques_top; vect_n * positions_top; vect_n * torques_bottom; vect_n * positions_bottom; /* For storing the results from measure mode, one vector per pose */ vect_n ** torques; vect_n ** positions; /* For storing the results from computation mode, one vector per joint */ vect_3 ** mus; /* Make a list of phases for each pose*/ enum { MU_P_START, MU_P_TO_TOP, MU_P_FROM_TOP, MU_P_MEAS_TOP, MU_P_TO_BOT, MU_P_FROM_BOT, MU_P_MEAS_BOT, MU_P_DONE } phase; char * phasenm[] = { "START", "TO_TOP", "FROM_TOP", "MEAS_TOP", "TO_BOT", "FROM_BOT", "MEAS_BOT", "DONE" }; clear(); mvprintw(0,0,"Starting Gravity Calibration Mode"); /* Ensure the WAM is set up, power cycled, and in the home position */ mvprintw(2,0,"To begin the calibration, follow the following steps:"); mvprintw(3,0," a) Ensure that all WAM power and signal cables are securely fastened."); mvprintw(4,0," b) Ensure that the WAM is powered on (receiving power)."); mvprintw(5,0," c) Ensure that all E-STOPs are released."); mvprintw(6,0," d) Place the WAM in Shift+Idle mode."); mvprintw(7,0," e) Carefully ensure that the WAM is in its home (folded) position."); mvprintw(8,0,"Press [Enter] to continue."); refresh(); while (btkey_get()!=BTKEY_ENTER) usleep(10000); /* Initialize system buses */ err = ReadSystemFromConfig("../../wam.conf", &busCount); if(err) return -1; /* Spin off the CAN thread */ startDone = 0; btrt_thread_create(&can_thd,"can",45,(void*)can_thd_function,NULL); while (!startDone) usleep(10000); /* Allocate the global variables */ mu_jts = (double **) malloc( wam->dof * sizeof(double *) ); mu_jps = (double **) malloc( wam->dof * sizeof(double *) ); for (j=0; j<wam->dof; j++) { mu_jts[j] = (double *) malloc( NUM_POINTS * sizeof(double) ); mu_jps[j] = (double *) malloc( NUM_POINTS * sizeof(double) ); } /* Spin off the WAM thread */ mu_n = NUM_POINTS; wam_thd.period = 0.002; /* Control loop period in seconds */ registerWAMcallback(wam, mu_callback); btrt_thread_create(&wam_thd,"ctrl",90,(void*)WAMControlThread,(void*)wam); /* Grab poses from the configuration file */ do { btparser parser; char key[256]; err = btParseFile(&parser,"cal.conf"); if (err) { syslog(LOG_ERR,"Calibration configuration file cal.conf not found."); printf("Calibration configuration file cal.conf not found.\n"); break; } sprintf(key,"calibration-poses-wam%d.poseCount",wam->dof); err = btParseGetVal(&parser,INT, key, &num_poses); if (err || num_poses < 4) { syslog(LOG_ERR,"Configuration group calibration-poses-wam%d not found,",wam->dof); syslog(LOG_ERR,"numPoses not present, or numPoses not at least 4."); printf("Configuration group calibration-poses-wam%d not found,\n",wam->dof); printf("numPoses not present, or numPoses not at least 4."); btParseClose(&parser); break; } poses = (vect_n **) btmalloc( num_poses * sizeof(vect_n *) ); for (pose=0; pose<num_poses; pose++) { poses[pose] = new_vn(wam->dof); sprintf(key, "calibration-poses-wam%d.pose[%d]", wam->dof, pose); err = btParseGetVal(&parser, VECTOR, key, (void*)poses[pose]); if (err) { syslog(LOG_ERR,"Not enough poses found! (%d expected, found only %d)", num_poses, pose); printf("Not enough poses found! (%d expected, found only %d)\n", num_poses, pose); break; } } btParseClose(&parser); } while (0); if (err) { /* Free the variables */ for (j=0; j<wam->dof; j++) { free(mu_jts[j]); free(mu_jps[j]); } free(mu_jts); free(mu_jps); /* Stop threads ... */ wam_thd.done = 1; usleep(10000); can_thd.done = 1; usleep(50000); /* End ncurses */ endwin(); return 0; } angle_diff = new_vn(wam->dof); fill_vn(angle_diff,ANGLE_DIFF); torques_top = new_vn(wam->dof); positions_top = new_vn(wam->dof); torques_bottom = new_vn(wam->dof); positions_bottom = new_vn(wam->dof); torques = (vect_n **) malloc( num_poses * sizeof(vect_n *) ); positions = (vect_n **) malloc( num_poses * sizeof(vect_n *) ); for (pose=0; pose<num_poses; pose++) { torques[pose] = new_vn(wam->dof); positions[pose] = new_vn(wam->dof); } mus = (vect_3 **) malloc( wam->dof * sizeof(vect_3 *) ); for (j=0; j<wam->dof; j++) mus[j] = new_v3(); /* Allow the user to shift-activate */ mvprintw(10,0,"IMPORTANT: Once gravity compensation begins, the WAM will begin"); mvprintw(11,0,"to move to a set of %d predefined poses (defined in cal.conf).",num_poses); mvprintw(13,0,"DO NOT TOUCH the WAM during the measurement process, or the"); mvprintw(14,0,"calibration computations will be sigificantly wrong, and"); mvprintw(15,0,"any subsequent gravity compensation will fail spectacularly!"); mvprintw(17,0,"Place the WAM in Shift+Activate mode,"); mvprintw(18,0,"and press [Enter] to start."); refresh(); while (btkey_get()!=BTKEY_ENTER) usleep(10000); /* Start the GUI! */ pose = 0; phase = MU_P_START; clear(); mvprintw(1,0,"Note: Press [Control+C] at any time to cancel the calibration."); mvprintw(2,0,"DO NOT TOUCH the WAM during the calibration process!"); done = 0; signal(SIGINT, sigint); while (!done) { /* Print current state */ mvprintw(0, 0,"Current Pose: %d of %d. ",pose+1,num_poses); mvprintw(0,30,"Current Phase: %s ",phasenm[phase]); /* Print current joint position and torque */ mvprintw(4,0, " Joint:"); mvprintw(5,0, " Position:"); mvprintw(6,0, " Torque:"); for (j=0; j<wam->dof; j++) { mvprintw(4, 13 + 9*j, " Joint %d ",j+1); mvprintw(5, 13 + 9*j, "% 08.5f ",wam->Jpos->q[j]); mvprintw(6, 13 + 9*j, "% 08.4f ",wam->Jtrq->q[j]); } /* Line 9 - Status Updates */ mvprintw(8,0,"Current Status:"); /* Note - lines 12-?? reserved for printing statistics */ mvprintw(11,0,"Recent Statistics:"); refresh(); usleep(5E4); /* Move through the state machine */ switch (phase) { case MU_P_START: mvprintw(9,3,"Moving to above position ... "); MoveSetup(wam, 1.0, 1.0); MoveWAM(wam,add_vn(poses[pose],angle_diff)); phase++; break; case MU_P_TO_TOP: if (!MoveIsDone(wam)) break; mvprintw(9,3,"Moving to position (from above) ... "); MoveSetup(wam, 0.05, 0.05); MoveWAM(wam,poses[pose]); phase++; case MU_P_FROM_TOP: if (!MoveIsDone(wam)) break; mvprintw(9,3,"Starting a measurement ... "); mu_n = 0; phase++; break; case MU_P_MEAS_TOP: if (mu_n < NUM_POINTS) break; mu_stats( torques_top, positions_top ); mvprintw(9,3,"Moving to below position ... "); MoveSetup(wam, 1.0, 1.0); MoveWAM(wam,sub_vn(poses[pose],angle_diff)); phase++; break; case MU_P_TO_BOT: if (!MoveIsDone(wam)) break; mvprintw(9,3,"Moving to position (from below) ... "); MoveSetup(wam, 0.05, 0.05); MoveWAM(wam,poses[pose]); phase++; break; case MU_P_FROM_BOT: if (!MoveIsDone(wam)) break; mvprintw(9,3,"Starting a measurement ... "); mu_n = 0; phase++; break; case MU_P_MEAS_BOT: if (mu_n < NUM_POINTS) break; mu_stats( torques_bottom, positions_bottom ); phase++; break; case MU_P_DONE: /* Get the midpoint position and torque ... */ set_vn(torques[pose],scale_vn(0.5,add_vn(torques_top,torques_bottom))); set_vn(positions[pose],scale_vn(0.5,add_vn(positions_top,positions_bottom))); pose++; phase = MU_P_START; if (pose == num_poses) done = 1; break; } } /* Re-fold, print, and exit */ clear(); mvprintw(0,0,"Moving back to the park location ..."); refresh(); MoveSetup(wam, 1.0, 1.0); MoveWAM(wam,wam->park_location); while (!MoveIsDone(wam)) usleep(10000); mvprintw(1,0,"Shift+Idle, and press [Enter] to continue."); refresh(); while (btkey_get()!=BTKEY_ENTER) usleep(10000); /* Stop threads ... */ wam_thd.done = 1; usleep(10000); can_thd.done = 1; usleep(50000); /* Free unneeded variables */ for (j=0; j<wam->dof; j++) { free(mu_jts[j]); free(mu_jps[j]); } free(mu_jts); free(mu_jps); destroy_vn(&angle_diff); destroy_vn(&torques_top); destroy_vn(&positions_top); destroy_vn(&torques_bottom); destroy_vn(&positions_bottom); /* End ncurses */ endwin(); if (done == 1) { /* Here we have the "Iterative Algorithm" * described in the Chris Dellin document entitled * "Newton-Euler First-Moment Gravity Compensation" */ /* Here we have the matrix composed of L matrices (negative) */ matr_mn * nLL; /* We have a GT matrix and a Y vector for each link */ matr_mn ** GT; vect_n ** Y; /* We have a solution vector P for each link */ vect_n ** P; vect_n * grav_torques; /* Start calculating ... * We have vectors of torque and position * in torques[] and positions[] */ printf("\n"); printf("Calculating ...\n"); /* Make the LL matrix */ nLL = new_mn( 3*num_poses, 3+2*num_poses ); zero_mn(nLL); for (pose=0; pose<num_poses; pose++) { setval_mn(nLL, 3*pose+0, 3+2*pose+0, -1.0 ); setval_mn(nLL, 3*pose+1, 3+2*pose+1, -1.0 ); } /* Make each link's GT matrix */ /* Make each link's Y torque solution matrix */ Y = (vect_n **) btmalloc( wam->dof * sizeof(vect_n *) ); GT = (matr_mn **) btmalloc( wam->dof * sizeof(matr_mn *) ); for (j=0; j<wam->dof; j++) { Y[j] = new_vn( 3*num_poses ); GT[j] = new_mn( 3*num_poses, 3+2*num_poses ); zero_mn(GT[j]); } grav_torques = new_vn(wam->dof); for (pose=0; pose<num_poses; pose++) { /* Put the robot in the pose (by position) */ set_vn(wam->robot.q,positions[pose]); eval_fk_bot(&wam->robot); get_gravity_torques(&wam->robot,grav_torques); for (j=0; j<wam->dof; j++) { /* GT: Gravity skew matrix */ setval_mn(GT[j], 3*pose+0, 1, -getval_v3(wam->robot.links[j].g,2) ); setval_mn(GT[j], 3*pose+0, 2, getval_v3(wam->robot.links[j].g,1) ); setval_mn(GT[j], 3*pose+1, 0, getval_v3(wam->robot.links[j].g,2) ); setval_mn(GT[j], 3*pose+1, 2, -getval_v3(wam->robot.links[j].g,0) ); setval_mn(GT[j], 3*pose+2, 0, -getval_v3(wam->robot.links[j].g,1) ); setval_mn(GT[j], 3*pose+2, 1, getval_v3(wam->robot.links[j].g,0) ); /* GT: -R*L */ setval_mn(GT[j], 3*pose+0, 3+2*pose+0, -getval_mh(wam->robot.links[j].trans,0,0) ); setval_mn(GT[j], 3*pose+0, 3+2*pose+1, -getval_mh(wam->robot.links[j].trans,1,0) ); setval_mn(GT[j], 3*pose+1, 3+2*pose+0, -getval_mh(wam->robot.links[j].trans,0,1) ); setval_mn(GT[j], 3*pose+1, 3+2*pose+1, -getval_mh(wam->robot.links[j].trans,1,1) ); setval_mn(GT[j], 3*pose+2, 3+2*pose+0, -getval_mh(wam->robot.links[j].trans,0,2) ); setval_mn(GT[j], 3*pose+2, 3+2*pose+1, -getval_mh(wam->robot.links[j].trans,1,2) ); /* Y */ setval_vn(Y[j], 3*pose+0, getval_vn(torques[pose],j) * getval_mh(wam->robot.links[j].trans,2,0) ); setval_vn(Y[j], 3*pose+1, getval_vn(torques[pose],j) * getval_mh(wam->robot.links[j].trans,2,1) ); setval_vn(Y[j], 3*pose+2, getval_vn(torques[pose],j) * getval_mh(wam->robot.links[j].trans,2,2) ); if (j < wam->dof-1) setval_vn(Y[j], 3*pose+2, getval_vn(Y[j],3*pose+2) - getval_vn(torques[pose],j+1) ); } } destroy_vn(&grav_torques); /* Make a space for each link's P solution vector */ P = (vect_n **) btmalloc( wam->dof * sizeof(vect_n *) ); for (j=0; j<wam->dof; j++) P[j] = new_vn( 3+2*num_poses ); /* Do the regression for each link */ { int i; matr_mn * m2x2; matr_mn * m2x3; vect_n * Yi; vect_n * index; vect_n * col; m2x2 = new_mn( 3+2*num_poses, 3+2*num_poses ); m2x3 = new_mn( 3+2*num_poses, 3*num_poses ); Yi = new_vn( 3*num_poses ); index = new_vn( 3+2*num_poses ); col = new_vn( 3+2*num_poses ); for (j=wam->dof-1; j>=0; j--) { mul_mn( m2x2, T_mn(GT[j]), GT[j] ); for (i=0; i<3+2*num_poses; i++) setval_mn(m2x2,i,i, getval_mn(m2x2,i,i) + CALC_LAMBDA ); mul_mn( m2x3, inv_mn(m2x2,index,col), T_mn(GT[j]) ); if (j < wam->dof-1) matXvec_mn(nLL,P[j+1],Yi); else fill_vn(Yi,0.0); set_vn(Yi, add_vn(Yi,Y[j]) ); matXvec_mn( m2x3, Yi, P[j] ); } destroy_mn(&m2x2); destroy_mn(&m2x3); destroy_vn(&Yi); destroy_vn(&index); destroy_vn(&col); /* Copy the results */ for (j=0; j<wam->dof; j++) { setval_v3(mus[j],0, getval_vn(P[j],0) ); setval_v3(mus[j],1, getval_vn(P[j],1) ); setval_v3(mus[j],2, getval_vn(P[j],2) ); } /* Clean up */ destroy_mn(&nLL); for (j=0; j<wam->dof; j++) { destroy_mn(>[j]); destroy_vn(&Y[j]); destroy_vn(&P[j]); } btfree((void **)>); btfree((void **)&Y); btfree((void **)&P); } /* Print results */ printf("\n"); printf("Gravity calibration ended.\n"); printf("\n"); printf("Copy the following lines into your wam.conf file, in the %s{} group.\n",wam->name); printf("It is usually placed above the safety{} group.\n"); printf("--------\n"); printf(" # Calibrated gravity vectors\n"); printf(" calibrated-gravity{\n"); for (j=0; j<wam->dof; j++) { printf(" mu%d = < % .6f, % .6f, % .6f >\n", j+1, getval_v3(mus[j],0), getval_v3(mus[j],1), getval_v3(mus[j],2)); } printf(" }\n"); printf("--------\n"); { FILE * logfile; logfile = fopen("cal-gravity.log","w"); if (logfile) { fprintf(logfile," # Calibrated gravity vectors\n"); fprintf(logfile," calibrated-gravity{\n"); for (j=0; j<wam->dof; j++) fprintf(logfile," mu%d = < % .6f, % .6f, % .6f >\n", j+1, getval_v3(mus[j],0), getval_v3(mus[j],1), getval_v3(mus[j],2)); fprintf(logfile," }\n"); fclose(logfile); printf("This text has been saved to cal-gravity.log.\n"); } else { syslog(LOG_ERR,"Could not write to cal-gravity.log."); printf("Error: Could not write to cal-gravity.log.\n"); } } printf("\n"); } /* Free the variables */ for (pose=0; pose<num_poses; pose++) { destroy_vn(&torques[pose]); destroy_vn(&positions[pose]); } free(torques); free(positions); for (j=0; j<wam->dof; j++) destroy_vn((vect_n **)&mus[j]); free(mus); return 0; }
int do_mode_zero() { int err; /* Generic error variable for function calls */ int busCount; /* Number of WAMs defined in the configuration file */ int i; /* For iterating through the pucks */ /* GUI stuff */ enum { MODE_TOZERO, MODE_CANCEL, MODE_PRINTVALS, MODE_JSELECT, MODE_EDIT } mode; int joint; int decplace; vect_n * jangle; char newhome[80]; char zeromag[80]; clear(); mvprintw(0,0,"Starting Zero Calibration Mode"); /* Ensure the WAM is set up, power cycled, and in the home position */ mvprintw(2,0,"To begin the calibration, follow the following steps:"); mvprintw(3,0," a) Ensure that all WAM power and signal cables are securely fastened."); mvprintw(4,0," b) Ensure that the WAM is powered on (receiving power)."); mvprintw(5,0," c) E-STOP the WAM (Important!)."); mvprintw(6,0," d) Release all E-STOPs."); mvprintw(7,0," e) Place the WAM in Shift+Idle mode."); mvprintw(8,0," f) Carefully ensure that the WAM is in its home (folded) position."); mvprintw(9,0,"Press [Enter] to continue."); refresh(); while (btkey_get()!=BTKEY_ENTER) usleep(10000); /* Initialize system buses */ err = ReadSystemFromConfig("../../wam.conf", &busCount); if(err) return -1; /* Spin off the CAN thread */ startDone = 0; btrt_thread_create(&can_thd,"can",45,(void*)can_thd_function,NULL); while (!startDone) usleep(10000); /* Spin off the magenc thread, which also detecs puck versions into mechset */ /* EEK! Why must this be such high priority? */ mz_mechset = (int *) malloc( wam->dof * sizeof(int) ); mz_magvals = (int *)calloc( wam->dof, sizeof(int) ); mz_magvals_set = 0; btrt_thread_create(&magenc_thd, "mage", 91, (void*)magenc_thd_function, NULL); /* Spin off the WAM thread */ wam_thd.period = 0.002; /* Control loop period in seconds */ btrt_thread_create(&wam_thd,"ctrl",90,(void*)WAMControlThread,(void*)wam); /* Allow the user to shift-activate */ mvprintw(11,0,"Place the WAM in Shift+Activate mode,"); mvprintw(12,0,"and press [Enter] to continue."); refresh(); while (btkey_get()!=BTKEY_ENTER) usleep(10000); /* Hold position */ SetJointSpace(wam); MoveSetup(wam, 1.0, 1.0); MoveWAM(wam,wam->Jpos); /* Start the user interface */ mode = MODE_TOZERO; joint = 0; jangle = new_vn(wam->dof); set_vn(jangle,wam->Jpos); clear(); done = 0; signal(SIGINT, sigint); while (!done) { char buf[80]; int j; int line; enum btkey key; /* Display the Zeroing calibration stuff ... */ mz_magvals_set = 1; mvprintw(0, 0, "Joint Position (rad): %s", sprint_vn(buf, wam->Jpos)); line = 2; if (mode == MODE_TOZERO) { attron(A_BOLD); mvprintw(line++, 0, "--> ] Move To Current Zero"); attroff(A_BOLD); } else mvprintw(line++, 0, " ] Move To Current Zero"); if (mode == MODE_CANCEL) { attron(A_BOLD); mvprintw(line++, 0, "--> ] Cancel Calibration"); attroff(A_BOLD); } else mvprintw(line++, 0, " ] Cancel Calibration"); if (mode == MODE_PRINTVALS) { attron(A_BOLD); mvprintw(line++, 0, "--> ] Print Calibrated Values and Exit"); attroff(A_BOLD); } else mvprintw(line++, 0, " ] Print Calibrated Values and Exit"); if (mode == MODE_JSELECT) { attron(A_BOLD); mvprintw(line, 0, "--> ] Joint:"); attroff(A_BOLD); } else mvprintw(line, 0, " ] Joint:"); mvprintw(line+1, 5, "-------"); if (mode == MODE_EDIT) attron(A_BOLD); mvprintw(line+2, 5, " Set:"); if (mode == MODE_EDIT) attroff(A_BOLD); mvprintw(line+3, 5, "Actual:"); mvprintw(line+5, 5, " Motor:"); mvprintw(line+6, 5, "MagEnc:"); for (j=0; j<wam->dof; j++) { if ((mode == MODE_JSELECT || mode == MODE_EDIT) && j==joint) { attron(A_BOLD); mvprintw(line+0, 13 + 9*j, "[Joint %d]",j+1); attroff(A_BOLD); } else mvprintw(line+0, 13 + 9*j, " Joint %d ",j+1); /* total with 8, 5 decimal points (+0.12345) */ if ( mode==MODE_EDIT && j==joint ) { int boldplace; mvprintw(line+1, 13 + 9*j, " _._____ ",j+1); mvprintw(line+2, 13 + 9*j, "% 08.5f ",jangle->q[j]); boldplace = decplace + 1; if (decplace) boldplace++; mvprintw(line+1, 13 + 9*j + boldplace,"x"); mvchgat(line+2, 13 + 9*j+boldplace, 1, A_BOLD, 0, NULL ); } else { mvprintw(line+1, 13 + 9*j, " ------- ",j+1); mvprintw(line+2, 13 + 9*j, "% 08.5f ",jangle->q[j]); } mvprintw(line+3, 13 + 9*j, "% 08.5f ",getval_vn(wam->Jpos,j)); mvprintw(line+5, 13 + 9*j, " Motor %d",j+1); if (mz_mechset[j]) mvprintw(line+6, 13 + 9*j, " %04d",mz_magvals[j]); else mvprintw(line+6, 13 + 9*j, " (None)",mz_magvals[j]); } refresh(); /* Wait a bit ... */ usleep(5E4); key = btkey_get(); /* If the user is in menu mode, work the menu ... */ if (mode != MODE_EDIT) switch (key) { case BTKEY_UP: mode--; if ((signed int)mode < 0) mode = 0; break; case BTKEY_DOWN: mode++; if (mode > MODE_JSELECT) mode = MODE_JSELECT; break; case BTKEY_ENTER: switch (mode) { case MODE_TOZERO: if (!MoveIsDone(wam)) break; fill_vn(jangle,0.0); MoveWAM(wam,jangle); break; case MODE_CANCEL: done = -1; break; case MODE_PRINTVALS: if (!MoveIsDone(wam)) break; done = 1; break; case MODE_JSELECT: mode = MODE_EDIT; decplace = 4; break; } break; default: if (mode == MODE_JSELECT) switch (key) { case BTKEY_LEFT: joint--; if (joint < 0) joint = 0; break; case BTKEY_RIGHT: joint++; if (joint >= wam->dof) joint = wam->dof - 1; break; } break; } /* We're in joint edit mode */ else switch (key) { case BTKEY_LEFT: decplace--; if (decplace < 0) decplace = 0; break; case BTKEY_RIGHT: decplace++; if (decplace > 5) decplace = 5; break; case BTKEY_BACKSPACE: mode = MODE_JSELECT; break; /* Actually do the moves */ case BTKEY_UP: if (!MoveIsDone(wam)) break; jangle->q[joint] += pow(10,-decplace); MoveWAM(wam,jangle); break; case BTKEY_DOWN: if (!MoveIsDone(wam)) break; jangle->q[joint] -= pow(10,-decplace); MoveWAM(wam,jangle); break; default: break; } } if (done == 1) { vect_n * vec; /* Save the new home location */ vec = new_vn(wam->dof); set_vn( vec, sub_vn(wam->park_location,jangle) ); sprint_vn(newhome,vec); destroy_vn(&vec); /* Save the zeromag values */ for (i=0; i<wam->dof; i++) if (!mz_mechset[i]) mz_magvals[i] = -1; sprintf(zeromag,"< %d",mz_magvals[0]); for (i=1; i<wam->dof; i++) sprintf(zeromag+strlen(zeromag),", %d",mz_magvals[i]); sprintf(zeromag+strlen(zeromag)," >"); } /* Re-fold, print, and exit */ clear(); mvprintw(0,0,"Moving back to the park location ..."); refresh(); MoveWAM(wam,wam->park_location); while (!MoveIsDone(wam)) usleep(10000); mvprintw(1,0,"Shift+Idle, and press [Enter] to continue."); refresh(); while (btkey_get()!=BTKEY_ENTER) usleep(10000); /* Stop threads ... */ wam_thd.done = 1; usleep(10000); can_thd.done = 1; usleep(50000); /* Stop ncurses ... */ endwin(); if (done == 1) { /* Print the results */ printf("\n"); printf("Zeroing calibration ended.\n"); printf("\n"); for (i=0; i<wam->dof; i++) if (!mz_mechset[i]) { printf("Note: Some (or all) of your pucks do not support absolute\n"); printf("position measurement, either because they do not use magnetic\n"); printf("encoders, or because they have not been updated to firmware r118.\n"); printf("\n"); break; } printf("Copy the following lines into your wam.conf file,\n"); printf("near the top, in the %s{} group.\n",wam->name); printf("Make sure it replaces the old home = < ... > definition.\n"); printf("--------\n"); printf(" # Calibrated zero values ...\n"); printf(" home = %s\n",newhome); for (i=0; i<wam->dof; i++) if (mz_mechset[i]) { printf(" zeromag = %s\n",zeromag); break; } printf("--------\n"); { FILE * logfile; logfile = fopen("cal-zero.log","w"); if (logfile) { fprintf(logfile," # Calibrated zero values ...\n"); fprintf(logfile," home = %s\n",newhome); for (i=0; i<wam->dof; i++) if (mz_mechset[i]) { fprintf(logfile," zeromag = %s\n",zeromag); break; } fclose(logfile); printf("This text has been saved to cal-zero.log.\n"); printf("\n"); } else { syslog(LOG_ERR,"Could not write to cal-zero.log."); printf("Error: Could not write to cal-zero.log.\n"); printf("\n"); } } printf("Note that you must E-Stop (or power-cycle) your WAM\n"); printf("for the calibrated settings to take effect!\n"); printf("\n"); } return 0; }