/* ************************************************************** */ /* * Module CM4000 * This module contains I/O functions for the Compumotor model * 4000 indexer. * * Zachary Wolf * 9/4/02 */ /* ************************************************************** */ /* INCLUDES */ #include #include #include #include #include "cm4000.h" /* ************************************************************** */ /* PRIVATE FUNCTIONS */ int cm4000_open_dev(int gpib_board_addr, int gpib_dev_addr); void cm4000_close_dev(int dev_ID); int cm4000_out(int dev_ID, char *buf); int cm4000_in(int dev_ID, char* buf); int cm4000_check_dev_open(int dev_ID); int cm4000_read_error_status(int dev_ID); void cm4000_hold_until_ready_to_reply(int dev_ID); int cm4000_serial_poll(int dev_ID, int* spoll); void cm4000_get_num_mot_steps_per_rev(int axis, long int* num_steps_per_rev); void cm4000_get_num_enc_steps_per_rev(int axis, long int* num_steps_per_rev); void cm4000_get_motor_resolution_code(int axis, int* mr); void cm4000_message(char* msg); void cm4000_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[CM4000_MAX_NUM_DEV + 1]; static int dev_descr[CM4000_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[CM4000_MAX_CMD + 1]; static char msg[CM4000_MAX_CMD + 1]; /* ************************************************************** */ /* PUBLIC FUNCTIONS */ /* ************************************************************** */ /* * cm4000_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 * 9/4/02 */ void cm4000_init(int gpib_board_addr, int gpib_dev_addr, int* ID) { /* Declare variables */ int dev_ID; int err; int mr; int axis; /* Message */ cm4000_message(""); cm4000_message("Initializing the CM4000..."); /* Check input parameters */ if (gpib_board_addr < 0 || gpib_board_addr > 10) { Fmt(msg, "%s 30) { Fmt(msg, "%s CM4000_MAX_NUM_DEV) { Fmt(msg, "%s 4) { Fmt(msg, "%s 999.999) { Fmt(msg, "%s 99.) { Fmt(msg, "%s 99999999) { Fmt(msg, "%s%i:%i", &reply_axis, &steps_taken); /* Debug */ //printf("cmd = %s\n", cmd); //printf("steps_requested = %i, steps_taken = %i\n", dis_steps, steps_taken); /* Make sure the proper number of steps were taken */ if (reply_axis != axis) { cm4000_error("The wrong axis number was returned"); return; } if (steps_taken != dis_steps) { cm4000_error("The wrong number of steps were taken"); return; } /* Done */ return; } /* ************************************************************** */ /* * cm4000_start_rel_move * This function starts a move of the motor. It moves the * specified number of revolutions with the specified acceleration * and velocity. * * Input: * dev_ID, device identifier * axis, axis number to move (1 to 4) * acc, acceleration (rev/sec/sec) * vel, velocity (rev/sec) * dis, distance (rev), can be + or - * * Zachary Wolf * 9/9/02 */ void cm4000_start_rel_move(int dev_ID, int axis, double acc, double vel, double dis) { /* Declare variables */ long int num_steps_per_rev; int dev_open; long int dis_steps; /* Convert distance in revolutions to distance in steps */ cm4000_get_num_mot_steps_per_rev(axis, &num_steps_per_rev); dis_steps = dis * num_steps_per_rev; /* Check input parameters */ if (dev_ID < 1 || dev_ID > CM4000_MAX_NUM_DEV) { Fmt(msg, "%s 4) { Fmt(msg, "%s 999.999) { Fmt(msg, "%s 99.) { Fmt(msg, "%s 99999999) { Fmt(msg, "%s CM4000_MAX_NUM_DEV) { Fmt(msg, "%s 4) { Fmt(msg, "%s 99999999) { Fmt(msg, "%s%i:%i", &reply_axis, &steps_taken); /* Debug */ //printf("cmd = %s\n", cmd); //printf("steps_requested = %i, steps_taken = %i\n", dis_steps, steps_taken); /* Make sure the proper number of steps were taken */ if (reply_axis != axis) { cm4000_error("The wrong axis number was returned"); return; } if (steps_taken != dis_steps) { cm4000_error("The wrong number of steps were taken"); return; } /* Done */ return; } /* ************************************************************** */ /* * cm4000_abs_move * This function moves the motor to the specified location * with the specified acceleration and velocity. * * Input: * dev_ID, device identifier * axis, number of the axis to move (1 to 4) * acc, acceleration (rev/sec/sec) * vel, velocity (rev/sec) * pos, position (rev), can be + or - * * Zachary Wolf * 9/4/02 */ void cm4000_abs_move(int dev_ID, int axis, double acc, double vel, double pos) { /* Declare variables */ long int num_steps_per_rev; int dev_open; long int pos_steps; long int fin_pos; int reply_axis; /* Convert position in revolutions to position in steps */ cm4000_get_num_mot_steps_per_rev(axis, &num_steps_per_rev); pos_steps = pos * num_steps_per_rev; /* Check input parameters */ if (dev_ID < 1 || dev_ID > CM4000_MAX_NUM_DEV) { Fmt(msg, "%s 4) { Fmt(msg, "%s 999.999) { Fmt(msg, "%s 99.) { Fmt(msg, "%s 99999999) { Fmt(msg, "%s%i:%i", &reply_axis, &fin_pos); /* Debug */ //printf("cmd = %s\n", cmd); //printf("position_requested = %i, final_position = %i\n", pos_steps, fin_pos); /* Make sure the proper position was achieved */ if (reply_axis != axis) { cm4000_error("The wrong axis number was returned"); return; } if (fin_pos != pos_steps) { cm4000_error("The wrong number of steps were taken"); return; } /* Done */ return; } /* ************************************************************** */ /* * cm4000_go_home * This function moves the motor home position. The velocity * and acceleration are specified. * * Input: * dev_ID, device identifier * axis, number of the axis to move (1 to 4) * acc, acceleration (rev/sec/sec) * vel, velocity (rev/sec) * * Zachary Wolf * 9/4/02 */ void cm4000_go_home(int dev_ID, int axis, double acc, double vel) { /* Declare variables */ int dev_open; int reply_axis; long int fin_pos; /* Check input parameters */ if (dev_ID < 1 || dev_ID > CM4000_MAX_NUM_DEV) { Fmt(msg, "%s 4) { Fmt(msg, "%s 999.999) { Fmt(msg, "%s 20.) { Fmt(msg, "%s%i:%i", &reply_axis, &fin_pos); /* Debug */ //printf("cmd = %s\n", cmd); //printf("position_requested = %i, final_position = %i\n", pos_steps, fin_pos); /* Check */ if (reply_axis != axis) { cm4000_error("The wrong axis number was returned"); return; } /* Done */ return; } /* ************************************************************** */ /* * cm4000_get_mot_position * This function gets the number of revolutions from zero that * the motor is currently at. * * Input: * dev_ID, device identifier * axis, axis number (1 to 4) * * Output: * pos, position (rev), can be + or - * * Zachary Wolf * 9/9/02 */ void cm4000_get_mot_position(int dev_ID, int axis, double* pos) { /* Declare variables */ int dev_open; long int pos_steps; long int num_steps_per_rev; int reply_axis; /* Check input parameters */ if (dev_ID < 1 || dev_ID > CM4000_MAX_NUM_DEV) { Fmt(msg, "%s 4) { Fmt(msg, "%s%i:%i", &reply_axis, &pos_steps); /* Check */ if (reply_axis != axis) { cm4000_error("The wrong axis number was returned"); return; } /* Convert the position in steps to position in revolutions */ cm4000_get_num_mot_steps_per_rev(axis, &num_steps_per_rev); *pos = (double) pos_steps / (double) num_steps_per_rev; /* Done */ return; } /* ************************************************************** */ /* * cm4000_get_enc_position * This function gets the number of revolutions from zero that * the encoder is currently at. * * Input: * dev_ID, device identifier * axis, axis number (1 to 4) * * Output: * pos, position (rev), can be + or - * * Zachary Wolf * 9/9/02 */ void cm4000_get_enc_position(int dev_ID, int axis, double* pos) { /* Declare variables */ int dev_open; long int pos_steps; long int num_steps_per_rev; int reply_axis; /* Check input parameters */ if (dev_ID < 1 || dev_ID > CM4000_MAX_NUM_DEV) { Fmt(msg, "%s 4) { Fmt(msg, "%s%i:%i", &reply_axis, &pos_steps); /* Check */ if (reply_axis != axis) { cm4000_error("The wrong axis number was returned"); return; } /* Convert the position in steps to position in revolutions */ /* Four encoder transitions make one step */ cm4000_get_num_enc_steps_per_rev(axis, &num_steps_per_rev); *pos = (double) pos_steps / (double)4 / (double) num_steps_per_rev; /* Done */ return; } /* ************************************************************** */ /* * cm4000_zero * This function sets the indexer position counter to zero. * * Input: * dev_ID, device identifier * axis, axis number (1 to 4) * * Zachary Wolf * 8/25/98 */ void cm4000_zero(int dev_ID, int axis) { /* Declare variables */ int err; int dev_open; /* Check input parameters */ if (dev_ID < 1 || dev_ID > CM4000_MAX_NUM_DEV) { Fmt(msg, "%s 4) { Fmt(msg, "%s CM4000_MAX_NUM_DEV) { Fmt(msg, "%s 10) { Fmt(msg, "%s 30) { Fmt(msg, "%s%s[t-]", buf); /* Done */ return 0; } /* ************************************************************** */ /* * cm4000_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 cm4000_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 */ } } /* ************************************************************** */ /* * cm4000_read_error_status * This function obtains 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 * 9/9/02 */ int cm4000_read_error_status(int dev_ID) { /* Declare variables */ int axis; int reply_axis; char status[CM4000_MAX_CMD]; /* Request the controller status */ for (axis = 1; axis <= 4; axis++) { Fmt(cmd, "%s<%i[w1]R", axis); cm4000_out(dev_ID, cmd); cm4000_hold_until_ready_to_reply(dev_ID); cm4000_in(dev_ID, cmd); Scan(cmd, "%s>%i:%s", &reply_axis, status); if (strcmp(status, "*S") == 0 || strcmp(status, "*C") == 0) { cm4000_error("Controller error"); return -1; } } /* Done */ return 0; } /* ************************************************************** */ /* * cm4000_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 * 9/9/02 */ int cm4000_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; } /* ************************************************************** */ /* * cm4000_hold_until_ready_to_reply * This function serial polls the device in a loop until the * ready to reply bit is set. * * Input: * dev_ID, device identifier * * Zachary Wolf * 9/9/02 */ void cm4000_hold_until_ready_to_reply(int dev_ID) { /* Declare variables */ int spoll; enum {TRUE, FALSE} busy; /* Loop while busy */ busy = TRUE; while (busy == TRUE) { cm4000_serial_poll(dev_ID, &spoll); if ((spoll & 32) == 32) { busy = FALSE; /* Ready to reply */ } else { busy = TRUE; /* Not ready to reply */ Delay(.1); } } /* Done */ return; } /* ************************************************************** */ /* * cm4000_get_num_mot_steps_per_rev * This function gets the motor's number of steps per revolution. * * Input: * axis, axis number (1 to 4) * * Output: * num_steps_per_rev, number of steps per revolution * * Zachary Wolf * 9/9/02 */ void cm4000_get_num_mot_steps_per_rev(int axis, long int* num_steps_per_rev) { /* Determine the number of steps per revolutuon */ if (axis == 1) *num_steps_per_rev = CM4000_NUM_MOT_STEPS_PER_REV_AXIS1; else if (axis == 2) *num_steps_per_rev = CM4000_NUM_MOT_STEPS_PER_REV_AXIS1; else if (axis == 3) *num_steps_per_rev = CM4000_NUM_MOT_STEPS_PER_REV_AXIS3; else if (axis == 4) *num_steps_per_rev = CM4000_NUM_MOT_STEPS_PER_REV_AXIS4; else cm4000_error("Unknown axis number"); /* Done */ return; } /* ************************************************************** */ /* * cm4000_get_num_enc_steps_per_rev * This function gets the encoder's number of steps per revolution. * * Input: * axis, axis number (1 to 4) * * Output: * num_steps_per_rev, number of steps per revolution * * Zachary Wolf * 9/9/02 */ void cm4000_get_num_enc_steps_per_rev(int axis, long int* num_steps_per_rev) { /* Determine the number of steps per revolutuon */ if (axis == 1) *num_steps_per_rev = CM4000_NUM_ENC_STEPS_PER_REV_AXIS1; else if (axis == 2) *num_steps_per_rev = CM4000_NUM_ENC_STEPS_PER_REV_AXIS1; else if (axis == 3) *num_steps_per_rev = CM4000_NUM_ENC_STEPS_PER_REV_AXIS3; else if (axis == 4) *num_steps_per_rev = CM4000_NUM_ENC_STEPS_PER_REV_AXIS4; else cm4000_error("Unknown axis number"); /* Done */ return; } /* ************************************************************** */ /* * cm4000_get_motor_resolution_code * This function gets the motor resolution code. * * Input: * axis, axis number (1 to 4) * * Output: * mr, motor resolution code * * Zachary Wolf * 9/9/02 */ void cm4000_get_motor_resolution_code(int axis, int* mr) { /* Declare variables */ long int num_steps_per_rev; /* Get the number of steps per revolution */ cm4000_get_num_mot_steps_per_rev(axis, &num_steps_per_rev); /* Determine the motor resolution code */ /* See p. 41 of the manual */ if (num_steps_per_rev == 200) *mr = 0; else if (num_steps_per_rev == 400) *mr = 1; else if (num_steps_per_rev == 800) *mr = 2; else if (num_steps_per_rev == 1000) *mr = 3; else if (num_steps_per_rev == 2000) *mr = 4; else if (num_steps_per_rev == 4000) *mr = 5; else if (num_steps_per_rev == 5000) *mr = 6; else if (num_steps_per_rev == 500) *mr = 7; else if (num_steps_per_rev == 10000) *mr = 8; else if (num_steps_per_rev == 21600) *mr = 9; else if (num_steps_per_rev == 25000) *mr = 10; else if (num_steps_per_rev == 25400) *mr = 11; else if (num_steps_per_rev == 36000) *mr = 12; else if (num_steps_per_rev == 50000) *mr = 13; else if (num_steps_per_rev == 50800) *mr = 14; else if (num_steps_per_rev == 4096) *mr = 15; else if (num_steps_per_rev == 12800) *mr = 16; else if (num_steps_per_rev == 25600) *mr = 17; else if (num_steps_per_rev == 12500) *mr = 18; else if (num_steps_per_rev == 16384) *mr = 19; else if (num_steps_per_rev == 20000) *mr = 20; else cm4000_error("Unknown motor resolution"); /* Done */ return; } /* ************************************************************** */ /* * cm4000_message * This function handles messages about the CM4000. * * Input: * message, string to display in standard I/O * * Zachary Wolf * 9/9/02 */ void cm4000_message(char* message) { /* Print the message */ printf("%s\n", message); /* Done */ return; } /* ************************************************************** */ /* * cm4000_error * This function handles error messages for the CM4000. * * Input: * message, string to display in standard I/O * * Zachary Wolf * 9/9/02 */ void cm4000_error(char* message) { /* Declare variables */ char buf[80]; /* Notify the operator of the error */ printf("\nCM4000 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); }