Movado は,基本系(FUND: fundamentals)・パラメタ系(PARA: parameters)・制御系(CONT: controller)・通信系(COMM: communicator)からなります.

基本系(FUND)は,メインプログラムのほかに,32 ビット固定小数点モジュール FIX からなります.メインプログラム main では,Movado の各系(PARA・CONT・COMM)を初期化したのち,制御サイクルごとのタイマ割り込み,およびシリアル通信割り込みの待機状態にはいります.また,32 ビット固定小数点モジュールは,32 ビット固定小数点(fix)データどうしの乗算・除算・加算・減算関数を外部に提供します.
パラメタ(PARA)系は,32 ビット固定小数点パラメタ領域 F・16 ビットパラメタ領域 W と,こららパラメタの初期化モジュール VAR からなります.たとえば,2 番モータの現在位置(POS)であれば F[0x0b][2] のように,特定モータの特定パラメタに直接アクセス(読み書き)することが可能になります.
制御系(cont)は,制御サイクルごとに呼び出される制御メインモジュール ACT と,そこからさらに呼び出されるモータ制御モジュール PID,台形制御モジュール CAM,動作キャリブレーションモジュール MMF からなります.ACT モジュールは,エンコーダから現在位置(POS)を読み取り,現在速度(VEL)を計測(アンチエイリアシング処理)します.リクエストがあれば,MMF や CAM を起動し,現在の制御サイクルでの目標位置(XPOS)を決定して,この目標位置に向けたモータ制御を PID で実行します.
通信系(comm)は,ホスト PC からの指令パケットを待ち受け,受信時にはそのパケットを処理し,必要に応じて返信をホスト PC に送信するモジュール PAC からなります.パケットの処理は,多くの場合,パラメタの読み書きとして実行されます.
// // fundamentals #include "sh7046f.h" // header for sh7046f #include "bios.c" // bios program for Pico-2
// program version #define VER 0x0103 // ex. 0x010f for 1.15
// Pico-2 controls 4 axes in parallel #define NN 4 // number of axes (motors)
// packet length #define PACLEN 6 // packet length in bytes
// address of this pico2 (5bits) <- to be set by SW5-1 uchar ADDR; // communication address
// control cycle (DTf: period, FQf: frequency) #define DTf8 0x00004189 // 0.001s in s0824 format #define FQf 0x03e80000 // 1000Hz in s1616 format #define CMi 767 // CMT count for 4000Hz = 768*8P
// fix type typedef int fix; // fixed point s1616
// // main of Movado int main () { void VAR_init(void), // parameter initializer PAC_do(uchar*), // packet interpretor ACT_do(void); // actuation process // check if rebooted from WOVF (watch-dog timer overflow) if (WDT_check()) { LED_set(0x1f); // "help me" on LEDs for (;;); // infinite loop }
// init LED, address LED_init(); LED_set(0x00); SWT_init(); ADDR = SWT_get();
// init variable block VAR_init();
// initialization for PWM/RCS/ENC PWM_init(); RCS_init(); ENC_init();
// SCI setup with address // PACLEN=6 (1-addr5-n2, 0-inst3-msbs4, // 0-hept7, 0-hept7, 0-hept7, 0-hept7 ) SCI_init(ADDR, PACLEN, (void *) PAC_do);
// CMT setup (cselB2=0x00, CMi=767) // 1000Hz (control) -> 4000Hz (strobe) -> P/768 -> CMi=767 CMT0_init(0x00, CMi, ACT_do);
// WDT setup (csel=0x04: 2.6667ms=375Hz) WDT_init(0x04);
// start event-loop set_imask(0); for (;;) { }
return 0; }
// // FIX: fixed point calculation (s1616) // xxxx:xxxx:xxxx:xxxx.xxxx:xxxx:xxxx:xxxx (32bits) // | | | | // 2^15 2^0 2^-1 2^-16
fix FIX_safe_s3216 (long long f64) {
if ((f64 & 0xffff80000000LL) == 0xffff80000000LL) return f64 & 0xffffffffLL; // minus (normal) else if (f64 & 0x800000000000LL) return 0x80000000; // minus (out of range) else if (f64 & 0x7fff80000000LL) return 0x7fffffff; // plus (out of range) else return f64; // plus (normal) } fix FIX_safe_s4816 (long long f64) {
if ((f64 & 0xffffffff80000000LL) == 0xffffffff80000000LL) return f64 & 0xffffffffLL; // minus (normal) else if (f64 & 0x8000000000000000LL) return 0x80000000; // minus (out of range) else if (f64 & 0x7fffffff80000000LL) return 0x7fffffff; // plus (out of range) else return f64; // plus (normal) } fix FIX_mul (fix f1, fix f2) { long long f64; f64 = (((long long) f1) * ((long long) f2)) >> 16;
return FIX_safe_s3216(f64); } fix FIX_div (fix f1, fix f2) { long long f64; f64 = (((long long) f1) << 16) / ((long long) f2);
return FIX_safe_s4816(f64); } fix FIX_add (fix f1, fix f2) { long long f64; f64 = ((long long) f1) + ((long long) f2);
return FIX_safe_s4816(f64); } fix FIX_sub (fix f1, fix f2) { long long f64; f64 = ((long long) f1) - ((long long) f2);
return FIX_safe_s4816(f64); }
// // fix quads (32bit fixed point s1616, packed for 4 axes) #define NF 29 // number of fix quads
fix F[NF][NN];
#define FO_MOT 0 // offset for DC-motor quads #define FO_RCS 5 // offset for RC-servo quads // ( XPOS, XVEL, ACAM, VCAM, PCAM, // RXPOS,RXVEL,RACAM,RVCAM,RPCAM )
#define XPOS 0x00 // goal position #define XVEL 0x01 // velocity in CAM (in rad/s) #define ACAM 0x02 // acceleration in CAM #define VCAM 0x03 // max velocity in CAM #define PCAM 0x04 // goal position in CAM
#define RXPOS 0x05 // RCS goal position #define RXVEL 0x06 // RCS velocity in CAM (in tick/s) #define RACAM 0x07 // RCS acceleration in CAM #define RVCAM 0x08 // RCS max velocity in CAM #define RPCAM 0x09 // RCS goal position in CAM
#define RXPOS_DEF 0x24000000 // default (center) for RXPOS #define RACAM_DEF 0x04000000 // default RACAM (approx 30deg/s/s) #define RVCAM_DEF 0x04000000 // RVCAM default (approx 30deg/s)
#define PMAR 0x0a // margin for MIN/MAX (in rad) #define PMAR_DEF 0x00010000 // default for PMAR at 1rad
#define POS 0x0b // current position #define VEL 0x0c // current velocity (after LPF) #define XTOR 0x0d // goal torque (EXPERIMENTAL) #define TOR 0x0e // current torque (EXPERIMENTAL)
#define ERPC8 0x0f // encoder resolution (s0824) #define ERPC8_16 0x001921fb // rad/count (for Nenc=16) #define ERPC8_200 0x000202b8 // rad/count (for Nenc=200) #define ERPC8_256 0x00019220 // rad/count (for Nenc=256)
#define MIN 0x10 // min position (set by MMF) #define MAX 0x11 // max position (set by MMF) #define MIN_DEF 0x80000000 // default MIN position #define MAX_DEF 0x7fffffff // default MAX position
#define KP 0x12 // gain for proportional control #define KI 0x13 // gain for integral control #define KD 0x14 // gain for differential control #define KP_DEF 0x00020000 // default KP = 2.00000 #define KI_DEF 0x00280000 // default KI = 40.00000 #define KD_DEF 0x00000ccd // default KD = 0.05000
#define VMP 0x15 // motor power voltage (in V) #define VMP_DEF 0x000c0000 // VMP default (for 12.0V)
#define VMAG 0x16 // voltage magnifier // VMAG = 32768 / VMP
#define VINT 0x17 // accumlator for integral cont
#define POLD 0x18 // old position for velocity calc
#define LPFA 0x19 // alpha factor (for LPF(VEL)) #define LPFA_16 0x00001000 // alpha = 1/16 #define LPFA_200 0x00004000 // alpha = 1/4 #define LPFA_256 0x00004000 // alpha = 1/4
#define LPFD 0x1a // decay factor (for LPF(VEL)) // LPFD = 1.0 - LPFA
#define ACAM0 0x1b // acceleration for move commands #define ACAM0_DEF 0x00d406ae // default ACAM0 = 0.5*(2*Pi*67.49)
#define VCAM0 0x1c // max velocity for move commands #define VCAM0_DEF 0x00d406ae // default VCAM0 = 0.5*(2*Pi*67.49)
// // word block (16bit; unsigned short) #define NW 10 // number of word quads
ushort W[NW][NN];
#define WO_MOT 0 // offset for DC-motor quads #define WO_RCS 2 // offset for RC-servo quads // ( CAMOD, MODE, // RCAMOD, RMODE )
#define CAMOD 0x00 // submode in CAM #define MODE 0x01 // operation mode #define RCAMOD 0x02 // RCS submode in CAM #define RMODE 0x03 // RCS operation mode #define CAMOD_NO 0x0000 // no CAM operation #define CAMOD_GO 0xffff // start CAM with ACAM (move/ac/el) #define CAMOD_FF 0x000f // goal ahead, moving forward #define CAMOD_FB 0x00f0 // goal ahead, moving backward #define CAMOD_BF 0x0f00 // goal back, moving forward #define CAMOD_BB 0xf000 // goal back, moving backward
#define MODE_NOP 0 // no operation #define MODE_POS 1 // position control #define MODE_VEL 2 // velocity control (reserved) #define MODE_TOR 3 // torque control (reserved)
#define MMFLG 0x04 // minmax finder flag #define MM_NOP 0x0000 // not in minmax mode #define MM_MIN 0xf000 // mining flag for MMF #define MM_MAX 0x000f // maxing flag for MMF #define MM_GO_CEN 0x03c0 // go-to-cen flag for MMF #define MM_GO_MIN 0x0c00 // go-to-min flag for MMF #define MM_GO_MAX 0x0030 // go-to-max flag for MMF
#define MMEMG 0x05 // minmax error magnitude
#define REP_INT 0x06 // report interval (of Dt) #define REP_CNT 0x07 // report count (tmp) #define REP_ACT 0x08 // report count in action #define REP_TIC 0x09 // report interval tick
// // initialize variables void VAR_init () { int n; fix erpc8, lpfa; // clear F/W blocks for (n = 0; n < NN; n++) { int index; // clear fix block for (index = 0; index < NF; index++) F[index][n] = 0; // clear word block for (index = 0; index < NW; index++) W[index][n] = 0; }
// set encoder resolution and lpf parameters (according to ADDR) if (ADDR & 0x10) { // 0x10..0x1e -> 256ppr/1000Hz erpc8 = ERPC8_256; lpfa = LPFA_256; } else if (ADDR & 0x08) { // 0x08..0x0f -> 200ppr/1000Hz erpc8 = ERPC8_200; lpfa = LPFA_200; } else { // 0x00..0x07 -> 16ppr/100Hz erpc8 = ERPC8_16; lpfa = LPFA_16; }
// init F/W blocks (for non-zero init value) for (n = 0; n < NN; n++) { // F F[KP][n] = KP_DEF; F[KI][n] = KI_DEF; F[KD][n] = KD_DEF; F[ACAM0][n] = ACAM0_DEF; F[VCAM0][n] = VCAM0_DEF; F[MIN][n] = MIN_DEF; F[MAX][n] = MAX_DEF; F[PMAR][n] = PMAR_DEF; F[ERPC8][n] = erpc8; F[LPFA][n] = lpfa; F[LPFD][n] = FIX_sub(0x00010000, lpfa); F[VMP][n] = VMP_DEF; F[VMAG][n] = FIX_div(0x7fffffff, VMP_DEF); F[RXPOS][n] = RXPOS_DEF; F[RACAM][n] = RACAM_DEF; F[RVCAM][n] = RVCAM_DEF; // W W[MODE][n] = MODE_POS; W[RMODE][n] = MODE_POS; }
}
// // ACT: actuation process void ACT_do (void) { fix ACT_enc(uchar); // encoder read in rad void PAC_report(int, fix), // position report for "report" MMF_do(uchar), // minmax finder module CAM_do(uchar, uchar, uchar), // trapezoid control module PID_do(uchar); // PID control module static uchar n = 0; // axis number {0,1,2,3} fix pos, vel; // current pos, vel (tmp)
// update POS and VEL pos = ACT_enc(n); F[POS][n] = pos; vel = FIX_mul(FIX_sub(pos, F[POLD][n]), FQf); F[POLD][n] = pos;
// low-pass filter for velocity // (needed for stabilizing the differentiation) // LPF = (1.0 - LPFA) * VEL + LPFA * VEL F[VEL][n] = FIX_add(FIX_mul(F[LPFD][n], F[VEL][n]), FIX_mul(F[LPFA][n], vel) );
// report (if needed) if (W[REP_ACT][n]) { if (W[REP_TIC][n] == 0) { PAC_report(n, pos); // report POS W[REP_ACT][n]--; // decrement counter W[REP_TIC][n] = W[REP_INT][n]; // reset interval } W[REP_TIC][n]--; }
// control the n-th motor switch (W[MODE][n]) { case MODE_NOP: // no-operator (and raw mode) break; case MODE_POS: // position control // if minmax then if (W[MMFLG][n]) MMF_do(n); // if CAM then if (W[CAMOD][n]) CAM_do(n, FO_MOT, WO_MOT); // PID control PID_do(n); break;
case MODE_VEL: // velocity control (experimental) PWM_set(n, FIX_mul(F[XVEL][n], F[VMAG][n]) >> 16); break; case MODE_TOR: // torque control (experimental) break; } // control the n-th RCS switch (W[RMODE][n]) { case MODE_NOP: // no-operator (and raw mode) break; case MODE_POS: // position control // if cam then if (W[RCAMOD][n]) CAM_do(n, FO_RCS, WO_RCS); // actuate the RCS RCS_set(n, F[RXPOS][n] >> 16); break;
} // update counters n++; if (n == NN) { // reset/update the counters n = 0; // clear watch-dog timer WDT_reset(); }
} // fix ACT_enc () // returns encoder position in rad (radian) // in fixed point s1616 format; fix ACT_enc (uchar n) { // ENC_get(n): Encoder count in 24bit integer // EPRC8[n] : Encoder resolution (rad/count; s0824) // --------------- s1616 ----------------- // ----- s2408 ----- -- s0824 -- return FIX_mul((ENC_get(n) << 8), F[ERPC8][n]);
}
// // PID: controller void PID_do (uchar n) { fix xposf, // goal position (after limitter) erf, // error (s1616) vpf, // output of proportional control vdf, // output of differential control vof; // final output // limit range of motion in [MIN, MAX] xposf = F[XPOS][n]; if (xposf < F[MIN][n]) xposf = F[MIN][n]; if (xposf > F[MAX][n]) xposf = F[MAX][n];
// calculate error // erf = xpos - POSf erf = FIX_sub(xposf, F[POS][n]);
// proportional control // vpf = KPf * erf vpf = FIX_mul(F[KP][n], erf);
// integral control // VINT += KIf * DTf * ERf F[VINT][n] = FIX_add(F[VINT][n], // --- s2408 --- -s0824- FIX_mul(FIX_mul((F[KI][n] >> 8), DTf8), erf)); if (F[VINT][n] > F[VMP][n]) F[VINT][n] = F[VMP][n]; if (F[VINT][n] < -F[VMP][n]) F[VINT][n] = -F[VMP][n];
// differential control (position-based version) // vdf = KDf * (POLD - POS) / DTf --- (DTf: DeltaT=0.001s) // = KDf * (POLD - POS) * FQf --- (FQf: Freq=1/DeltaT) // = - KDf * VEL vdf = -FIX_mul(F[KD][n], F[VEL][n]);
// sum up the outputs // vof = (vpf + VIf + vdf); vof = FIX_add(vpf, FIX_add(F[VINT][n], vdf)); if (vof > F[VMP][n]) vof = F[VMP][n]; if (vof < -F[VMP][n]) vof = -F[VMP][n];
// power meter for debugging if (vof >= 0) LED_op(0x0f, (vof >> 16) & 0x0f); else LED_op(0x0f, ((-vof) >> 16) & 0x0f);
// PWM output (s1616 -> short) PWM_set(n, FIX_mul(vof, F[VMAG][n]) >> 16);
}
// // CAM: constant acceleration mode (MOT/RCS shared version) // for MOT (motor), provide FO_MOT and WO_MOT for fo and wo; // for RCS (servo), provide FO_RCS and WO_RCS for fo and wo; // (these values will give bias for var-block index)
void CAM_do (uchar n, uchar fo, uchar wo) { fix acam, vcam, xvel; acam = FIX_mul(FIX_mul(F[ACAM+fo][n] >> 8, DTf8) >> 8, DTf8); vcam = FIX_mul(F[VCAM+fo][n] >> 8, DTf8); xvel = F[XVEL+fo][n];
// ACAM0 should be more than 15.26 (=1000*1000/65536) // (in any case, acam should be more than 0x00000001) if (acam <= 0) acam = 0x00000001;
// CAM operation if (xvel > acam) { // I'm moving forward if (F[XPOS+fo][n] > F[PCAM+fo][n]) {
// and the goal is behind! W[CAMOD+wo][n] = CAMOD_BF; // decrease speed, anyway xvel = FIX_sub(xvel, acam); if (xvel < -vcam) xvel = -vcam; } else {
int vabsf, pcrif; // the goal is ahead // (or I'm passing above the goal forward) W[CAMOD+wo][n] = CAMOD_FF; // compute the critical point for braking vabsf = xvel; pcrif = FIX_sub(F[PCAM+fo][n], FIX_div(FIX_mul(vabsf, FIX_add(vabsf, acam)), FIX_add(acam, acam) )); // If I have passed (or am passing) the point, // then decrease speed // otherwise increase speed if (F[XPOS+fo][n] >= FIX_sub(pcrif, vabsf)) { xvel = FIX_sub(xvel, acam); if (xvel < -vcam) xvel = -vcam; } else { xvel = FIX_add(xvel, acam); if (xvel > vcam) xvel = vcam; } } } else if (xvel < -acam) { // I'm moving backward if (F[XPOS+fo][n] < F[PCAM+fo][n]) {
// and the goal is ahead! W[CAMOD+wo][n] = CAMOD_FB; // increase speed, anyway xvel = FIX_add(xvel, acam); if (xvel > vcam) xvel = vcam; } else {
int vabsf, pcrif; // the goal is behind // (or I'm passing above the goal backward) W[CAMOD+wo][n] = CAMOD_BB; // compute the critical point for braking vabsf = -xvel; pcrif = FIX_add(F[PCAM+fo][n], FIX_div(FIX_mul(vabsf, FIX_add(vabsf, acam)), FIX_add(acam, acam) )); // If I have passed (or am passing) the point, // then increase speed // otherwise decrease speed if (F[XPOS+fo][n] <= pcrif + vabsf) { xvel = FIX_add(xvel, acam); if (xvel > vcam) xvel = vcam; } else { xvel = FIX_sub(xvel, acam); if (xvel < -vcam) xvel = -vcam; } } } else { // I'm almost stand still (VNOW is almost zero) if (F[XPOS+fo][n] < FIX_sub(F[PCAM+fo][n], acam)) {
// the goal is ahead W[CAMOD+wo][n] = CAMOD_FF; // increase speed to move forward xvel = FIX_add(xvel, acam); if (xvel > vcam) xvel = vcam; } else if (F[PCAM+fo][n] + acam < F[XPOS+fo][n]) {
// the goal is behind W[CAMOD+wo][n] = CAMOD_BB; // decrease speed to move backward xvel = FIX_sub(xvel, acam); if (xvel < -vcam) xvel = -vcam; } else {
// I'm almost at the goal // (force to stop moving at the goal) F[XPOS+fo][n] = F[PCAM+fo][n]; xvel = 0; W[CAMOD+wo][n] = CAMOD_NO; return; } } // finally update the goal position and goal velocity F[XPOS+fo][n] = FIX_add(F[XPOS+fo][n], xvel); F[XVEL+fo][n] = xvel;
}
// // MMF: minmax finder void MMF_do (uchar n) { fix mvel, merr; // indicate MMF-ing LED_op(0x10, 0x10);
// minmax velocity (VCAM0/FQf) // (for different velocity, change setvel before do_min/max/etc) mvel = FIX_mul(F[VCAM0][n] >> 8, DTf8);
// error for collision detection // (ushort MMEMG [rad]) merr = FIX_mul(mvel, W[MMEMG][n] << 16);
if (W[MMFLG][n] & MM_MIN) {
// find min end // if in CAM, stop it (otherwise XPOS would get stuck) W[CAMOD][n] = CAMOD_NO; // check collision with min end if (-FIX_sub(F[XPOS][n], F[POS][n]) > merr) { // collision!! // set MIN at POS+margin F[MIN][n] = FIX_add(F[POS][n], F[PMAR][n]); // stop motor at MIN F[XPOS][n] = F[MIN][n]; // clear MM_MIN flag W[MMFLG][n] &= ~(MM_MIN); LED_op(0x10, 0x00); } else { // no collision, so go backward F[XPOS][n] = FIX_sub(F[XPOS][n], mvel); } } else if (W[MMFLG][n] & MM_MAX) {
// find max end // if in CAM, stop it (otherwise XPOS would get stuck) W[CAMOD][n] = CAMOD_NO; // check collision with max end if (FIX_sub(F[XPOS][n], F[POS][n]) > merr) { // collision!! // set MIN at POS-margin F[MAX][n] = FIX_sub(F[POS][n], F[PMAR][n]); // stop motor at MAX F[XPOS][n] = F[MAX][n]; // clear MM_MAX flag W[MMFLG][n] &= ~(MM_MAX); LED_op(0x10, 0x00); } else { // no collision, so go forward F[XPOS][n] = FIX_add(F[XPOS][n], mvel); } } else if (W[MMFLG][n] & (MM_GO_CEN | MM_GO_MAX | MM_GO_MIN)) {
fix xpos, diff; // set goal position if (W[MMFLG][n] & MM_GO_MAX) xpos = F[MAX][n]; else if (W[MMFLG][n] & MM_GO_MIN) xpos = F[MIN][n]; else // center = (MIN+MAX)*0.5 xpos = FIX_mul(FIX_add(F[MIN][n], F[MAX][n]), 0x00008000); // forward/backword/terminte diff = FIX_sub(xpos , F[XPOS][n]); if (diff > mvel) { // move forward F[XPOS][n] = FIX_add(F[XPOS][n], mvel); } else if (diff < -mvel) { // move backward F[XPOS][n] = FIX_sub(F[XPOS][n], mvel); } else {
fix offset; // zero (make current position "zero") offset = xposf; F[XPOS][n] = 0; F[POS][n] = 0; F[POLD][n] = 0; ENC_set(n, 0); // move MIN/MAX F[MIN][n] = FIX_sub(F[MIN][n], offset); F[MAX][n] = FIX_sub(F[MAX][n], offset); // clear the flag W[MMFLG][n] = MM_NOP; LED_op(0x10, 0x00); } } }
// // PAC: packet translator void PAC_to_NIQ (uchar *packet, ushort *n, ushort *inst, uint *quad) {
uchar msbs; uchar data1, data2, data3, data4; // motor number (N) *n = packet[0] & 0x03; // inst (I) from upper 3 bits of packet[1] // (lower 4 bits are msbs for arg(g1-4)) *inst = packet[1] >> 4; msbs = packet[1] & 0x0f; // quad (Q) = data1..4 data1 = packet[2] | ((msbs & 0x08)? 0x80: 0); data2 = packet[3] | ((msbs & 0x04)? 0x80: 0); data3 = packet[4] | ((msbs & 0x02)? 0x80: 0); data4 = packet[5] | ((msbs & 0x01)? 0x80: 0); *quad = (data1 << 24) | (data2 << 16) | (data3 << 8) | data4; } void PAC_from_NIQ (uchar *packet, ushort n, ushort inst, uint quad) {
packet[0] = (ADDR << 2) | (n & 0x03); packet[1] = (inst & 0x07) << 4 | ((quad & 0x80000000)? 0x08: 0) | ((quad & 0x00800000)? 0x04: 0) | ((quad & 0x00008000)? 0x02: 0) | ((quad & 0x00000080)? 0x01: 0); packet[2] = (quad & 0x7f000000) >> 24; packet[3] = (quad & 0x007f0000) >> 16; packet[4] = (quad & 0x00007f00) >> 8; packet[5] = (quad & 0x0000007f); } // PAC_do: packet interpreter ushort Low16; // lower 16bits for fix
void PAC_do (uchar *packet) { ushort n, inst; uint quad; uchar r_packet[PACLEN]; void PAC_report_trigger(int); PAC_to_NIQ(packet, &n, &inst, &quad); if (inst == 0) {
// move: move to pos in CAM with preset acc F[ACAM][n] = F[ACAM0][n]; F[VCAM][n] = F[VCAM0][n]; F[PCAM][n] = (fix) quad; W[CAMOD][n] = CAMOD_GO; // if needed, trigger reporting if (W[REP_CNT][n]) PAC_report_trigger(n);
} else if (inst == 1) { fix arg; arg = (fix) quad; if (arg < 0) {
// movac: move to pos in CAM with -acc // (arg = acc:n16,pos:s16) F[ACAM][n] = - (arg & 0xffff0000); F[VCAM][n] = F[VCAM0][n]; F[PCAM][n] = (fix) (arg << 16); W[CAMOD][n] = CAMOD_GO; // if needed, trigger reporting if (W[REP_CNT][n]) PAC_report_trigger(n); } else {
// setacc: acceleration for move F[ACAM0][n] = arg; } } else if (inst == 2) {
fix arg; arg = (fix) quad; if (arg < 0) { // movel: move to pos in CAM with -vel // (arg = vel:n16,pos:s16) F[ACAM][n] = F[ACAM0][n]; F[VCAM][n] = - (arg & 0xffff0000); F[PCAM][n] = (fix) (arg << 16); W[CAMOD][n] = CAMOD_GO; // if needed, trigger reporting if (W[REP_CNT][n]) PAC_report_trigger(n); } else {
// setvel: velocity for move F[VCAM0][n] = arg; } } else if (inst == 3) {
// setpos: ballistic motion // cancel CAM W[CAMOD][n] = CAMOD_NO; // set to XPOS F[XPOS][n] = (fix) quad; // if needed, trigger reporting if (W[REP_CNT][n]) PAC_report_trigger(n); } else if (inst == 5) {
// getacc: current acceleration quad = (uint) F[ACAM][n]; PAC_from_NIQ(r_packet, n, inst, quad); SCI_transmit(r_packet); } else if (inst == 6) {
// getvel: current velocity quad = (uint) F[VEL][n]; PAC_from_NIQ(r_packet, n, inst, quad); SCI_transmit(r_packet); } else if (inst == 7) {
// getpos: current position quad = (uint) F[POS][n]; PAC_from_NIQ(r_packet, n, inst, quad); SCI_transmit(r_packet); } else if (inst == 4) {
ushort jnst, index, word; // sub-command jnst = quad >> 24; index = (quad & 0x00ff0000) >> 16; word = quad & 0x0000ffff; if (jnst == 0x00) {
// set_fix if (index == 0xff) Low16 = word; else if (index < NF) { F[index][n] = (fix) ((word << 16) | Low16); // auto set variables (VMAG, LPFD) if (index == VMP) { // VMAG = 32768 / VMP; F[VMAG][n] = FIX_div(0x7fffffff, F[VMP][n]); } else if (index == LPFA) { // LPFD = 1.0 - LPFA F[LPFD][n] = FIX_sub(0x00010000, F[LPFA][n]); } } } else if (jnst == 0x01) {
// set_word if (index < NW) W[index][n] = word; } else if (jnst == 0x70) {
switch (index) { case 0x00: // move_rcs F[RPCAM][n] = (fix) (word << 16); W[RCAMOD][n] = CAMOD_GO; break; case 0x01: // setacc_rcs F[RACAM][n] = (fix) (word << 16); break; case 0x02: // setvel_rcs F[RVCAM][n] = (fix) (word << 16); break; case 0x03: // setpos_rcs W[RCAMOD][n] = CAMOD_NO; F[RXPOS][n] = (fix) (word << 16); break; } } else if (jnst == 0x7f) {
switch (index) { case 0x00: // set_zero W[CAMOD][n] = CAMOD_NO; F[XPOS][n] = 0; F[POS][n] = 0; F[POLD][n] = 0; ENC_set(n, 0); break; case 0x01: // set_mode W[MODE][n] = word; break; case 0x02: // set_camod W[CAMOD][n] = word; break; case 0x04: // go_cen W[MMFLG][n] = MM_GO_CEN; break; case 0x05: // do_max W[MMFLG][n] = MM_MAX; W[MMEMG][n] = word; F[MAX][n] = MAX_DEF; break; case 0x06: // do_min W[MMFLG][n] = MM_MIN; W[MMEMG][n] = word; F[MIN][n] = MIN_DEF; break; case 0x07: // do_minmax W[MMFLG][n] = (MM_MIN | MM_MAX); W[MMEMG][n] = word; F[MIN][n] = MIN_DEF; F[MAX][n] = MAX_DEF; break; case 0x08: // do_minmaxcen W[MMFLG][n] = (MM_MIN | MM_MAX | MM_GO_CEN); W[MMEMG][n] = word; F[MIN][n] = MIN_DEF; F[MAX][n] = MAX_DEF; break; case 0x09: // do_minmaxmax W[MMFLG][n] = (MM_MIN | MM_MAX | MM_GO_MAX); W[MMEMG][n] = word; F[MIN][n] = MIN_DEF; F[MAX][n] = MAX_DEF; break; case 0x0a: // do_minmaxmin W[MMFLG][n] = (MM_MIN | MM_MAX | MM_GO_MIN); W[MMEMG][n] = word; F[MIN][n] = MIN_DEF; F[MAX][n] = MAX_DEF; break; case 0xff: // reset VAR_init(); for (n = 0; n < NN; n++) ENC_set(n, 0); break; } } else if (jnst == 0x80) {
// get_fix F[index][n] if (index == 0xff) quad = (quad & 0xffff0000) | Low16; else if (index < NF) { uint tmp; tmp = (uint) F[index][n]; Low16 = tmp & 0xffff; quad = (quad & 0xffff0000) | (tmp >> 16); } else quad = 0xffffffff; // to indicate error PAC_from_NIQ(r_packet, n, inst, quad); SCI_transmit(r_packet); } else if (jnst == 0x81) {
// get_word W[index][n] if (index < NW) quad = (quad & 0xffff0000) | W[index][n]; else quad = 0xffffffff; // to indicate error PAC_from_NIQ(r_packet, n, inst, quad); SCI_transmit(r_packet); } else if (jnst == 0x82) {
// get_version quad = VER; PAC_from_NIQ(r_packet, n, inst, quad); SCI_transmit(r_packet); } else if (jnst == 0xf0) {
switch (index) { case 0x05: // getacc_rcs word = (ushort) (F[RACAM][n] >> 16); quad = (jnst << 24) | (index << 16) | word; break; case 0x06: // getvel_rcs word = (ushort) (F[RVCAM][n] >> 16); quad = (jnst << 24) | (index << 16) | word; break; case 0x07: // getpos_rcs if (W[RCAMOD][n]) word = (ushort) (F[RPCAM][n] >> 16); else word = (ushort) (F[RXPOS][n] >> 16); quad = (jnst << 24) | (index << 16) | word; break; default: quad = 0xffffffff; } PAC_from_NIQ(r_packet, n, inst, quad); SCI_transmit(r_packet); } else if (jnst == 0xff) {
// get_report W[REP_INT][n] = index; // interval (# of control loops) W[REP_CNT][n] = word; // report counts } else if (jnst >= 0x80) {
// unknown query (return "error" packet) quad = 0xffffffff; PAC_from_NIQ(r_packet, n, inst, quad); SCI_transmit(r_packet); } } } void PAC_report_trigger (int n) {
W[REP_ACT][n] = W[REP_CNT][n]; W[REP_CNT][n] = 0; W[REP_TIC][n] = 0; } void PAC_report (int n, fix pos) {
uchar r_packet[PACLEN]; PAC_from_NIQ(r_packet, n, 7, pos); // report packet (I=7) SCI_transmit(r_packet); }