home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Between Heaven & Hell 2
/
BetweenHeavenHell.cdr
/
500
/
470
/
rccl070
< prev
next >
Wrap
Text File
|
1987-03-02
|
17KB
|
834 lines
/*LINTLIBRARY*/
#include <sys/types.h>
#include <sys/drc.h>
#include <signal.h>
#include <sgtty.h>
#include "../h/exiod.h"
#include "../h/unim.h"
#include "../h/which.h"
#include "../h/rtc.h"
#ifdef PUMA
#include "../h/pumadata.h"
#endif
#ifdef STAN
#include "../h/standata.h"
#endif
struct chg chg; /* global control structure */
struct how how; /* global robot state structure */
int terminate = NO; /* shuts up the pack routine */
char *mess; /* printed by release */
static short obuff[COMSIZE] = {4, VERSION, ARMTYPE};
static unsigned short ref[6] = {ECCL1, ECCL2, ECCL3, ECCL4, ECCL5, ECCL6};
static unsigned short max[6] = {ECMX1, ECMX2, ECMX3, ECMX4, ECMX5, ECMX6};
static unsigned short min[6] = {ECMN1, ECMN2, ECMN3, ECMN4, ECMN5, ECMN6};
static unsigned short mvl[6] = {EMXV1, EMXV2, EMXV3, EMXV4, EMXV5, EMXV6};
static unsigned short mxdc[6] = {MXDC1, MXDC2, MXDC3, MXDC4, MXDC5, MXDC6};
static unsigned short mxoc[6] = {MXOC1, MXOC2, MXOC3, MXOC4, MXOC5, MXOC6};
static short idx[6] = {XCCL1, XCCL2, XCCL3, XCCL4, XCCL5, XCCL6};
#ifdef ADC
static int nch = NJOINTS;
static int adcmap[ADC] =
{0, 1, 2, 3, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
#endif
static int rate;
static int inserf = NO;
static int active = NO;
static int first = YES;
static int cbrkset = NO;
static int checking = YES;
static struct sgttyb mode;
/*
* set of macros to test requests contained in the chg structure
* and fill the output buffer on a byte basis in order to save
* maximum space.
*/
#define IRQST(x) *(k = &chg. x [i].set)
#define STUFFI(x,C) if (stack > top - 4)\
goto fatal;\
*stack++ = C | i;\
v = chg. x [i].vali;\
*stack++ = v >> 8;\
*stack++ = v & 0xff;\
*k = NO;
#define CMDI(x,C) if(IRQST(x)) {STUFFI(x,C)}
#define ARQST(x) *(k = &chg. x .set)
#define STUFFA(x,C) if (stack > top - 14)\
goto fatal;\
*stack++ = C;\
for (i = 0; i < NJOINTS; ++i) {\
v = chg. x . vala[i];\
*stack++ = v >> 8;\
*stack++ = v & 0xff;\
} *k = NO;
#define CMDA(x,C) if(ARQST(x)) {STUFFA(x,C)}
#define GRQST(x) *(k = &chg. x .set)
#define STUFFG(x,C) if (stack > top - 4)\
goto fatal;\
*stack++ = C;\
v = chg. x .valg;\
*stack++ = v >> 8;\
*stack++ = v & 0xff;\
*k = NO;
#define CMDG(x,C) if(GRQST(x)) {STUFFG(x,C)}
#define RQSTE(x) *(k = &chg. x)
#define STUFFE(C) if (stack > top - 2)\
goto fatal;\
*stack++ = C;\
*k = NO;
#define CMDE(x,C) if (RQSTE(x)) {STUFFE(C)}
/*
* to avoid the use of the terrible scanf
*/
#define GETCHAR(c) while ((c = getchar()) == ' ' \
|| c == '\t' || c == '\n') ;
#define QUERY(c) GETCHAR(c) \
while (c != 'y' && c != 'n') { \
GETCHAR(c); \
}
/*
* the pack function is called after execution of the interrupt
* user function 1 to translate the requests expressed in the
* chg structure into the communication language understandable
* by the lsi code.
* If for a reason or another, the flag terminate is raised,
* the user interrupt functions will no longer be called and
* pack will refuse to send anything but a rate command witc neg val which
* cause the lsi code to stop interrupting the vax and turn off
* the arm power.
*/
static pack() /*::*/
{
register int i;
register unsigned short v;
register char *k;
register char *stack = (char *)(obuff + 1); /* for byte count */
register char *top = (char *)(obuff + COMSIZE);
register int inc;
register unsigned short mcc;
if (terminate) {
terminated: chg.end = YES;
CMDE(end, END_E)
goto checksum ;
}
for (i = 0; i < NJOINTS; ++i) {
switch (IRQST(i_motion)) {
case NO :
break;
case POS :
inc = chg.i_motion[i].vali - how.pos[i];
inc = (inc < 0) ? -inc : inc;
if (checking) {
if (inc > mvl[i] * rate) {
goto toofast;
}
inc = chg.i_motion[i].vali;
if (inc > max[i] || inc < min[i]) {
goto toofar;
}
}
STUFFI(i_motion,POS_I)
break;
case CUR :
mcc = chg.i_motion[i].vali;
mcc = (mcc > 0100000) ? -mcc : mcc;
if (mcc > mxdc[i]) {
goto toostrong;
}
STUFFI(i_motion,CUR_I)
break;
case STOP :
STUFFI(i_motion,STOPP_I);
break;
case STOPCAL :
STUFFI(i_motion,STOPM_I);
break;
default :
goto fatal;
}
}
switch (ARQST(a_motion)) {
case NO :
break;
case POS :
if (checking) {
for (i = 0; i < NJOINTS; ++i) {
inc = chg.a_motion.vala[i] - how.pos[i];
inc = (inc < 0) ? -inc : inc;
if (inc > mvl[i] * rate) {
goto toofast;
}
inc = chg.a_motion.vala[i];
if (inc > max[i] || inc < min[i]) {
goto toofar;
}
}
}
STUFFA(a_motion,POS_A)
break;
case CUR :
for (i = 0; i < NJOINTS; ++i) {
mcc = chg.a_motion.vala[i];
mcc = (mcc > 0100000) ? -mcc : mcc;
if (mcc > mxdc[i]) {
goto toostrong;
}
}
STUFFA(a_motion,CUR_A)
break;
case STOP :
STUFFA(a_motion,STOPP_A);
break;
case STOPCAL :
STUFFA(a_motion,STOPM_A);
break;
default :
goto fatal;
}
CMDG(g_hand, HAND_G)
#ifdef ADC
if (chg.g_adco.set) {
++nch;
}
CMDG(g_adco, ADCO_G)
#endif
CMDG(g_rate, RATE_G)
if (chg.g_rate.set) {
rate = (1 << chg.g_rate.valg) * HARDCLOCK;
}
CMDE(stop, STOP_E)
CMDE(calib, CALIB_E)
checksum:
i = stack - (char *)(obuff + 1); /* byte count */
if (i % 2) {
i++;
*stack++ = -1;
}
if (stack > top - 2) /* room for checksum ?*/
goto fatal;
return(i); /* return byte count */
fatal :
stack = (char *)(obuff + 1);
top = (char *)(obuff + COMSIZE);
mess = "** too many commands";
terminate = YES;
goto terminated;
toofast :
stack = (char *)(obuff + 1);
terminate = YES;
mess = "** too large position increment";
goto terminated;
toofar :
stack = (char *)(obuff + 1);
terminate = YES;
mess = "** out of range";
goto terminated;
toostrong :
stack = (char *)(obuff + 1);
terminate = YES;
mess = "** too much current";
goto terminated;
}
/*
* - set up the driver
* - have the SIGINT caught to terminate interaction
* - have the SIGHUP caught on device error
*
* On IT :
* 1) The driver gets a buffer from the controller
* 2) User fn1 is called and is meant to process the arm state
* 3) Commands are put in buffer by pack
* 3) The driver sends a buffer to the controller (previous commands)
* 4) User fn2 is called and is meant to compute next command
*
* One may code any sequence of 'control-release' in the user programs
* Each of these sequence corresponds to a sequence
* 'interrupt/send state/execute commands - turn off armpower in the lsi'
*
*/
static dummy(){}
#define BAD 2
#define TOOF 3
static struct drcROBOT drcROBOT = {
(caddr_t) obuff, /* this write buffer, first word is byte cnt */
(caddr_t) &how, /* this is read buffer */
sizeof(how), /* # of bytes to read */
dummy,
dummy
};
static int fdr;
static int (* userfn1)();
static int (* userfn2)();
static int exch1 = 0;
static int exch2 = 0;
static int hang;
control(fn1, fn2) /*::*/
int (* fn1)(), (* fn2)();
{
int count;
int release();
int ondrcerr();
int onintr1();
int onintr2();
int ex;
if (active) {
terminate = YES;
mess = "** exit";
release("** channel not released");
exit(4);
}
userfn1 = fn1;
userfn2 = fn2;
drcROBOT.R_routine = onintr1;
drcROBOT.R_routine2 = onintr2;
(void) signal(SIGINT, release);
(void) signal(SIGHUP, ondrcerr);
terminate = NO;
active = YES;
mess = "";
ex = exch2 = exch1 = 0;
rate = (1 << DEFAULTRATE) * HARDCLOCK;
if ((fdr = open("/dev/drc0", 2)) < 0) {
printf("Can't open /dev/drc0 for write\n");
exit(1);
}
if ((count=write(fdr, (char *)&drcROBOT,
sizeof (struct drcROBOT))) != sizeof (struct drcROBOT)) {
printf("write error initing drcROBOT, count:%d\n", count);
exit(2);
}
printf("** channel opened, turn on ARM POWER\n");
while (exch2 == ex) {
nap(10);
}
}
adcopen(ch) /*::*/
int ch;
{
#ifdef ADC
if (!active || ch < NJOINTS || ch >= ADC || adcmap[ch] >= 0) {
return(-1);
}
chg.g_adco.set = YES;
chg.g_adco.valg = ch;
while (chg.g_adco.set) {
nap(1);
}
return(adcmap[ch] = nch - 1);
#else
return(-1);
#endif
}
static onintr1()
{
register short chks;
register short *sp;
register int i;
register short inc;
static short old[NJOINTS];
if (inserf) {
mess = "** interrupt occurred before end of user function";
terminate = TOOF;
return;
}
inserf = YES;
if (terminate == TOOF || terminate == BAD) {
inserf = NO;
return;
}
sp = (short *)how.pos;
chks = how.exio;
for (i = 0; i < NJOINTS; ++i) {
chks += *sp++;
}
#ifdef ADC
for (i = 0; i < nch; ++i) {
chks += *sp++;
}
#endif
if(*sp != chks) {
terminate = BAD;
mess = "** bad checksum";
return;
}
++exch1;
if (checking) {
#ifdef ADC
for (i = 0; i < NJOINTS; ++i) {
inc = how.adcr[i];
inc = (inc < 0) ? -inc : inc;
if (inc > mxoc[i]) {
mess = "** too large observed current";
terminate = YES;
break;
}
}
#endif
if (exch1 == 1) {
for (i = 0; i < NJOINTS; ++i) {
old[i] = how.pos[i];
}
}
else {
for (i = 0; i < NJOINTS; ++i) {
inc = how.pos[i] - old[i];
inc = (inc < 0) ? -inc : inc;
if (inc > mvl[i] * rate) {
mess = "** too large observed velocity";
terminate = YES;
break;
}
inc = old[i] = how.pos[i];
if (inc > max[i] || inc < min[i]) {
mess = "** joint(s) out of range";
terminate = YES;
break;
}
}
}
}
if (exch1 != 1) {
if (!(terminate || (hang = !(how.exio & ARMPWR)))) {
(* userfn1)(); /* process arm state */
}
*obuff = pack(); /* byte count */
i = *obuff / 2;
chks = 0;
for (sp = obuff + 1; i--;)
chks += *sp++;
*sp = chks;
*obuff += 2; /* for chks */
}
else {
obuff[0] = 4 + 4 * NJOINTS;
obuff[1] = VERSION;
obuff[2] = ARMTYPE;
for (i = 0; i < NJOINTS; ++i) {
obuff[3 + i] = ref[i];
obuff[3 + NJOINTS + i] = idx[i];
}
}
}
static onintr2()
{
if (terminate) {
inserf = NO;
return;
}
if (!hang) {
++exch2;
(* userfn2)(); /* command arm */
}
inserf = NO;
}
static ondrcerr()
{
int i;
(void) close(fdr);
printf("**** driver error...exch1 = %d exch2 = %d\n", exch1, exch2);
printf("obuff:\n");
for (i = 0; i < COMSIZE; ++i)
printf("0x%x ",obuff[i] & 0xffff);
printf("\nhow:\n");
printf("exio 0x%x\n", how.exio & 0xffff);
printf("pos:\n");
for (i = 0; i < NJOINTS; ++i)
printf("%u ",how.pos[i] & 0xffff);
#ifdef ADC
printf("\nadc :");
for (i = 0; i < nch; ++i)
printf(" 0%o\n", how.adcr[i] & 0xffff);
#endif
printf("\nterminate %d\n", terminate);
exit(3);
}
release(s)
char *s;
{
int c;
terminate = YES;
active = NO;
nap(10);
#ifdef ADC
nch = NJOINTS;
for (c = NJOINTS; c < ADC; ++c) {
adcmap[c] = -1;
}
#endif
(void) close(fdr);
if ((int)s == SIGINT) {
printf("\n** Interrupted\n");
printf("%s\n", mess);
}
else {
printf("%s\n", s);
printf("%s\n", mess);
}
printf("** exch1 = %d exch2 = %d\n", exch1, exch2);
if ((int)s == SIGINT) {
if (cbrkset) {
mode.sg_flags &= ~CBREAK;
ioctl(1, TIOCSETP, &mode);
}
printf("** attempt an automatic home return ? ");
QUERY(c);
if (c == 'y') {
home();
}
exit(1);
}
}
/*
* manual stepping mode
*/
#define GO(x ,y) printf("%c=%c%c" ,'\033' ,' '+x ,' '+y)
#define CALREQ 2
#define BS '\010'
#define CR '\015'
#define MAXMAG 100
#define HANDSTEP 10
static int enough = NO;
static int mag = 0;
static int poshd = 0;
static unsigned short ideal[NJOINTS];
static int offset[NJOINTS] = {0, 0, 0, 0, 0, 0};
stepmode() /*::*/
{
int dummy(), soft();
int c;
int sig = YES;
enough = NO;
first = YES;
checking = NO;
mag = 0;
poshd = 0;
for (c = 0; c < NJOINTS; ++c) {
offset[c] = 0;
}
if (gtty(1, &mode) < 0) {
printf("** can't gtty\n");
exit(1);
}
control(dummy, soft);
while(first) {
nap(10);
}
mode.sg_flags |= CBREAK;
ioctl(1, TIOCSETP, &mode);
cbrkset = YES;
GO(22, 0);
printf(
"faster(.) slower(,) reverse(-) joints[1-6] hand(o/c) exit(return)\n\n");
printf(
"** exit ? (y/n) _ calibrate ? (y/n) _ sure ? (y/n) _");
GO(22, 0);
printf("* ");
for (c = 0; c < 6 ; ++c) {
GO(22, ((c + 1) * 8));
printf("%6u", how.pos[c]);
}
while (!enough) {
putchar(CR);
putchar(':');
c = getchar();
putchar(BS);
switch (c) {
case '1' :
case '2' :
case '3' :
case '4' :
case '5' :
case '6' :
offset[c -= '1'] += (sig) ? mag : -mag;
GO(22, ((c + 1) * 8));
printf("%6u", how.pos[c]);
break;
#ifdef PUMA
case 'o' :
poshd = 'o';
break;
case 'c' :
poshd = 'c';
break;
#endif
#ifdef STAN
case 'o' :
poshd += HANDSTEP;
break;
case 'c' :
poshd -= HANDSTEP;
break;
#endif
case '.' :
(mag < MAXMAG) ? ++mag : mag;
break;
case ',' :
(mag) ? --mag : mag;
break;
case '-' :
sig = !sig;
break;
case '\n' :
printf("** exit ? (y/n) ");
if (getchar() == 'y') {
printf(" calibrate ? (y/n) ");
if (getchar() == 'y') {
printf(" sure ? (y/n) ");
if (getchar() == 'y') {
chg.calib = YES;
enough = CALREQ;
nap(20);
}
else {
GO(22, 0);
}
}
else {
printf(" sure ? (y/n) ");
if (getchar() == 'y') {
enough = YES;
}
else {
GO(22, 0);
}
}
}
else {
GO(22, 1);
}
break;
default :
break;
}
}
mode.sg_flags &= ~CBREAK;
ioctl(1, TIOCSETP, &mode);
cbrkset = NO;
release("\n** end of step mode");
checking = YES;
if (enough == CALREQ) {
printf("** calibrating\n");
sleep(5);
}
}
static soft()
{
register int i;
if (enough) {
return;
}
if (first) {
first = NO;
for (i = 0; i < NJOINTS; ++i) {
ideal[i] = how.pos[i];
}
}
for (i = 0; i < NJOINTS; ++i) {
if (how.pos[i] <= MAXMAG) {
ideal[i] = chg.i_motion[i].vali = 077777;
chg.i_motion[i].set = STOPCAL;
}
if (how.pos[i] >= 65535-MAXMAG) {
ideal[i] = chg.i_motion[i].vali = 077777;
chg.i_motion[i].set = STOPCAL;
}
if (offset[i] > 0) {
offset[i] -= mag;
ideal[i] -= mag;
}
if (offset[i] < 0) {
offset[i] += mag;
ideal[i] += mag;
}
chg.a_motion.vala[i] = ideal[i];
}
chg.a_motion.set = POS;
chg.g_hand.valg = poshd;
chg.g_hand.set = YES;
}
/*
* Automatic home position return
*/
#define SMALL 100
#define STABTIM 50
static home()
{
int dummy(), back();
first = YES;
checking = NO;
printf("** attempting a home return\n");
control(dummy, back);
while (!terminate) {
nap(10);
}
nap(10);
(void) close(fdr);
printf("** back home, calibrated\n");
checking = YES;
nap(10);
}
static back()
{
extern struct how how;
extern struct chg chg;
extern int terminate;
static int finish;
static int count;
static unsigned short where[NJOINTS],
inc[NJOINTS],
half[NJOINTS],
done[NJOINTS];
register int i;
if (first) {
first = NO;
for (i = 0; i < NJOINTS; ++i) {
where[i] = how.pos[i];
if (where[i] > ref[i]) {
half[i] = (where[i] - ref[i]) / 2 + ref[i];
half[i] -= SMALL;
}
else {
half[i] = ref[i] - (ref[i] - where[i]) / 2;
half[i] += SMALL;
}
finish = NO;
count = STABTIM;
inc[i] = 0;
}
}
if (!finish) {
for (i = 0, finish = YES; i < NJOINTS; ++i) {
if (where[i] > ref[i]) {
done[i] = where[i] - ref[i] < SMALL;
}
else {
done[i] = ref[i] - where[i] < SMALL;
}
if (!done[i]) {
finish = NO;
}
}
}
else {
if (--count == 0) {
terminate = YES;
}
}
for (i = 0; i < NJOINTS; ++i) {
if (!done[i]) {
if (where[i] > ref[i]) {
if (where[i] > half[i]) {
--inc[i];
}
else {
++inc[i];
}
}
if (where[i] < ref[i]) {
if (where[i] < half[i]) {
++inc[i];
}
else {
--inc[i];
}
}
}
else {
where[i] = ref[i];
}
where[i] += inc[i];
chg.a_motion.vala[i] = where[i];
}
chg.a_motion.set = POS;
}