// This example uses the Kinesis C++ API to move and control Thorlabs integrated stepper motor, LTS, K10CR1, and MLJ stages.
/* Default parameters
HS LTS300C 300mm Stage
General
Name = HS LTS300C 300mm Stage
Stage ID = Unknown
Axis ID = SingleAxis
Home Settings
HomeDir = MOT_Reverse
HomeLimitSwitch = MOT_ReverseLimitSwitch
HomeVel = 2
HomeZeroOffset = 0,5
Jog Settings
JogMode = MOT_ExtSingleStep
JogStopMode = MOT_Profiled
JogStepSize = 5,0
JogMinVel = 0,0
JogAccn = 10,0
JogMaxVel = 10,0
Control Settings
DefMinVel = 0,0
DefAccn = 20,0
DefMaxVel = 20,0
Limit Settings
CWHardLimit = MOT_LimitSwitchMakeOnContact
CCWHardLimit = MOT_LimitSwitchMakeOnContact
CWSoftLimit = 3,0
CCWSoftLimit = 1,0
SoftLimitMode = MOT_LimitSwitchIgnored
LimitsSoftwareApproachPolicy = DisallowIllegalMoves
Physical Settings
Pitch = 1,0
StepsPerRev = 200
GearboxRatio = 1
TST101 Stage ID = 0
UseDeviceUnits = False
Units = MOT_Linear
DirSense = MOT_Backwards
MinPos = 0,00
MaxPos = 300,00
MaxAccn = 50,0
MaxVel = 50,0
MaxContinuousVel = 40,0
Factor = 1,0
UnitsTxt = mm
DisplayDP = -1
Misc. Settings
BacklashDist = 0,05
MoveFactor = 30
RestFactor = 5
Stepper Motor Settings
Pitch = 1,0
StepsPerRev = 200
GearboxRatio = 1
TST101 Stage ID = 0
UseDeviceUnits = False
Units = MOT_Linear
DirSense = MOT_Backwards
MinPos = 0,00
MaxPos = 300,00
MaxAccn = 50,0
MaxVel = 50,0
MaxContinuousVel = 40,0
Factor = 1,0
UnitsTxt = mm
DisplayDP = -1
Velocity Profile Settings
BowIndex = 0
Button Settings
ButtonMode = MOT_JogMode
ButtonPos1 = 10,0
ButtonPos2 = 20,0
Potentiometer Settings
FPControls = True
PotZeroWnd = 1
PotVel1 = 5,0
PotWnd1 = 50
PotVel2 = 10,0
PotWnd2 = 80
PotVel3 = 15,0
PotWnd3 = 100
PotVel4 = 20,0
*/
//CVI Add dll path to: Options>Environment>Include Path> C:\Program Files\Thorlabs\Kinesis
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <windows.h>
#include <userint.h>
#include <utility.h>
#include "ThorlabsLTS_ui.h"
#include "ThorlabsMotionControlIntegratedStepperMotors.h"
#include "ThorlabsLTS.h"
char serialNumbers[][9] = {"45388004", "45387934","45388034"};
// Set number of microsteps, found in APT communications protocol. Should be changed to 136533 if using K10CR1
int StepsPerMm = 409600;
int LTSTimerOut=0;
int pth=0,tctrl;
int CVICALLBACK LTS_Timeout (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2) {
switch (event) {
case EVENT_TIMER_TICK:
LTSTimerOut = 1;
break;
}
return 0;
}
/*
void LTS_Timerast (int signumber) {
LTSTimerOut = 1;
printf("TIMEOUT !!!\n");
SetCtrlAttribute (p1_h, P1_TIMEOUT, ATTR_ENABLED, 0);
}
*/
// tout in ms
void LTS_Tmlnk (int tout) {
if (!pth) {
pth = NewPanel (0, "Timeout pannel", 0, 0, 200, 200);
tctrl = NewCtrl (pth, CTRL_TIMER, "Timeout", 0, 0);
SetCtrlAttribute (pth, tctrl, ATTR_CALLBACK_FUNCTION_POINTER, LTS_Timeout);
SetCtrlAttribute (pth, tctrl, ATTR_ENABLED, 0);
SetCtrlAttribute (pth, tctrl, ATTR_CTRL_MODE, VAL_INDICATOR);
// SetActiveCtrl (pth, tctrl);
}
LTSTimerOut = 0;
SetCtrlAttribute (pth, tctrl, ATTR_INTERVAL, (double)tout/1000.);
SetCtrlAttribute (pth, tctrl, ATTR_ENABLED, 1);
}
void LTS_Tmulk ( void ) {
SetCtrlAttribute (pth, tctrl, ATTR_ENABLED, 0);
LTSTimerOut = 0;
}
//Waits should only be used for Home commands. The home command has a different status return.
void LTS_waitHome(int i, int tout)// Waits until a single axis is homed.
{
WORD messageType=0;
WORD messageId=0;
DWORD messageData=0;
int condition=0;
LTS_Tmlnk (tout);
do {
while (!ISC_MessageQueueSize(serialNumbers[i])){
Sleep(250);
ProcessSystemEvents();
if (LTSTimerOut) break;
}
if (LTSTimerOut){
printf( "Timeout in axis [%d] pos: %f messageType %d, messageId %d\n",i
,LTS_GetPosition
(i
), messageType
, messageId
);
break;
}
ISC_GetNextMessage(serialNumbers[i], &messageType, &messageId, &messageData);
printf( "axis [%d] pos: %f messageType %d, messageId %d\n",i
,LTS_GetPosition
(i
), messageType
, messageId
);
condition = (messageType == 2) && (messageId == 0);
} while (!condition);
LTS_Tmulk();
}
void LTS_waitMove(int i, int tout)// Waits until axis is stopped.
{
WORD messageType=0;
WORD messageId=0;
DWORD messageData=0;
int condition=0;
LTS_Tmlnk (tout);
do {
while (!ISC_MessageQueueSize(serialNumbers[i])){
Sleep(250);
ProcessSystemEvents();
if (LTSTimerOut) break;
}
if (LTSTimerOut){
printf( "Timeout in axis [%d] pos: %f messageType %d, messageId %d\n",i
,LTS_GetPosition
(i
), messageType
, messageId
);
break;
}
ISC_GetNextMessage(serialNumbers[i], &messageType, &messageId, &messageData);
// printf( "axis [%d] pos: %f messageType %d, messageId %d\n",i,LTS_GetPosition(i), messageType, messageId);
condition = (messageType == 2) && (messageId == 1);
} while (!condition);
LTS_Tmulk();
}
int LTS_Init(int i){
int errorReturn = ISC_Open(serialNumbers[i]);
/*
double stepsPerRev = 200;
double gearBoxRatio = 1;
double pitch = 1;
int err = ISC_SetMotorParamsExt(serialNumbers[i], stepsPerRev, gearBoxRatio, pitch);
err = ISC_GetMotorParamsExt(serialNumbers[i], &stepsPerRev, &gearBoxRatio, &pitch);
// No effect
*/
Sleep(1000);
if (errorReturn == 0){
printf( "Device %d (serial %s) Connected... \n",i
, serialNumbers
[i
]);
//Settings are loaded based on Stage Name. The integrated stepper class holds LTS and K10CR1 Information.
ISC_SetLEDswitches(serialNumbers[i], 0); // disable LED
Sleep(100);
ISC_StartPolling(serialNumbers[i], 50);
Sleep(1000);
} else {
printf( "Error connecting device %d (%s)\n",i
, serialNumbers
[i
] );
}
return errorReturn;
}
int LTS_Open(){
TLI_BuildDeviceList();
TLI_DeviceInfo info;
int err=0;
for (int i=0;i<3;i++){
TLI_GetDeviceInfo(serialNumbers[i], &info);
Sleep(100);
err = LTS_Init(i);
printf("%s err=%x\n", info.
description, err
);
if (err) return err;
}
return 0;
}
void LTS_Close(int i){
//Close the stage
ISC_StopPolling(serialNumbers[i]);
ISC_Close(serialNumbers[i]);
printf( "Device Disconnected...\n");
}
// wait in ms
void LTS_Home(int i,int wait){
//Set up homing parameters.
MOT_HomingParameters homingParams;
ISC_GetHomingParamsBlock(serialNumbers[i], &homingParams);
homingParams.direction = MOT_Reverse;
ISC_SetHomingParamsBlock(serialNumbers[i], &homingParams);
//Clear existing messages in the hardware buffer.
ISC_ClearMessageQueue(serialNumbers[i]);
//Home the stage and wait for the return message before continuing.
ISC_Home(serialNumbers[i]);
if (wait) LTS_waitHome(i, wait);
}
void LTS_StopProfiled(int i){
ISC_StopProfiled(serialNumbers[i]);
}
void LTS_MoveAbsolute(int i, double position, int wait){
ISC_SetMoveAbsolutePosition(serialNumbers[i], (position*StepsPerMm));
ISC_MoveAbsolute(serialNumbers[i]);
//Clear existing messages in the hardware buffer.
ISC_ClearMessageQueue(serialNumbers[i]);
if (wait) LTS_waitMove(i, wait);
}
void LTS_MoveRelative(int i, double distance, int wait){
ISC_SetMoveRelativeDistance(serialNumbers[i], (distance*StepsPerMm));
ISC_MoveRelativeDistance(serialNumbers[i]);
//Clear existing messages in the hardware buffer.
ISC_ClearMessageQueue(serialNumbers[i]);
if (wait) LTS_waitMove(i, wait);
}
double LTS_GetPosition(int i){
int device_unit = ISC_GetPosition(serialNumbers[i]); ;
double real_unit = 1.0*device_unit / StepsPerMm;
//const int unitType = 0 ;// 0 .. distance , 1 .. velocity, 2 .. acceleration
// does not work int err = ISC_GetRealValueFromDeviceUnit(serialNumbers[i], device_unit,&real_unit, unitType);
// printf("err = 0x%x pos %d %f\n", err ,device_unit, real_unit);
return real_unit;
}
unsigned int LTS_GetStatus(int i){
return ISC_GetStatusBits(serialNumbers[i]);
}
int LTS_Enable(int i){
return ISC_EnableChannel(serialNumbers[i]);
}
int LTS_Disable(int i){
return ISC_DisableChannel(serialNumbers[i]);
}
int LTS_GetNumberPositions(int i){
return ISC_GetNumberPositions(serialNumbers[i]);
}
void LTS_RegisterMessageCallback(int i, void (* functionPointer)()){
ISC_RegisterMessageCallback(serialNumbers[i], functionPointer );
}
void LTS_GetRealValueFromDeviceUnit(int i, int device_unit, double *real_unit, int unitType){
ISC_GetRealValueFromDeviceUnit(serialNumbers[i], device_unit, real_unit, unitType);
}
void LTS_GetDeviceUnitFromRealValue(int i, double real_unit, int *device_unit, int unitType){
ISC_GetDeviceUnitFromRealValue(serialNumbers[i], real_unit, device_unit, unitType);
}
//*******************************************************************
#ifdef LTS_MAIN
int p1_h;
int rID, tfID;
#define MAX_THREADS 10
static CmtThreadPoolHandle poolHandle = 0;
int lid[][14]= {
{P1_L1,P1_L2,P1_L3,P1_L4,P1_L5,P1_L6,P1_L7,P1_L8,P1_L9,P1_L10,P1_L11,P1_L12,P1_L13,P1_L14},
{P1_L1_2,P1_L2_2,P1_L3_2,P1_L4_2,P1_L5_2,P1_L6_2,P1_L7_2,P1_L8_2,P1_L9_2,P1_L10_2,P1_L11_2,P1_L12_2,P1_L13_2,P1_L14_2},
{P1_L1_3,P1_L2_3,P1_L3_3,P1_L4_3,P1_L5_3,P1_L6_3,P1_L7_3,P1_L8_3,P1_L9_3,P1_L10_3,P1_L11_3,P1_L12_3,P1_L13_3,P1_L14_3}};
int dstat[3]={P1_N2,P1_N2_2,P1_N2_3};
int dpos[3]={P1_XP,P1_YP,P1_ZP};
int ctrl_c=0;
void LTS_SetStatus(int nid){
int status=LTS_GetStatus(nid);
SetCtrlVal (p1_h, dstat[nid], status);
SetCtrlVal (p1_h, lid[nid][12], (status & 0x20000000)>0);
SetCtrlVal (p1_h, lid[nid][13], (status & 0x80000000)>0);
for (int i=0; i<12; i++) {
SetCtrlVal (p1_h, lid[nid][i], status & 1);
status>>=1;
}
}
void CVICALLBACK EndOfThread ( CmtThreadPoolHandle poolhandle,
CmtThreadFunctionID functionID, unsigned int event,
int value, void *callbackData ) {
SetCtrlVal (p1_h, P1_SCANLED, 0);
ctrl_c=0;
return ;
}
int CVICALLBACK daq(void *functionData) {
ctrl_c =0;
SetCtrlVal (p1_h, P1_SCANLED, 1);
int nx,ny,nz;
GetCtrlVal(p1_h,P1_NX, &nx);
GetCtrlVal(p1_h,P1_NY, &ny);
GetCtrlVal(p1_h,P1_NZ, &nz);
double dx,dy,dz;
GetCtrlVal(p1_h,P1_DX, &dx);
GetCtrlVal(p1_h,P1_DY, &dy);
GetCtrlVal(p1_h,P1_DZ, &dz);
double x0,y0,z0;
GetCtrlVal(p1_h,P1_X0, &x0);
GetCtrlVal(p1_h,P1_Y0, &y0);
GetCtrlVal(p1_h,P1_Z0, &z0);
int cbx,cby,cbz;
int timeout=10000; // timeout in ms
GetCtrlVal(p1_h,P1_CBX, &cbx);
GetCtrlVal(p1_h,P1_CBY, &cby);
GetCtrlVal(p1_h,P1_CBZ, &cbz);
if (!cbx) nx=1;
if (!cby) ny=1;
if (!cbz) nz=1;
int nstep=0;
double totalSteps=nx*ny*nz;
for (int iz=0;iz<nz;iz++){
double zposition= z0+ iz*dz;
SetCtrlVal(p1_h,P1_IZ, iz);
SetCtrlVal(p1_h,P1_DAQLED, 1);
LTS_MoveAbsolute(2,zposition,timeout);
SetCtrlVal(p1_h,P1_DAQLED, 0);
for (int iy=0;iy<ny;iy++){
double yposition= y0+ iy*dy;
SetCtrlVal(p1_h,P1_IY, iy);
SetCtrlVal(p1_h,P1_DAQLED, 1);
LTS_MoveAbsolute(1,yposition,timeout);
SetCtrlVal(p1_h,P1_DAQLED, 0);
for (int ix=0;ix<nx;ix++){
double xposition= x0+ ix*dx;
SetCtrlVal(p1_h,P1_IX, ix);
SetCtrlVal(p1_h,P1_DAQLED, 1);
LTS_MoveAbsolute(0,xposition,timeout);
SetCtrlVal(p1_h,P1_DAQLED, 0);
for (int k=0;k<3;k++){
double n2 = LTS_GetPosition(k);
SetCtrlVal (p1_h, dpos[k], n2);
LTS_SetStatus(k);
}
//printf("[%d]\n",nstep++);
nstep++;
double ratio = nstep/totalSteps;
SetCtrlVal(p1_h,P1_PROGRESS, 100.*ratio);
Delay(0.1);
if (ctrl_c) break;
}
if (ctrl_c) break;
}
if (ctrl_c) break;
}
return 0;
}
void MessageCB(){
//printf("Message %d\n",d[0]);
return;
}
int __stdcall WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow) {
int evcontrl,evpanel,ierr;
double n2;
int comled;
int enabled=0;
double SingleMove=1; // in mm
SetSleepPolicy(VAL_SLEEP_MORE);
CmtNewThreadPool (MAX_THREADS, &poolHandle);
SetStdioPort (CVI_STDIO_WINDOW);
if (InitCVIRTE (hInstance, 0, 0) == 0) return -1; // out of memory
p1_h = LoadPanel (0,"ThorlabsLTS_ui.uir", P1);
//p1_h = BuildP1 (0);
ierr = DisplayPanel (p1_h);
ierr = SetActiveCtrl (p1_h,P1_B1);
ierr = SetActiveCtrl (p1_h,P1_B3);
GetCtrlVal (p1_h, P1_COMLED, &comled);
if (!comled) {
//GetCtrlVal (p1_h, P1_PORT, &port);
//if (MIKRO_Open (port)) continue;
LTS_Open();
SetCtrlVal (p1_h, P1_COMLED, 1);
for (int i=0;i<3;i++) LTS_RegisterMessageCallback(i, &MessageCB );
}
int scanled=0;
while (1) {
ierr = GetUserEvent (1, &evpanel, &evcontrl);
//printf("GetUserEvent %d %d\n", evpanel, evcontrl);
if (evcontrl == P1_STOPSCAN) ctrl_c=1;
GetCtrlVal (p1_h, P1_SCANLED, &scanled);
if (scanled) continue;
if (evcontrl == P1_B1) break;
switch (evcontrl) {
case P1_BL:
LTS_MoveRelative(0,-SingleMove, 0);
break;
case P1_BR:
LTS_MoveRelative(0,+SingleMove, 0);
break;
case P1_BU:
LTS_MoveRelative(1,+SingleMove, 0);
break;
case P1_BD:
LTS_MoveRelative(1,-SingleMove, 0);
break;
case P1_BF:
LTS_MoveRelative(2,+SingleMove, 0);
break;
case P1_BB:
LTS_MoveRelative(2,-SingleMove, 0);
break;
case P1_HO:
LTS_Home(0,180000);
break;
case P1_HO_2:
LTS_Home(1,180000);
break;
case P1_HO_3:
LTS_Home(2,180000);
break;
case P1_GX:
GetCtrlVal (p1_h, P1_XG, &n2);
LTS_MoveAbsolute(0,n2,15000);
break;
case P1_GY:
GetCtrlVal (p1_h, P1_YG, &n2);
LTS_MoveAbsolute(1,n2,15000);
break;
case P1_GZ:
GetCtrlVal (p1_h, P1_ZG, &n2);
LTS_MoveAbsolute(2,n2,15000);
break;
case P1_G:
GetCtrlVal (p1_h, P1_XG, &n2);
LTS_MoveAbsolute(0,n2,15000);
GetCtrlVal (p1_h, P1_YG, &n2);
LTS_MoveAbsolute(1,n2,15000);
GetCtrlVal (p1_h, P1_ZG, &n2);
LTS_MoveAbsolute(2,n2,15000);
break;
case P1_B3: // reset
case P1_B3_2: // reset
case P1_B3_3: // reset
printf("RST Not yet implemented\n");
break;
case P1_STOP:
LTS_StopProfiled(0);
break;
case P1_STOP_2:
LTS_StopProfiled(1);
break;
case P1_STOP_3:
LTS_StopProfiled(2);
break;
case P1_EN:
LTS_Enable(0);
break;
case P1_EN_2:
LTS_Enable(1);
break;
case P1_EN_3:
LTS_Enable(2);
break;
case P1_DIS:
LTS_Disable(0);
break;
case P1_DIS_2:
LTS_Disable(1);
break;
case P1_DIS_3:
LTS_Disable(2);
break;
case P1_TIMER:
for (int k=0;k<3;k++){
double position = LTS_GetPosition(k);
SetCtrlVal (p1_h, dpos[k], position);
LTS_SetStatus(k);
}
break;
case P1_SCAN:
enabled=1;
const int LTS_Enabled = 0x80000000;
for (int i=0;i<3;i++) if (!(LTS_GetStatus(i)& LTS_Enabled)) enabled =0;
if (enabled){
SetCtrlVal(p1_h,P1_DAQLED, 0);
CmtScheduleThreadPoolFunctionAdv (poolHandle, daq, &rID,
DEFAULT_THREAD_PRIORITY,
EndOfThread,
EVENT_TP_THREAD_FUNCTION_END,
NULL, RUN_IN_SCHEDULED_THREAD,
&tfID);
} else {
MessagePopup ("Error", "Enable LTS Stages First");
}
break;
default:
break;
}
Delay(0.001);
}
GetCtrlVal (p1_h, P1_COMLED, &comled);
if (comled) for (int i=0;i<3;i++) LTS_Close (i);
return 0;
}
int CVICALLBACK TimerCB (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
int isrunning;
switch (event)
{
case EVENT_TIMER_TICK:
GetCtrlVal (p1_h, P1_SCANLED, &isrunning);
if (!isrunning) QueueUserEvent (1, p1_h, P1_TIMER);
break;
}
return 0;
}
#else
// *************************************
/*
int main(int argc, char ** argv)
{
//Sets up simulations. Comment in if running on physical hardware.
//TLI_InitializeSimulations();
//Input serial number. Change for your specific device.
//serials = ["45388004", "45387934","45388034"]
//Build Device List and open device.
TLI_BuildDeviceList();
TLI_DeviceInfo info;
int err=0;
for (int i=0;i<3;i++){
TLI_GetDeviceInfo(serialNumbers[i], &info);
printf("%s\n", info.description);
Sleep(1000);
err |= LTS_Init(i);
}
for (int i=0;i<3;i++){
//Move the stage and wait for the return message before continuing.
for (int k=0;k<10;k++){
LTS_MoveAbsolute(i,k);
printf( "Moving ...\n");
LTS_waitMove(i);
printf( "Move Complete...\n");
}
}
for (int i=0;i<3;i++){
LTS_Close(i);
}
//Closes simulations. Comment if running on physical hardware.
//TLI_UninitializeSimulations();
Delay(10);
return 0;
}
*/
#endif