#include "siutils.h"
#include "mechanism.h"
Functions | |
void | MechInitTable (si_mechanism_t *mech) |
Initialize the data members of an si_mechanism struct. | |
int | MechGetPos (si_mechanism_t *mech, char *reply) |
Query the Si microstep drive for the current mechanism position. | |
int | MechSetProfile (si_mechanism_t *mech, char *reply) |
Upload the motion profile to the microstep drive. | |
int | MechMoveAbs (si_mechanism_t *mech, int req_pos, char *reply) |
Move a mechanism to an absolute step-count position. | |
int | MechMoveRel (si_mechanism_t *mech, int delta, char *reply) |
Move a mechanism by a relative step-count distance from its current position. | |
int | MechMoveTo (si_mechanism_t *mech, int req_pos, int offset, char *reply) |
Move to an indexed mechanism to a selected indexed position. | |
int | MechFindPos (si_mechanism_t *mech, char *reply) |
Seek a valid indexed position starting from an invalid (in-between) position. | |
int | MechBrake (si_mechanism_t *mech, int action, char *reply) |
Set the mechanism brake. | |
void | MechAbort (si_mechanism_t *mech) |
Abort a move in progress. | |
int | MechEncToDev (int encpos, int npos, int offset, int topology) |
Convert a raw encoder position into an offset device position in an indexed mechanism (Convenience Function). |
This is a set of API functions for operating a mechanism driven by a stepper motor using an Applied Motion Products Si indexing microstep drive.
More details to follow...
2004 Jun 16 - added MechBrake() function, and added brake operations to the MechMoveXXX functions [rwp/osu] 2004 Jul 16 - added StepsPerMM to MechInitTable() [rwp/osu]
|
Initialize the data members of an si_mechanism struct.
|
|
Query the Si microstep drive for the current mechanism position.
If the mechanism uses position encoders, it interprets the bit string returned by the IS command and convert this into an encoder data value (integer) and the relevant flags, loading the following si_mechanism struct data members: si_mechanism::Inputs = Input sensor bit string si_mechanism::EncPos = Decimal representation of the position encoder bits si_mechanism::InPos = In-Position flag (in-/out-of-position), if used si_mechanism::AtHome = Home Position Flag (at home/away), if used si_mechanism::CWlimit = CW limit switch state, if used si_mechanism::CCWlimit = CCW limit switch state, if used si_mechanism::Occupied = Position occupation state (occupied/empty) if used.On success, the reply string contains an IMPv2-conformal position status string reporting the mechanism position in keyword=value pairs as follows (for example) RawIn=11111011 Inputs=11000011 ISMask=11000111 StepCounts=16172The calling routine can do something with this string or not as required. It is also free to interpret/use the various si_mechanism struct data members as required. The string above contains minimal engineering-level information. The usual use is to print it to stdout when the client is running in Verbose or Debug (super-verbose) mode.
|
|
Upload the motion profile to the microstep drive.
si_mechanism::Speed = speed (velocity) in rev/s - VE si_mechanism::Accel = acceleration rate in rev/s/s - AC si_mechanism::Decel = deceleration rate in rev/s/s - DE si_mechanism::Distance = move distance in steps - DI si_mechanism::Current = motor current in Amps - CC si_mechanism::IdleCurrent = motor idle current in Amps - CI si_mechanism::Idle = Enable/Disable motor idle - ME/MDIn addition, we set these parameters: if si_mechanism::Limits = MECH_NORMALLY_CLOSED DL1 - if limit switch is sinking/normally-closed or sourcing/normally-open if si_mechanism::Limits = MECH_NORMALLY_OPEN DL2 - if limit sensor is sinking/normally-open or sourcing/normally-closed if si_mechanism::Limits = MECH_NOLIMITS DL3 - limit switches disabled
JD - disable Jog Inputs (maybe unnecessary) JA1 - set the Jog Acceleration to 1 rev/s/sWhen the drive is power cycled, it loses all knowledge of its position (all parameters are volatile except for the power-on current - PC - and power-up communications mode - PM). The accelerations, speed, etc. are reset to device defaults. To provide a check, we always set the Jog Acceleration parameter (JA) to 1. If we ever see it set to SI_JA_DEFAULT, we will have some indication that the controller has been power-cycled. This is important for being able to operate linear continuous drive mechanisms in step-counting mode to tell the position without resort to an absolute position encoder. For example, the MechMoveAbs() command checks the value of JA before uploading the profile.
|
|
Move a mechanism to an absolute step-count position.
The move takes place in the following sequence:
|
|
Move a mechanism by a relative step-count distance from its current position.
The move takes place in the following sequence:
|
|
Move to an indexed mechanism to a selected indexed position.
The rules for determining "success" of a requested move are as follows:
All of our devices use positions numbered 1..si_mechanism::NPos, (1-relative), but the encoder values run 0..si_mechanism::NPos-1 (0-relative). This does sometimes lead to confusion, so beware! To avoid errors, the MechEncToDev() function is provided to make this computation simple and consistent. See MechEncToDev() for details.
The algorithm to make a least-path move is as follows: where cur_pos is the current position (e.g., Filter 1), req_pos is the requested position (e.g., Filter 4), Npos is the number of valid positions in the rotary mechanism (si_mechanism::NPos), and StepPos is the number of steps between valid positions (si_mechanism::StepPos). The code below validates that the requested position is indeed within the valid index limits.
Again, cur_pos is the current position, req_pos is the requested position, and StepPos is the number of steps between valid positions (si_mechanism::StepPos), and req_pos is validated below before computing the move vector.
|
|
Seek a valid indexed position starting from an invalid (in-between) position.
Experimentally, the values we use for seeking a valid position are as follows: speed (VE) = 20% normal speed (si_mechanism::Speed) accel (AC) = 1 rev/sec/sec (minimum) decel (DE) = 1 rev/sec/sec (minimum) distance until change (DC) = 2*abs(si_mechanism::StepPos) = 2 index distances distance to move (DI) = R*VE^2/(2*DE) where R = the microstep resolution.If the in-position bit doesn't assert after moving 2 whole index positions, we have problems. The FY (Feed to sensor with safety distance) will Timeout and return a "!" if the in-position sensor is not seen after moving DC steps. DI steps are computed to allow the motor to ramp down after seeing the sensor but not miss it. Before the move, we turn the idle ON (ME command) to avoid getting pulled into a kinematic docking detent during a slow move, and once we get into position, we turn idle OFF (MD command) to drop into the position detent.
|
|
Set the mechanism brake.
On completion, sets the si_mechanism::Brake data member. If the brake state is unknown, it is set to -1. After a successful braking action, it sleeps for si_mechanism::Polltime milliseconds to allow things to settle mechanically before returning.
|
|
Abort a move in progress.
|
|
Convert a raw encoder position into an offset device position in an indexed mechanism (Convenience Function).
Key features are that all rotary indexed mechanisms we build have fixed positions that are numbered 1-relative (i.e., 1..si_mechanism::NPos, not 0..si_mechanism::NPos-1). A negative offset has to be "wrapped" using the number of positions. You'd be very surprised how long it took to get this right. Modular arithmetic in a rotary (cyclic) mechanism makes everyone's head hurt. For linear indexed mechanisms, the device position algorithm is much simpler, but easy to mis-code: Again, like rotary mechanisms, the logical device positions are always numbered 1..si_mechanism::NPos. |