// 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"
void LTS_waitMove
(int i
, int timeout
);
void LTS_waitHome
(int i
, int timeout
);
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;
double SingleMove
=1; // in mm
int LTSTimerOut
=0;
int p1_h
;
int CVICALLBACK LTS_Timeout
(int panel
, int control
, int event
,
void *callbackData
, int eventData1
, int eventData2
) {
switch (event
) {
case EVENT_TIMER_TICK
:
LTSTimerOut
= 1;
printf("LTS timeout\n");
break;
}
return 0;
}
/*
void LTS_Timerast (int signumber) {
LTSTimerOut = 1;
printf("TIMEOUT !!!\n");
SetCtrlAttribute (p1_h, P1_TIMEOUT, ATTR_ENABLED, 0);
}
*/
void LTS_Tmlnk
(int tout
) {
LTSTimerOut
= 0;
SetCtrlAttribute
(p1_h
, P1_TIMEOUT
, ATTR_INTERVAL
, (float)tout
/1000.
);
SetCtrlAttribute
(p1_h
, P1_TIMEOUT
, ATTR_ENABLED
, 1);
}
void LTS_Tmulk
( void ) {
SetCtrlAttribute
(p1_h
, P1_TIMEOUT
, ATTR_ENABLED
, 0);
LTSTimerOut
= 0;
}
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
]);
printf( "Start Homing...\n");
if (wait
) LTS_waitHome
(i
, wait
);
// printf( "Homed...\n");
}
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
ISC_StartPolling
(serialNumbers
[i
], 50);
Sleep
(1000);
} else {
printf( "Error connecting device %d (%s)\n",i
, serialNumbers
[i
] );
}
return errorReturn
;
}
void LTS_Close
(int i
){
//Close the stage
ISC_StopPolling
(serialNumbers
[i
]);
ISC_Close
(serialNumbers
[i
]);
printf( "Device Disconnected...\n");
}
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
]);
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
]);
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
]);
}
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_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
);
}
//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);
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
);
condition
= (messageType
== 2) && (messageId
== 0);
} while (!condition
|| !LTSTimerOut
);
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);
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
);
condition
= (messageType
== 2) && (messageId
== 1);
} while (!condition
);
LTS_Tmulk
();
}
//*******************************************************************
#ifdef LTS_MAIN
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;
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,0);
break;
case P1_HO_2
:
LTS_Home
(1,0);
break;
case P1_HO_3
:
LTS_Home
(2,0);
break;
case P1_GX
:
GetCtrlVal
(p1_h
, P1_XG
, &n2
);
LTS_MoveAbsolute
(0,n2
,0);
break;
case P1_GY
:
GetCtrlVal
(p1_h
, P1_YG
, &n2
);
LTS_MoveAbsolute
(1,n2
,0);
break;
case P1_GZ
:
GetCtrlVal
(p1_h
, P1_ZG
, &n2
);
LTS_MoveAbsolute
(2,n2
,0);
break;
case P1_G
:
GetCtrlVal
(p1_h
, P1_XG
, &n2
);
LTS_MoveAbsolute
(0,n2
,0);
GetCtrlVal
(p1_h
, P1_YG
, &n2
);
LTS_MoveAbsolute
(1,n2
,0);
GetCtrlVal
(p1_h
, P1_ZG
, &n2
);
LTS_MoveAbsolute
(2,n2
,0);
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");
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