Finally works
This commit is contained in:
@@ -38,7 +38,7 @@ from tomcat_bec.devices.aerotech.AerotechAutomation1Enums import (
|
|||||||
os.environ["EPICS_CA_ADDR_LIST"] = "129.129.106.255"
|
os.environ["EPICS_CA_ADDR_LIST"] = "129.129.106.255"
|
||||||
AA1_IOC_NAME = "X02DA-ES1-SMP1"
|
AA1_IOC_NAME = "X02DA-ES1-SMP1"
|
||||||
AA1_AXIS_NAME = "ROTY"
|
AA1_AXIS_NAME = "ROTY"
|
||||||
|
MOTOR_TOL = 1.0
|
||||||
|
|
||||||
class AerotechMotor(EpicsMotor):
|
class AerotechMotor(EpicsMotor):
|
||||||
""" EpicsMotor extension with additional PVs"""
|
""" EpicsMotor extension with additional PVs"""
|
||||||
@@ -56,6 +56,9 @@ class AerotechAutomation1Test(unittest.TestCase):
|
|||||||
# HIL testing only if there's hardware
|
# HIL testing only if there's hardware
|
||||||
dev = aa1Controller(AA1_IOC_NAME + ":CTRL:", name="aa1")
|
dev = aa1Controller(AA1_IOC_NAME + ":CTRL:", name="aa1")
|
||||||
dev.wait_for_connection()
|
dev.wait_for_connection()
|
||||||
|
mot = AerotechMotor(AA1_IOC_NAME + ":" + AA1_AXIS_NAME, name="mot")
|
||||||
|
mot.wait_for_connection()
|
||||||
|
mot.motor_enable.set(1, settle_time=0.1).wait()
|
||||||
cls._isConnected = True
|
cls._isConnected = True
|
||||||
|
|
||||||
def test_01_ControllerProxy(self):
|
def test_01_ControllerProxy(self):
|
||||||
@@ -294,7 +297,7 @@ class AerotechAutomation1Test(unittest.TestCase):
|
|||||||
print(f"Absolute move to {target}, distance: {dist}")
|
print(f"Absolute move to {target}, distance: {dist}")
|
||||||
mot.move(target, wait=True)
|
mot.move(target, wait=True)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
np.abs(target - mot.position) < 0.1,
|
np.abs(target - mot.position) < MOTOR_TOL,
|
||||||
f"Final position {mot.position} is too far from target {target}",
|
f"Final position {mot.position} is too far from target {target}",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -797,7 +800,7 @@ class AerotechAutomation1Test(unittest.TestCase):
|
|||||||
for ii in range(len(positions)):
|
for ii in range(len(positions)):
|
||||||
mot.move(positions[ii])
|
mot.move(positions[ii])
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
np.abs(mot.position - positions[ii]) < 1.0,
|
np.abs(mot.position - positions[ii]) < MOTOR_TOL,
|
||||||
f"Expected to reach {positions[ii]}, now is at {mot.position} on step {ii}",
|
f"Expected to reach {positions[ii]}, now is at {mot.position} on step {ii}",
|
||||||
)
|
)
|
||||||
pso.trigger()
|
pso.trigger()
|
||||||
@@ -894,12 +897,12 @@ class AerotechAutomation1Test(unittest.TestCase):
|
|||||||
if scan_type in ["Pos", "Neg"]:
|
if scan_type in ["Pos", "Neg"]:
|
||||||
mot.move(pos_end)
|
mot.move(pos_end)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
np.abs(mot.position - pos_end) < 1.0,
|
np.abs(mot.position - pos_end) < MOTOR_TOL,
|
||||||
f"Expected to reach {pos_end}, now is at {mot.position} on iteration {ii}",
|
f"Expected to reach {pos_end}, now is at {mot.position} on iteration {ii}",
|
||||||
)
|
)
|
||||||
mot.move(pos_start)
|
mot.move(pos_start)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
np.abs(mot.position - pos_start) < 1.0,
|
np.abs(mot.position - pos_start) < MOTOR_TOL,
|
||||||
f"Expected to rewind to {pos_start}, now at {mot.position} on iteration {ii}",
|
f"Expected to rewind to {pos_start}, now at {mot.position} on iteration {ii}",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -907,13 +910,13 @@ class AerotechAutomation1Test(unittest.TestCase):
|
|||||||
if ii % 2 == 0:
|
if ii % 2 == 0:
|
||||||
mot.move(pos_end, wait=True)
|
mot.move(pos_end, wait=True)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
np.abs(mot.position - pos_end) < 1.0,
|
np.abs(mot.position - pos_end) < MOTOR_TOL,
|
||||||
f"Expected to reach {pos_end}, now at {mot.position} on iteration {ii}",
|
f"Expected to reach {pos_end}, now at {mot.position} on iteration {ii}",
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
mot.move(pos_start, wait=True)
|
mot.move(pos_start, wait=True)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
np.abs(mot.position - pos_start) < 1.0,
|
np.abs(mot.position - pos_start) < MOTOR_TOL,
|
||||||
f"Expected to reach {pos_start}, now at {mot.position} on iteration {ii}",
|
f"Expected to reach {pos_start}, now at {mot.position} on iteration {ii}",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -955,14 +958,19 @@ class AerotechAutomation1Test(unittest.TestCase):
|
|||||||
"startpos": 42,
|
"startpos": 42,
|
||||||
"scanrange": 180,
|
"scanrange": 180,
|
||||||
"nrepeat": 13,
|
"nrepeat": 13,
|
||||||
"scandir": "NegPos",
|
"scandir": "NEGPOS",
|
||||||
|
"npoints": 1300,
|
||||||
"scanvel": 150,
|
"scanvel": 150,
|
||||||
"scanacc": 500,
|
"scanacc": 500,
|
||||||
|
"accdist": 0.5*150*150/500,
|
||||||
|
"psotrigger": "PsoEvent",
|
||||||
|
"psoBoundsPos": [0.5*150*150/500, 180],
|
||||||
|
"psoBoundsNeg": [0.5*150*150/500, 180]
|
||||||
}
|
}
|
||||||
tm = jinja2.Template(templatetext)
|
tm = jinja2.Template(templatetext)
|
||||||
text = tm.render(scan=scanconfig)
|
text = tm.render(scan=scanconfig)
|
||||||
# with open("test/tcatSequenceScan.ascript", "w") as text_file:
|
with open("./tcatSequenceScanRBV.ascript", "w") as text_file:
|
||||||
# text_file.write(text)
|
text_file.write(text)
|
||||||
|
|
||||||
# Throws if IOC is not available or PVs are incorrect
|
# Throws if IOC is not available or PVs are incorrect
|
||||||
tsk = aa1Tasks(AA1_IOC_NAME + ":TASK:", name="tsk")
|
tsk = aa1Tasks(AA1_IOC_NAME + ":TASK:", name="tsk")
|
||||||
@@ -987,7 +995,7 @@ class AerotechAutomation1Test(unittest.TestCase):
|
|||||||
time.sleep(1.0)
|
time.sleep(1.0)
|
||||||
npoints_rbv = ddc.nsamples_rbv.value
|
npoints_rbv = ddc.nsamples_rbv.value
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
npoints_rbv, 13, f"Expected to record 13 DDC points, got: {npoints_rbv} after script"
|
npoints_rbv, 26, f"Expected to record 13 DDC points, got: {npoints_rbv} after script"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
// Test program for zig-zag line scanning with PSO window output "enable"
|
// Test program for simple zig-zag line scanning with PSO window output
|
||||||
// signal and DDC synchronized to external trigger input.
|
// "enable" signal and DDC synchronized to external trigger input.
|
||||||
// The file expects external parameter validation
|
// The file expects external parameter validation
|
||||||
// The PSO locations arrays are set externally from EPICS PV
|
// The PSO locations arrays are set externally from EPICS PV
|
||||||
|
//
|
||||||
|
#define DDC_ADDR 0x800000
|
||||||
|
#define PSO_ADDR 0x0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
enum ScanType
|
enum ScanType
|
||||||
Pos = 0
|
POS = 0
|
||||||
Neg = 1
|
NEG = 1
|
||||||
PosNeg = 2
|
POSNEG = 2
|
||||||
NegPos = 3
|
NEGPOS = 3
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -15,74 +20,98 @@ program
|
|||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// External parameters - USE THEESE
|
// External parameters - USE THEESE
|
||||||
var $fStartPosition as real = {{ scan.startpos }}
|
var $fStartPosition as real = {{ scan.startpos }}
|
||||||
var $fScanRange as real = $fStartPosition + {{ scan.scanrange }}
|
var $fScanRange as real = {{ scan.scanrange }}
|
||||||
var $iNumRepeat as integer = {{ scan.nrepeat }}
|
var $iNumRepeat as integer = {{ scan.nrepeat }}
|
||||||
var $eScanType as ScanType = ScanType.{{ scan.scandir or 'Pos' }}
|
var $eScanType as ScanType = ScanType.{{ scan.scandir or 'POS' }}
|
||||||
|
var $iNumDdcRead as integer = {{ scan.npoints }}
|
||||||
|
|
||||||
var $fVelJog as real = {{ scan.jogvel or 200 }}
|
var $fVelJog as real = {{ scan.jogvel or 200 }}
|
||||||
var $fVelScan as real = {{ scan.scanvel }}
|
var $fVelScan as real = {{ scan.scanvel }}
|
||||||
var $fAcceleration = {{ scan.scanacc or 500 }}
|
var $fAcceleration = {{ scan.scanacc }}
|
||||||
var $fSafeDist = 10.0
|
var $fAccDistance as real = {{ scan.accdist }}
|
||||||
|
var $eDdcTrigger as DriveDataCaptureTrigger = DriveDataCaptureTrigger.{{ scan.psotrigger }}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// Internal parameters - dont use
|
// Internal parameters - dont use
|
||||||
var $axis as axis = ROTY
|
var $axis as axis = ROTY
|
||||||
var $ii as integer
|
var $ii as integer
|
||||||
|
var $axisFaults as integer = 0
|
||||||
var $iDdcSafeSpace as integer = 4096
|
var $iDdcSafeSpace as integer = 4096
|
||||||
|
|
||||||
// Set acceleration
|
// Set acceleration
|
||||||
SetupAxisRampType($axis, RampType.Linear)
|
SetupAxisRampType($axis, RampType.Linear)
|
||||||
SetupAxisRampValue($axis,0,$fAcceleration)
|
SetupAxisRampValue($axis, 0, $fAcceleration)
|
||||||
var $fAccDistance as real = 0.5 * $fVelScan * $fVelScan / $fAcceleration + $fSafeDist
|
|
||||||
|
|
||||||
// set the actual scan range
|
// set the actual scan range
|
||||||
var $fPosStart as real
|
var $fPosStart as real
|
||||||
var $fPosEnd as real
|
var $fPosEnd as real
|
||||||
if $eScanType == ScanType.Pos
|
if $eScanType == ScanType.POS
|
||||||
$fPosStart = $fStartPosition - $fAccDistance
|
$fPosStart = $fStartPosition - $fAccDistance
|
||||||
$fPosEnd = $fStartPosition + $fScanRange + $fAccDistance
|
$fPosEnd = $fStartPosition + $fScanRange + $fAccDistance
|
||||||
elseif $eScanType == ScanType.Neg
|
elseif $eScanType == ScanType.NEG
|
||||||
$fPosStart = $fStartPosition + $fAccDistance
|
$fPosStart = $fStartPosition + $fAccDistance
|
||||||
$fPosEnd = $fStartPosition - $fScanRange - $fAccDistance
|
$fPosEnd = $fStartPosition - $fScanRange - $fAccDistance
|
||||||
elseif $eScanType == ScanType.PosNeg
|
elseif $eScanType == ScanType.POSNEG
|
||||||
$fPosStart = $fStartPosition - $fAccDistance
|
$fPosStart = $fStartPosition - $fAccDistance
|
||||||
$fPosEnd = $fStartPosition + $fScanRange + $fAccDistance
|
$fPosEnd = $fStartPosition + $fScanRange + $fAccDistance
|
||||||
elseif $eScanType == ScanType.NegPos
|
elseif $eScanType == ScanType.NEGPOS
|
||||||
$fPosStart = $fStartPosition + $fAccDistance
|
$fPosStart = $fStartPosition + $fAccDistance
|
||||||
$fPosEnd = $fStartPosition - $fScanRange - $fAccDistance
|
$fPosEnd = $fStartPosition - $fScanRange - $fAccDistance
|
||||||
end
|
end
|
||||||
|
|
||||||
// Move to start position before the scan
|
// Move to start position before the scan
|
||||||
|
// NOTE: Also wait for GigaFrost to start, otherwise early triggers might be missed
|
||||||
MoveAbsolute($axis, $fPosStart, $fVelJog)
|
MoveAbsolute($axis, $fPosStart, $fVelJog)
|
||||||
WaitForInPosition($axis)
|
WaitForInPosition($axis)
|
||||||
|
Dwell(2)
|
||||||
|
|
||||||
|
// Set globals for feedback
|
||||||
|
$rglobal[2] = $fPosStart
|
||||||
|
$rglobal[3] = $fPosEnd
|
||||||
|
|
||||||
// Configure PSO
|
// Configure PSO
|
||||||
|
// FIXME : When the controller is restarted
|
||||||
|
PsoDistanceConfigureInputs($axis, [PsoDistanceInput.XC4PrimaryFeedback])
|
||||||
PsoDistanceCounterOff($axis)
|
PsoDistanceCounterOff($axis)
|
||||||
PsoDistanceEventsOff($axis)
|
PsoDistanceEventsOff($axis)
|
||||||
PsoWindowConfigureEvents($axis, PsoWindowEventMode.None)
|
PsoWindowConfigureEvents($axis, PsoWindowEventMode.None)
|
||||||
PsoWaveformOff($axis)
|
PsoWaveformOff($axis)
|
||||||
PsoOutputConfigureSource($axis, PsoOutputSource.Waveform)
|
// Simple PSO trigger pattern
|
||||||
var $iPsoArrayAddr as integer = 0
|
var $iPsoArrayPosAddr as integer = PSO_ADDR
|
||||||
var $iPsoArray[] as real = [UnitsToCounts($axis, $fAccDistance), UnitsToCounts($axis, $fScanRange)]
|
var $iPsoArrayPos[] as real = [{% for psoDist in scan.psoBoundsPos[:-1] %} UnitsToCounts($axis, {{ psoDist }}), {% endfor %} UnitsToCounts($axis, {{ scan.psoBoundsPos[-1] }}) ]
|
||||||
DriveArrayWrite($axis, $iPsoArray, $iPsoArrayAddr, length($iPsoArray), DriveArrayType.PsoDistanceEventDistances)
|
DriveArrayWrite($axis, $iPsoArrayPos, $iPsoArrayPosAddr, length($iPsoArrayPos), DriveArrayType.PsoDistanceEventDistances)
|
||||||
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayAddr, 2, 0)
|
|
||||||
|
{% if scan.psoBoundsNeg|length > 0 %}
|
||||||
|
var $iPsoArrayNegAddr as integer = ($iPsoArrayPosAddr + length($iPsoArrayPos)) * 4
|
||||||
|
var $iPsoArrayNeg[] as real = [{% for psoDist in scan.psoBoundsNeg[:-1] %} UnitsToCounts($axis, {{ psoDist }}), {% endfor %} UnitsToCounts($axis, {{ scan.psoBoundsNeg[-1] }}) ]
|
||||||
|
DriveArrayWrite($axis, $iPsoArrayNeg, $iPsoArrayNegAddr, length($iPsoArrayNeg), DriveArrayType.PsoDistanceEventDistances)
|
||||||
|
{% else %}
|
||||||
|
var $iPsoArrayNegAddr as integer = ($iPsoArrayPosAddr + length($iPsoArrayPos)) * 4
|
||||||
|
var $iPsoArrayNegSize as integer = 0
|
||||||
|
var $iPsoArrayNeg[] as real = []
|
||||||
|
// DriveArrayWrite($axis, $iPsoArrayNeg, $iPsoArrayNegAddr, length($iPsoArrayNeg), DriveArrayType.PsoDistanceEventDistances)
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayPosAddr, length($iPsoArrayPos), 0)
|
||||||
|
PsoDistanceCounterOn($axis)
|
||||||
PsoDistanceEventsOn($axis)
|
PsoDistanceEventsOn($axis)
|
||||||
|
|
||||||
PsoWaveformConfigureMode($axis, PsoWaveformMode.Toggle)
|
PsoWaveformConfigureMode($axis, PsoWaveformMode.Toggle)
|
||||||
PsoWaveformOn($axis)
|
PsoWaveformOn($axis)
|
||||||
|
PsoOutputConfigureSource($axis, PsoOutputSource.Waveform)
|
||||||
|
|
||||||
// Configure Drive Data Collection
|
// Configure Drive Data Collection
|
||||||
var $iDdcArrayAddr as integer = 8388608
|
var $iDdcArraySize as integer = $iNumDdcRead
|
||||||
var $iDdcArraySize as integer = 5000
|
|
||||||
|
|
||||||
DriveDataCaptureConfigureInput($axis, 0, DriveDataCaptureInput.PrimaryFeedback);
|
DriveDataCaptureConfigureInput($axis, 0, DriveDataCaptureInput.PrimaryFeedback);
|
||||||
DriveDataCaptureConfigureInput($axis, 1, DriveDataCaptureInput.AnalogInput0 );
|
DriveDataCaptureConfigureInput($axis, 1, DriveDataCaptureInput.AnalogInput0 );
|
||||||
|
|
||||||
DriveDataCaptureConfigureTrigger($axis, 0, DriveDataCaptureTrigger.PsoOutput );
|
DriveDataCaptureConfigureTrigger($axis, 0, $eDdcTrigger );
|
||||||
DriveDataCaptureConfigureTrigger($axis, 1, DriveDataCaptureTrigger.PsoOutput );
|
DriveDataCaptureConfigureTrigger($axis, 1, $eDdcTrigger );
|
||||||
|
|
||||||
DriveDataCaptureConfigureArray($axis, 0, $iDdcArrayAddr, $iDdcArraySize);
|
DriveDataCaptureConfigureArray($axis, 0, DDC_ADDR, $iDdcArraySize);
|
||||||
DriveDataCaptureConfigureArray($axis, 1, $iDdcArrayAddr + $iDdcSafeSpace + 8 * $iDdcArraySize, $iDdcArraySize);
|
DriveDataCaptureConfigureArray($axis, 1, DDC_ADDR + $iDdcSafeSpace + 8 * $iDdcArraySize, $iDdcArraySize);
|
||||||
|
|
||||||
// Directly before scan
|
// Directly before scan
|
||||||
PsoDistanceCounterOn($axis)
|
PsoDistanceCounterOn($axis)
|
||||||
@@ -92,41 +121,44 @@ program
|
|||||||
///////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////
|
||||||
// Start the actual scanning
|
// Start the actual scanning
|
||||||
///////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////
|
||||||
for $ii = 0 to ($iNumRepeat-1)
|
|
||||||
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayAddr, 2, 0)
|
|
||||||
|
|
||||||
if $eScanType == ScanType.Pos
|
if $eScanType == ScanType.POS || $eScanType == ScanType.NEG
|
||||||
MoveAbsolute($axis, $fPosEnd, $fVelScan)
|
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayPosAddr, length($iPsoArrayPos), 0)
|
||||||
WaitForInPosition($axis)
|
MoveAbsolute($axis, $fPosEnd, $fVelScan)
|
||||||
MoveAbsolute($axis, $fPosStart, $fVelScan)
|
WaitForMotionDone($axis)
|
||||||
WaitForInPosition($axis)
|
|
||||||
elseif $eScanType == ScanType.Neg
|
$axisFaults = StatusGetAxisItem($axis, AxisDataSignal.AxisFault)
|
||||||
MoveAbsolute($axis, $fPosEnd, $fVelScan)
|
if $axisFaults
|
||||||
WaitForInPosition($axis)
|
TaskSetError(TaskGetIndex(), "AxisFault on axis ROTY")
|
||||||
MoveAbsolute($axis, $fPosStart, $fVelScan)
|
end
|
||||||
WaitForInPosition($axis)
|
elseif $eScanType == ScanType.POSNEG || $eScanType == ScanType.NEGPOS
|
||||||
elseif $eScanType == ScanType.PosNeg
|
for $ii = 0 to ($iNumRepeat-1)
|
||||||
if ($ii % 2) == 0
|
// Feedback on progress
|
||||||
MoveAbsolute($axis, $fPosEnd, $fVelScan)
|
$rglobal[4] = $ii
|
||||||
WaitForInPosition($axis)
|
if ($ii % 2) == 0
|
||||||
elseif ($ii % 2) == 1
|
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayPosAddr, length($iPsoArrayPos), 0)
|
||||||
MoveAbsolute($axis, $fPosStart, $fVelScan)
|
MoveAbsolute($axis, $fPosEnd, $fVelScan)
|
||||||
WaitForInPosition($axis)
|
elseif ($ii % 2) == 1
|
||||||
end
|
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayNegAddr, length($iPsoArrayNeg), 0)
|
||||||
elseif $eScanType == ScanType.NegPos
|
MoveAbsolute($axis, $fPosStart, $fVelScan)
|
||||||
if ($ii % 2) == 0
|
end
|
||||||
MoveAbsolute($axis, $fPosEnd, $fVelScan)
|
WaitForMotionDone($axis)
|
||||||
WaitForInPosition($axis)
|
|
||||||
elseif ($ii % 2) == 1
|
$axisFaults = StatusGetAxisItem($axis, AxisDataSignal.AxisFault)
|
||||||
MoveAbsolute($axis, $fPosStart, $fVelScan)
|
if $axisFaults
|
||||||
WaitForInPosition($axis)
|
TaskSetError(TaskGetIndex(), "AxisFault on axis ROTY")
|
||||||
end
|
end
|
||||||
|
Dwell(0.2)
|
||||||
end
|
end
|
||||||
Dwell(0.2)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
// Directly after scan
|
// Directly after scan
|
||||||
PsoDistanceCounterOff($axis)
|
PsoDistanceCounterOff($axis)
|
||||||
DriveDataCaptureOff($axis, 0)
|
DriveDataCaptureOff($axis, 0)
|
||||||
DriveDataCaptureOff($axis, 1)
|
DriveDataCaptureOff($axis, 1)
|
||||||
|
// move back to start position
|
||||||
|
MoveAbsolute($axis, $fPosStart, $fVelJog)
|
||||||
|
WaitForInPosition($axis)
|
||||||
|
Dwell(2)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
158
tomcat_bec/tcatSequenceScanRBV.ascript
Normal file
158
tomcat_bec/tcatSequenceScanRBV.ascript
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
// Test program for simple zig-zag line scanning with PSO window output
|
||||||
|
// "enable" signal and DDC synchronized to external trigger input.
|
||||||
|
// The file expects external parameter validation
|
||||||
|
// The PSO locations arrays are set externally from EPICS PV
|
||||||
|
//
|
||||||
|
#define DDC_ADDR 0x800000
|
||||||
|
#define PSO_ADDR 0x0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
enum ScanType
|
||||||
|
POS = 0
|
||||||
|
NEG = 1
|
||||||
|
POSNEG = 2
|
||||||
|
NEGPOS = 3
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
program
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// External parameters - USE THEESE
|
||||||
|
var $fStartPosition as real = 42
|
||||||
|
var $fScanRange as real = 180
|
||||||
|
var $iNumRepeat as integer = 13
|
||||||
|
var $eScanType as ScanType = ScanType.NEGPOS
|
||||||
|
var $iNumDdcRead as integer = 1300
|
||||||
|
|
||||||
|
var $fVelJog as real = 200
|
||||||
|
var $fVelScan as real = 150
|
||||||
|
var $fAcceleration = 500
|
||||||
|
var $fAccDistance as real = 22.5
|
||||||
|
var $eDdcTrigger as DriveDataCaptureTrigger = DriveDataCaptureTrigger.PsoEvent
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Internal parameters - dont use
|
||||||
|
var $axis as axis = ROTY
|
||||||
|
var $ii as integer
|
||||||
|
var $axisFaults as integer = 0
|
||||||
|
var $iDdcSafeSpace as integer = 4096
|
||||||
|
|
||||||
|
// Set acceleration
|
||||||
|
SetupAxisRampType($axis, RampType.Linear)
|
||||||
|
SetupAxisRampValue($axis, 0, $fAcceleration)
|
||||||
|
|
||||||
|
// set the actual scan range
|
||||||
|
var $fPosStart as real
|
||||||
|
var $fPosEnd as real
|
||||||
|
if $eScanType == ScanType.POS
|
||||||
|
$fPosStart = $fStartPosition - $fAccDistance
|
||||||
|
$fPosEnd = $fStartPosition + $fScanRange + $fAccDistance
|
||||||
|
elseif $eScanType == ScanType.NEG
|
||||||
|
$fPosStart = $fStartPosition + $fAccDistance
|
||||||
|
$fPosEnd = $fStartPosition - $fScanRange - $fAccDistance
|
||||||
|
elseif $eScanType == ScanType.POSNEG
|
||||||
|
$fPosStart = $fStartPosition - $fAccDistance
|
||||||
|
$fPosEnd = $fStartPosition + $fScanRange + $fAccDistance
|
||||||
|
elseif $eScanType == ScanType.NEGPOS
|
||||||
|
$fPosStart = $fStartPosition + $fAccDistance
|
||||||
|
$fPosEnd = $fStartPosition - $fScanRange - $fAccDistance
|
||||||
|
end
|
||||||
|
|
||||||
|
// Move to start position before the scan
|
||||||
|
// NOTE: Also wait for GigaFrost to start, otherwise early triggers might be missed
|
||||||
|
MoveAbsolute($axis, $fPosStart, $fVelJog)
|
||||||
|
WaitForInPosition($axis)
|
||||||
|
Dwell(2)
|
||||||
|
|
||||||
|
// Set globals for feedback
|
||||||
|
$rglobal[2] = $fPosStart
|
||||||
|
$rglobal[3] = $fPosEnd
|
||||||
|
|
||||||
|
// Configure PSO
|
||||||
|
// FIXME : When the controller is restarted
|
||||||
|
PsoDistanceConfigureInputs($axis, [PsoDistanceInput.XC4PrimaryFeedback])
|
||||||
|
PsoDistanceCounterOff($axis)
|
||||||
|
PsoDistanceEventsOff($axis)
|
||||||
|
PsoWindowConfigureEvents($axis, PsoWindowEventMode.None)
|
||||||
|
PsoWaveformOff($axis)
|
||||||
|
// Simple PSO trigger pattern
|
||||||
|
var $iPsoArrayPosAddr as integer = PSO_ADDR
|
||||||
|
var $iPsoArrayPos[] as real = [ UnitsToCounts($axis, 22.5), UnitsToCounts($axis, 180) ]
|
||||||
|
DriveArrayWrite($axis, $iPsoArrayPos, $iPsoArrayPosAddr, length($iPsoArrayPos), DriveArrayType.PsoDistanceEventDistances)
|
||||||
|
|
||||||
|
|
||||||
|
var $iPsoArrayNegAddr as integer = ($iPsoArrayPosAddr + length($iPsoArrayPos)) * 4
|
||||||
|
var $iPsoArrayNeg[] as real = [ UnitsToCounts($axis, 22.5), UnitsToCounts($axis, 180) ]
|
||||||
|
DriveArrayWrite($axis, $iPsoArrayNeg, $iPsoArrayNegAddr, length($iPsoArrayNeg), DriveArrayType.PsoDistanceEventDistances)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayPosAddr, length($iPsoArrayPos), 0)
|
||||||
|
PsoDistanceCounterOn($axis)
|
||||||
|
PsoDistanceEventsOn($axis)
|
||||||
|
|
||||||
|
PsoWaveformConfigureMode($axis, PsoWaveformMode.Toggle)
|
||||||
|
PsoWaveformOn($axis)
|
||||||
|
PsoOutputConfigureSource($axis, PsoOutputSource.Waveform)
|
||||||
|
|
||||||
|
// Configure Drive Data Collection
|
||||||
|
var $iDdcArraySize as integer = $iNumDdcRead
|
||||||
|
|
||||||
|
DriveDataCaptureConfigureInput($axis, 0, DriveDataCaptureInput.PrimaryFeedback);
|
||||||
|
DriveDataCaptureConfigureInput($axis, 1, DriveDataCaptureInput.AnalogInput0 );
|
||||||
|
|
||||||
|
DriveDataCaptureConfigureTrigger($axis, 0, $eDdcTrigger );
|
||||||
|
DriveDataCaptureConfigureTrigger($axis, 1, $eDdcTrigger );
|
||||||
|
|
||||||
|
DriveDataCaptureConfigureArray($axis, 0, DDC_ADDR, $iDdcArraySize);
|
||||||
|
DriveDataCaptureConfigureArray($axis, 1, DDC_ADDR + $iDdcSafeSpace + 8 * $iDdcArraySize, $iDdcArraySize);
|
||||||
|
|
||||||
|
// Directly before scan
|
||||||
|
PsoDistanceCounterOn($axis)
|
||||||
|
DriveDataCaptureOn($axis, 0)
|
||||||
|
DriveDataCaptureOn($axis, 1)
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////
|
||||||
|
// Start the actual scanning
|
||||||
|
///////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
if $eScanType == ScanType.POS || $eScanType == ScanType.NEG
|
||||||
|
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayPosAddr, length($iPsoArrayPos), 0)
|
||||||
|
MoveAbsolute($axis, $fPosEnd, $fVelScan)
|
||||||
|
WaitForMotionDone($axis)
|
||||||
|
|
||||||
|
$axisFaults = StatusGetAxisItem($axis, AxisDataSignal.AxisFault)
|
||||||
|
if $axisFaults
|
||||||
|
TaskSetError(TaskGetIndex(), "AxisFault on axis ROTY")
|
||||||
|
end
|
||||||
|
elseif $eScanType == ScanType.POSNEG || $eScanType == ScanType.NEGPOS
|
||||||
|
for $ii = 0 to ($iNumRepeat-1)
|
||||||
|
// Feedback on progress
|
||||||
|
$rglobal[4] = $ii
|
||||||
|
if ($ii % 2) == 0
|
||||||
|
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayPosAddr, length($iPsoArrayPos), 0)
|
||||||
|
MoveAbsolute($axis, $fPosEnd, $fVelScan)
|
||||||
|
elseif ($ii % 2) == 1
|
||||||
|
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayNegAddr, length($iPsoArrayNeg), 0)
|
||||||
|
MoveAbsolute($axis, $fPosStart, $fVelScan)
|
||||||
|
end
|
||||||
|
WaitForMotionDone($axis)
|
||||||
|
|
||||||
|
$axisFaults = StatusGetAxisItem($axis, AxisDataSignal.AxisFault)
|
||||||
|
if $axisFaults
|
||||||
|
TaskSetError(TaskGetIndex(), "AxisFault on axis ROTY")
|
||||||
|
end
|
||||||
|
Dwell(0.2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// Directly after scan
|
||||||
|
PsoDistanceCounterOff($axis)
|
||||||
|
DriveDataCaptureOff($axis, 0)
|
||||||
|
DriveDataCaptureOff($axis, 1)
|
||||||
|
// move back to start position
|
||||||
|
MoveAbsolute($axis, $fPosStart, $fVelJog)
|
||||||
|
WaitForInPosition($axis)
|
||||||
|
Dwell(2)
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user