/* ************************************************************** */ /* * Module MC4 * This module contains I/O functions for the Klinger model * MC-4 indexer. * * Zachary Wolf * 7/23/99 */ /* ************************************************************** */ /* INCLUDES */ #include #include #include #include #include "mc4.h" /* ************************************************************** */ /* PRIVATE FUNCTIONS */ int mc4_open_dev(int gpib_board_addr, int gpib_dev_addr); void mc4_close_dev(int dev_ID); int mc4_out(int dev_ID, char *buf); int mc4_in(int dev_ID, char* buf); int mc4_check_dev_open(int dev_ID); int mc4_check_errors(int dev_ID); void mc4_hold_until_move_complete(int dev_ID); int mc4_serial_poll(int dev_ID, int* spoll); void mc4_message(char* msg); void mc4_error(char* msg); /* ************************************************************** */ /* PRIVATE DEVICE TABLE */ /* * This table allows several devices of the same type to be * used in the system. * dev_addr, contains the GPIB addresses of opened devices * dev_descr, contains the device descriptors of opened devices * dev_count, contains the number of devices open of this type */ static int dev_addr[MC4_MAX_NUM_DEV + 1]; static int dev_descr[MC4_MAX_NUM_DEV + 1]; static int dev_count; /* ************************************************************** */ /* PRIVATE GLOBAL VARIABLES */ /* * cmd, buffer for GPIB I/O strings * msg, buffer for message strings to Standard I/O */ static char cmd[MC4_MAX_CMD + 1]; static char msg[MC4_MAX_CMD + 1]; /* ************************************************************** */ /* PUBLIC FUNCTIONS */ /* ************************************************************** */ /* * mc4_init * This function opens the device, queries for ID, and * initializes the device to a known state. * * Input: * gpib_board_addr, address of the GPIB board the device is connected to (0, 1, ...) * gpib_dev_addr, GPIB address of the device (1 to 30, 0 is reserved) * * Output: * ID, identifier for future references to the device * * Zachary Wolf * 7/23/99 */ void mc4_init(int gpib_board_addr, int gpib_dev_addr, int* ID) { /* Declare variables */ int dev_ID; int err; /* Message */ mc4_message(""); mc4_message("Initializing the MC4..."); /* Check input parameters */ if (gpib_board_addr < 0 || gpib_board_addr > 10) { Fmt(msg, "%s 30) { Fmt(msg, "%s MC4_MAX_NUM_DEV) { Fmt(msg, "%s 2.) { Fmt(msg, "%s 4000.) { Fmt(msg, "%s 7999999) { Fmt(msg, "%s 0.) rot_dir = '+'; else rot_dir = '-'; Fmt(cmd, "%s<%c%c", rot_dir, axis); mc4_out(dev_ID, cmd); /* Enable holding torque */ Fmt(cmd, "%s 3. / MC4_NUM_STEPS_PER_REV) mc4_error("mc4_rel_motor_move: the motor did not move the proper amount"); /* Done */ return; } /* ************************************************************** */ /* * mc4_rel_stage_move * This function moves a stage a specified distance relative to * its present position. The acceleration and velocity are specified. * * Input: * dev_ID, device identifier * axis, axis to move (W, X, Y, or Z) * acc, acceleration (m/sec/sec) * vel, velocity (m/sec) * dis, distance (m), can be + or - * * Zachary Wolf * 7/23/99 */ void mc4_rel_stage_move(int dev_ID, char axis, double acc, double vel, double dis) { /* Declare variables */ double acc_ang, vel_ang, dis_ang; double ini_pos, fin_pos; /* Calculate motor rotation parameters from the input parameters */ acc_ang = acc * MC4_NUM_REV_PER_METER; vel_ang = vel * MC4_NUM_REV_PER_METER; dis_ang = dis * MC4_NUM_REV_PER_METER; /* Exit here if testing without hardware */ #ifdef DUMMY_DEVICES return; #endif /* Get the initial stage position before the move */ mc4_get_stage_pos(dev_ID, axis, &ini_pos); /* Move the stage */ mc4_rel_motor_move(dev_ID, axis, acc_ang, vel_ang, dis_ang); /* Get the stage position after the move */ mc4_get_stage_pos(dev_ID, axis, &fin_pos); /* Check the move */ if (fabs(fin_pos - ini_pos - dis) > 3. / (MC4_NUM_STEPS_PER_REV * MC4_NUM_REV_PER_METER)) mc4_error("mc4_rel_stage_move: the stage did not move the proper amount"); /* Done */ return; } /* ************************************************************** */ /* * mc4_rel_2_motor_move * This function moves two motors simultaneously a given number of revolutions relative to * their present position. The acceleration and velocity are specified. * * Input: * dev_ID, device identifier * axis1, axis 1 to move (W, X, Y, or Z) * axis2, axis 2 to move (W, X, Y, or Z) * acc, acceleration (rev/sec/sec) * vel, velocity (rev/sec) * dis, distance (rev), can be + or - * * Zachary Wolf * 8/2/99 */ void mc4_rel_2_motor_move(int dev_ID, char axis1, char axis2, double acc, double vel, double dis) { /* Declare variables */ int err; int dev_open; double acc_time; double step_rate; double num_steps; char rot_dir; double ini_pos1, fin_pos1; double ini_pos2, fin_pos2; /* Check input parameters */ if (dev_ID < 1 || dev_ID > MC4_MAX_NUM_DEV) { Fmt(msg, "%s 2.) { Fmt(msg, "%s 4000.) { Fmt(msg, "%s 7999999) { Fmt(msg, "%s 0.) rot_dir = '+'; else rot_dir = '-'; Fmt(cmd, "%s<%c%c", rot_dir, axis1); mc4_out(dev_ID, cmd); Fmt(cmd, "%s<%c%c", rot_dir, axis2); mc4_out(dev_ID, cmd); /* Enable holding torque */ Fmt(cmd, "%s", axis1, axis2); mc4_out(dev_ID, cmd); /* Wait unil the move is complete */ Delay(fabs(dis)/vel + 2*vel/acc); mc4_hold_until_move_complete(dev_ID); /* Check for errors */ mc4_check_errors(dev_ID); /* Get the motor positions after the move */ mc4_get_motor_pos(dev_ID, axis1, &fin_pos1); mc4_get_motor_pos(dev_ID, axis2, &fin_pos2); /* Check the move */ if (fabs(fin_pos1 - ini_pos1 - dis) > 3. / MC4_NUM_STEPS_PER_REV) mc4_error("mc4_rel_2_motor_move: motor 1 did not move the proper amount"); if (fabs(fin_pos2 - ini_pos2 - dis) > 3. / MC4_NUM_STEPS_PER_REV) mc4_error("mc4_rel_2_motor_move: motor 2 did not move the proper amount"); /* Done */ return; } /* ************************************************************** */ /* * mc4_rel_2_stage_move * This function moves two stages a specified distance relative to * their present position. The acceleration and velocity are specified. * * Input: * dev_ID, device identifier * axis1, axis 1 to move (W, X, Y, or Z) * axis2, axis 2 to move (W, X, Y, or Z) * acc, acceleration (m/sec/sec) * vel, velocity (m/sec) * dis, distance (m), can be + or - * * Zachary Wolf * 7/23/99 */ void mc4_rel_2_stage_move(int dev_ID, char axis1, char axis2, double acc, double vel, double dis) { /* Declare variables */ double acc_ang, vel_ang, dis_ang; double ini_pos1, fin_pos1; double ini_pos2, fin_pos2; /* Calculate motor rotation parameters from the input parameters */ acc_ang = acc * MC4_NUM_REV_PER_METER; vel_ang = vel * MC4_NUM_REV_PER_METER; dis_ang = dis * MC4_NUM_REV_PER_METER; /* Exit here if testing without hardware */ #ifdef DUMMY_DEVICES return; #endif /* Get the initial stage positions before the move */ mc4_get_stage_pos(dev_ID, axis1, &ini_pos1); mc4_get_stage_pos(dev_ID, axis2, &ini_pos2); /* Move the stage */ mc4_rel_2_motor_move(dev_ID, axis1, axis2, acc_ang, vel_ang, dis_ang); /* Get the stage positions after the move */ mc4_get_stage_pos(dev_ID, axis1, &fin_pos1); mc4_get_stage_pos(dev_ID, axis2, &fin_pos2); /* Check the move */ if (fabs(fin_pos1 - ini_pos1 - dis) > 3. / (MC4_NUM_STEPS_PER_REV * MC4_NUM_REV_PER_METER)) mc4_error("mc4_rel_2_stage_move: stage 1 did not move the proper amount"); if (fabs(fin_pos2 - ini_pos2 - dis) > 3. / (MC4_NUM_STEPS_PER_REV * MC4_NUM_REV_PER_METER)) mc4_error("mc4_rel_2_stage_move: stage 2 did not move the proper amount"); /* Done */ return; } /* ************************************************************** */ /* * mc4_rel_2_stage_move_time_critical * This function does the setup for two stages to move a specified * distance relative to their present position. * The acceleration and velocity are specified. * * Input: * dev_ID, device identifier * axis1, axis 1 to move (W, X, Y, or Z) * axis2, axis 2 to move (W, X, Y, or Z) * acc, acceleration (m/sec/sec) * vel, velocity (m/sec) * dis, distance (m), can be + or - * * Zachary Wolf * 7/23/99 */ void mc4_rel_2_stage_move_time_critical(int dev_ID, char axis1, char axis2, double acc, double vel, double dis) { /* Declare variables */ int err; int dev_open; double acc_time; double step_rate; double num_steps; char rot_dir; double ini_pos1, fin_pos1; double ini_pos2, fin_pos2; /* Check input parameters */ if (dev_ID < 1 || dev_ID > MC4_MAX_NUM_DEV) { Fmt(msg, "%s 2.) { Fmt(msg, "%s 4000.) { Fmt(msg, "%s 7999999) { Fmt(msg, "%s 0.) rot_dir = '+'; else rot_dir = '-'; Fmt(cmd, "%s<%c%c", rot_dir, axis1); mc4_out(dev_ID, cmd); Fmt(cmd, "%s<%c%c", rot_dir, axis2); mc4_out(dev_ID, cmd); /* Enable holding torque */ Fmt(cmd, "%s", axis1, axis2); mc4_out(dev_ID, cmd); /* Wait unil the move is complete */ Delay(fabs(dis)/vel + 2*vel/acc); mc4_hold_until_move_complete(dev_ID); /* Check for errors */ mc4_check_errors(dev_ID); /* Get the motor positions after the move */ mc4_get_motor_pos(dev_ID, axis1, &fin_pos1); mc4_get_motor_pos(dev_ID, axis2, &fin_pos2); /* Check the move */ if (fabs(fin_pos1 - ini_pos1 - dis * MC4_NUM_REV_PER_METER) > 3. / MC4_NUM_STEPS_PER_REV) mc4_error("mc4_rel_2_motor_move: motor 1 did not move the proper amount"); if (fabs(fin_pos2 - ini_pos2 - dis * MC4_NUM_REV_PER_METER) > 3. / MC4_NUM_STEPS_PER_REV) mc4_error("mc4_rel_2_motor_move: motor 2 did not move the proper amount"); /* Done */ return; } /* ************************************************************** */ /* * mc4_abs_motor_move * This function moves a motor to a given position. * The acceleration and velocity are specified. * * Input: * dev_ID, device identifier * axis, axis to move (W, X, Y, or Z) * acc, acceleration (rev/sec/sec) * vel, velocity (rev/sec) * pos, position (rev), can be + or - * * Zachary Wolf * 8/2/99 */ void mc4_abs_motor_move(int dev_ID, char axis, double acc, double vel, double pos) { /* Declare variables */ int err; int dev_open; double acc_time; double step_rate; double pos_steps; double fin_pos; double ini_pos; /* Check input parameters */ if (dev_ID < 1 || dev_ID > MC4_MAX_NUM_DEV) { Fmt(msg, "%s 2.) { Fmt(msg, "%s 4000.) { Fmt(msg, "%s 7999999) { Fmt(msg, "%s 3. / MC4_NUM_STEPS_PER_REV) mc4_error("mc4_abs_motor_move: the motor did not move to the proper position"); /* Done */ return; } /* ************************************************************** */ /* * mc4_abs_stage_move * This function moves a stage to a specified position. * The acceleration and velocity are specified. * * Input: * dev_ID, device identifier * axis, axis to move (W, X, Y, or Z) * acc, acceleration (m/sec/sec) * vel, velocity (m/sec) * pos, position (m), can be + or - * * Zachary Wolf * 8/2/99 */ void mc4_abs_stage_move(int dev_ID, char axis, double acc, double vel, double pos) { /* Declare variables */ double acc_ang, vel_ang, pos_ang; double fin_pos; /* Calculate motor rotation parameters from the input parameters */ acc_ang = acc * MC4_NUM_REV_PER_METER; vel_ang = vel * MC4_NUM_REV_PER_METER; pos_ang = pos * MC4_NUM_REV_PER_METER; /* Exit here if testing without hardware */ #ifdef DUMMY_DEVICES return; #endif /* Move the stage */ mc4_abs_motor_move(dev_ID, axis, acc_ang, vel_ang, pos_ang); /* Get the stage position after the move */ mc4_get_stage_pos(dev_ID, axis, &fin_pos); /* Check the move */ if (fabs(fin_pos - pos) > 3. / (MC4_NUM_STEPS_PER_REV * MC4_NUM_REV_PER_METER)) mc4_error("mc4_abs_stage_move: the stage did not move to the proper position"); /* Done */ return; } /* ************************************************************** */ /* * mc4_abs_2_motor_move * This function moves two motors simultaneously to a given position. * The acceleration and velocity are specified. * Actually, all motors are moved since two motors can not be positioned * simultaneously ( doesn't work). The two axes specified are * checked to make sure they went to the proper position. * * Input: * dev_ID, device identifier * axis1, axis 1 to move (W, X, Y, or Z) * axis2, axis 2 to move (W, X, Y, or Z) * acc, acceleration (rev/sec/sec) * vel, velocity (rev/sec) * pos, position (rev), can be + or - * * Zachary Wolf * 8/2/99 */ void mc4_abs_2_motor_move(int dev_ID, char axis1, char axis2, double acc, double vel, double pos) { /* Declare variables */ int err; int dev_open; double acc_time; double step_rate; double pos_steps; double fin_pos1, fin_pos2; double ini_pos1, ini_pos2; /* Check input parameters */ if (dev_ID < 1 || dev_ID > MC4_MAX_NUM_DEV) { Fmt(msg, "%s 2.) { Fmt(msg, "%s 4000.) { Fmt(msg, "%s 7999999) { Fmt(msg, "%s 3. / MC4_NUM_STEPS_PER_REV) mc4_error("mc4_abs_2_motor_move: motor 1 did not move to the proper position"); if (fabs(fin_pos2 - pos) > 3. / MC4_NUM_STEPS_PER_REV) mc4_error("mc4_abs_2_motor_move: motor 2 did not move to the proper position"); /* Done */ return; } /* ************************************************************** */ /* * mc4_abs_2_stage_move * This function moves two stages to a specified position. * The acceleration and velocity are specified. * * Input: * dev_ID, device identifier * axis1, axis 1 to move (W, X, Y, or Z) * axis2, axis 2 to move (W, X, Y, or Z) * acc, acceleration (m/sec/sec) * vel, velocity (m/sec) * pos, position (m), can be + or - * * Zachary Wolf * 8/2/99 */ void mc4_abs_2_stage_move(int dev_ID, char axis1, char axis2, double acc, double vel, double pos) { /* Declare variables */ double acc_ang, vel_ang, pos_ang; double fin_pos1, fin_pos2; /* Calculate motor rotation parameters from the input parameters */ acc_ang = acc * MC4_NUM_REV_PER_METER; vel_ang = vel * MC4_NUM_REV_PER_METER; pos_ang = pos * MC4_NUM_REV_PER_METER; /* Exit here if testing without hardware */ #ifdef DUMMY_DEVICES return; #endif /* Move the stage */ mc4_abs_2_motor_move(dev_ID, axis1, axis2, acc_ang, vel_ang, pos_ang); /* Get the stage positions after the move */ mc4_get_stage_pos(dev_ID, axis1, &fin_pos1); mc4_get_stage_pos(dev_ID, axis2, &fin_pos2); /* Check the move */ if (fabs(fin_pos1 - pos) > 3. / (MC4_NUM_STEPS_PER_REV * MC4_NUM_REV_PER_METER)) mc4_error("mc4_abs_2_stage_move: stage 1 did not move to the proper position"); if (fabs(fin_pos2 - pos) > 3. / (MC4_NUM_STEPS_PER_REV * MC4_NUM_REV_PER_METER)) mc4_error("mc4_abs_2_stage_move: stage 2 did not move to the proper position"); /* Done */ return; } /* ************************************************************** */ /* * mc4_zero * This function sets the indexer position counter to zero. * * Input: * dev_ID, device identifier * * Zachary Wolf * 8/3/99 */ void mc4_zero(int dev_ID) { /* Declare variables */ int err; int dev_open; /* Check input parameters */ if (dev_ID < 1 || dev_ID > MC4_MAX_NUM_DEV) { Fmt(msg, "%s MC4_MAX_NUM_DEV) { Fmt(msg, "%s%c=%f", &msg_axis, &num_steps); if (err != 2) mc4_error("MC4: Could not read axis position"); if (msg_axis != axis) mc4_error("MC4: Could not read axis position"); /* Convert from steps to revolutions */ *pos = num_steps / MC4_NUM_STEPS_PER_REV; /* Check for errors */ mc4_check_errors(dev_ID); /* Done */ return; } /* ************************************************************** */ /* * mc4_get_stage_pos * This function gets the position of the specified stage. * * Input: * dev_ID, device identifier * axis, axis name identifying motor (W, X, Y, or Z) * * Output: * pos, stage position (m) * * Zachary Wolf * 8/3/99 */ void mc4_get_stage_pos(int dev_ID, char axis, double* pos) { /* Declare variables */ double ang_pos; /* Exit here if testing without hardware */ #ifdef DUMMY_DEVICES *pos = 0.; return; #endif /* Get the motor position */ mc4_get_motor_pos(dev_ID, axis, &ang_pos); /* Calculate the stage position */ *pos = ang_pos / MC4_NUM_REV_PER_METER; /* Done */ return; } /* ************************************************************** */ /* * mc4_exit * This function prepares the MC4 for shutdown and closes * the device. * * Input: * dev_ID, device identifier * * Zachary Wolf * 8/3/99 */ void mc4_exit(int dev_ID) { /* Declare variables */ int err; int dev_open; /* Check input parameters */ if (dev_ID < 1 || dev_ID > MC4_MAX_NUM_DEV) { Fmt(msg, "%s 10) { Fmt(msg, "%s 30) { Fmt(msg, "%s%s[t-]", buf); /* Done */ return 0; } /* ************************************************************** */ /* * mc4_check_dev_open * This function checks to see if the specified device is open. * If the device has been opened, a 1 is returned, 0 otherwise. * * Input: * dev_ID, device identifier * * Output: * status, 1 if device is open, 0 otherwise * * Zachary Wolf * 7/27/98 */ int mc4_check_dev_open(int dev_ID) { /* See if the device descriptor has a positive value */ if (dev_descr[dev_ID] > 0) { return 1; /* Open */ } else { return 0; /* Not open */ } } /* ************************************************************** */ /* * mc4_check_errors * This function checks for device errors. * The operator is alerted if there is an error. * * Input: * dev_ID, device identifier * * Output: * err, 0 if no errors, -1 otherwise * * Zachary Wolf * 8/3/99 */ int mc4_check_errors(int dev_ID) { /* Declare variables */ char err_msg[MC4_MAX_CMD + 1]; int spoll; /* Get the output buffer contents to look for an error message */ mc4_in(dev_ID, err_msg); /* Check for problems */ if (err_msg[0] == 'E') { mc4_error(err_msg); return -1; } /* Perform a serial poll to see if a stage is at its limit */ mc4_serial_poll(dev_ID, &spoll); /* Check for problems */ if ((spoll & 16) == 16) { mc4_error("Stage at limit"); return -1; } /* Done */ return 0; } /* ************************************************************** */ /* * mc4_serial_poll * This function performs a serial poll of the device. * * Input: * dev_ID, device identifier * * Output: * spoll, contents of the serial poll register * err, 0 if ok, -1 otherwise * * Zachary Wolf * 8/26/98 */ int mc4_serial_poll(int dev_ID, int* spoll) { /* Declare variables */ int err; char spoll_char; /* Perform the serial poll */ err = ibrsp(dev_descr[dev_ID], &spoll_char); /* Check for errors */ if (err & 0x8000) { Fmt(msg, "%s%i", spoll); /* Debug */ /* printf("%i\n", *spoll); */ /* Done */ return 0; } /* ************************************************************** */ /* * mc4_hold_until_move_complete * This function loops until all axes have stopped moving. * The command "FS01" must have been previously issued so that * the moving status is returned. * * Input: * dev_ID, device identifier * * Zachary Wolf * 8/3/99 */ void mc4_hold_until_move_complete(int dev_ID) { /* Declare variables */ char status[MC4_MAX_CMD + 1]; enum {TRUE, FALSE} moving; /* Loop while moving */ moving = TRUE; while (moving == TRUE) { mc4_in(dev_ID, status); //printf("moving status: %s\n", status); if (status[0] != '0') return; /* Move complete */ if ((int) status[1] == 0x40) { moving = FALSE; /* Move complete */ } else { moving = TRUE; /* Still moving */ Delay(1.); } } /* Done */ return; } /* ************************************************************** */ /* * mc4_message * This function handles messages about the MC4. * * Input: * message, string to display in standard I/O * * Zachary Wolf * 8/3/98 */ void mc4_message(char* message) { /* Print the message */ printf("%s\n", message); /* Done */ return; } /* ************************************************************** */ /* * mc4_error * This function handles error messages for the MC4. * * Input: * message, string to display in standard I/O * * Zachary Wolf * 8/3/98 */ void mc4_error(char* message) { /* Declare variables */ char buf[80]; /* Notify the operator of the error */ printf("\nMC4 ERROR: %s\n", message); Beep(); Delay(.5); Beep(); /* Terminate the program if the operator desires */ printf("Press ENTER to continue.\nPress any key then ENTER to terminate program.\n"); fgets(buf, 80, stdin); if (buf[0] == '\n') return; else exit(0); }