Inventory¶
The 2-BM equipment inventory: the CORA Asset model view (the device tree, settings, vendor Models, drawings, and signal wiring) plus the computed axes. Live condition is served by the app, not this page.
Assets¶
One row per registered Asset under the 2-BM root (tier = Unit, bound to its Site Facility via facility_code). Hutches 2-BM-A (optics) / 2-BM-B (experiment) are Enclosures, not Assets. Condition is served live by the app.
| Asset | Family | Model | Parent | Key settings | Condition |
|---|---|---|---|---|---|
StationShutter |
Shutter |
(none cited) | 2-BM |
- | live |
SampleTable |
Table |
(none) | 2-BM |
axis_layout=translation_xyz |
live |
RotaryDriveChassis |
Housing |
aerotech_tm3a |
2-BM |
serial 160591-A-1-1, order 730578 |
live |
RotaryDrive |
MotionController |
aerotech_ensemble_ml |
RotaryDriveChassis |
serial 730792/1, axis_count=1, Aerotech_Native |
live |
Rotary |
RotaryStage |
aerotech_abrs250mp |
LaminographyPitch |
-360..360 deg, max_speed=720 deg/s (operational), aperture=35 mm, encoder_resolution=0.000676 deg |
live |
SampleStageDrive |
MotionController |
oms_vme58 |
2-BM |
axis_count=91, OMS_VME |
live |
FrontEndDrive |
MotionController |
oms_vme58 |
2-BM |
axis_count=91, OMS_VME |
live |
FrontEndWindow |
Window |
(none) | 2-BM |
OFHC-housed Be window assembly; identity-only (beam-effect deferred) | live |
Window_W4_20 |
Window |
(none) | FrontEndWindow |
Be 0.25 mm, z 28718, aperture 120 x 15 mm | live |
Window_W4_60 |
Window |
(none) | FrontEndWindow |
Be 0.13 mm, z 30804, aperture 25 x 120 mm | live |
Window_DS |
Window |
(none) | FrontEndWindow |
Be 0.25 mm, z 32417, aperture 8.8 x 145 mm (unlabelled, downstream-most) | live |
Mirror |
Mirror |
(none) | MirrorTable |
driven by FrontEndDrive; 4 coating stripes (a/b/c/d), held in Mono, swept per Pink energy (MIRROR-1) |
live |
Mirror_StripeReachX |
PseudoAxis |
(none) | Mirror |
m1_horizontal (2bma:m3); Mono held at stripe a, Pink swept per energy |
live |
MirrorTable |
Table |
(none) | 2-BM |
axis_layout=virtual_pose, virtual_record=2bma:table1 |
live |
Monochromator |
Monochromator |
(none) | 2-BM |
dmm_insertion=inserted (MODE-2); driven by FrontEndDrive |
live |
Monochromator_BraggArmUpstream |
PseudoAxis |
(none) | Monochromator |
energy->upstream Bragg arm (deg) | live |
Monochromator_BraggArmDownstream |
PseudoAxis |
(none) | Monochromator |
energy->downstream Bragg arm (deg) | live |
Monochromator_M2Y |
PseudoAxis |
(none) | Monochromator |
energy->M2 vertical offset (mm) | live |
ConditioningSlit |
Slit |
(none) | 2-BM |
white-beam slits; driven by FrontEndDrive |
live |
Filter |
Filter |
(none) | 2-BM |
foil changer; driven by FrontEndDrive |
live |
Filter_FoilSelector_Upstream |
PseudoAxis |
(none) | Filter |
m17 slot index -> position (Nearest); operational selector | live |
Filter_FoilSelector_Downstream |
PseudoAxis |
(none) | Filter |
m18 slot index -> position (Nearest); bindings retained | Faulted (m18 failed 2026-06-19) |
DiagnosticFlag |
Screen |
(none) | 2-BM |
2bma:m44 at z=32500; raised in Mono, parked in Pink |
live |
DiagnosticFlag_Y |
PseudoAxis |
(none) | DiagnosticFlag |
energy->flag height (Mono); parked out in Pink | live |
SampleSlit |
Slit |
(none) | 2-BM |
B-station slits; driven by FrontEndDrive |
live |
SampleSlit_VerticalTop |
PseudoAxis |
(none) | SampleSlit |
energy->top blade beam position (mm) | live |
SampleSlit_VerticalBottom |
PseudoAxis |
(none) | SampleSlit |
energy->bottom blade beam position (mm) | live |
SampleSlit_VerticalCenter |
PseudoAxis |
(none) | SampleSlit |
derived MidRange(top, bot); beam-walk centre |
live |
SampleSlit_VerticalAperture |
PseudoAxis |
(none) | SampleSlit |
derived Difference(top, bot); constant 20 mm gap |
live |
SampleTop_X |
LinearStage |
kohzu_cyat070 |
Rotary |
-10..10 mm, max_speed=1 mm/s, encoder_resolution=0.0005 mm |
live |
SampleTop_Z |
LinearStage |
kohzu_cyat070 |
SampleTop_X |
same Model/controller as SampleTop_X |
live |
HexapodDrive |
MotionController |
aerotech_automation1_ixr3 |
2-BM |
serial 486125-01, axis_count=6, Aerotech_Native |
live |
Hexapod |
Hexapod |
aerotech_hex300 |
SampleTable |
serial 486060-01; full HEX300 envelope (see Settings) |
live |
Hexapod_X |
PseudoAxis |
(none) | Hexapod |
DoF; translation X | live |
Hexapod_Y |
PseudoAxis |
(none) | Hexapod |
DoF; translation Y | live |
Hexapod_Z |
PseudoAxis |
(none) | Hexapod |
DoF; translation Z; modelled, not wired in current EPICS | modelled (unwired) |
Hexapod_Roll |
PseudoAxis |
(none) | Hexapod |
DoF; rotation A about X | live |
Hexapod_Pitch |
PseudoAxis |
(none) | Hexapod |
DoF; rotation B about Y | live |
Hexapod_Yaw |
PseudoAxis |
(none) | Hexapod |
DoF; rotation C about Z; modelled, not wired in current EPICS | modelled (unwired) |
LaminographyPitch |
TiltStage |
kohzu_sa16a |
Hexapod |
Kohzu SA16A 2bmb:m49; tomo/lamino = tilt setpoint |
live |
PropagationDistanceDrive |
MotionController |
aerotech_ensemble_hle |
2-BM |
serial 228849-02, axis_count=1, Aerotech_Native |
live |
Timing |
TimingController |
(none) | 2-BM |
softGlueZynq trigger box; protocol=EPICS; no controller_id |
live |
ApertureFineDrive |
MotionController |
piezosystem_jena_nv200d |
2-BM |
two Jena NV200D units; fine-positions the Aperture coded-mask; FPGA-stepped via Timing |
live |
DetectorTable |
Table |
(none) | 2-BM |
axis_layout=virtual_pose, virtual_record=2bmb:table3 |
live |
DetectorTable_X |
PseudoAxis |
(none) | DetectorTable |
IOC virtual axis; 2bmb:table3.X |
live |
DetectorTable_Y |
PseudoAxis |
(none) | DetectorTable |
IOC virtual axis; 2bmb:table3.Y |
live |
DetectorTable_Z |
PseudoAxis |
(none) | DetectorTable |
IOC virtual axis; 2bmb:table3.Z |
live |
DetectorTable_Roll |
PseudoAxis |
(none) | DetectorTable |
IOC virtual axis; raw AZ; 2bmb:table3.AZ |
live |
DetectorTable_Pitch |
PseudoAxis |
(none) | DetectorTable |
IOC virtual axis; raw AX; 2bmb:table3.AX |
live |
DetectorTable_Yaw |
PseudoAxis |
(none) | DetectorTable |
IOC virtual axis; raw AY; 2bmb:table3.AY |
live |
Housing |
Housing |
(none) | PropagationDistance |
Microscope chassis; installed into a Mount | live |
Turret |
LinearStage |
(microscope catalog) | Housing |
-60.3784..59.2300 mm (DET-11), encoder_resolution=0.0016 mm |
live |
Objective_10x |
Objective |
(microscope catalog) | Housing |
mag 10.0, NA 0.28, WD 33.5 mm | live |
Objective_2x |
Objective |
(microscope catalog) | Housing |
mag 2.0, NA 0.055, WD 34 mm | live |
Objective_1.1x |
Objective |
(microscope catalog) | Housing |
mag 1.1, NA 0.03, WD 50 mm | live |
Objective_Selector |
PseudoAxis |
(none) | Housing |
writes MCTOptics LensSelect; (lens x camera) turret lookup, Camera 0 column as 1D provenance rule (DET-11) |
live |
PropagationDistance |
LinearStage |
aerotech_pro225sl |
DetectorTable |
sample-to-detector rail; driven by PropagationDistanceDrive |
live |
Camera |
Camera |
(microscope catalog) | Housing |
5 MP FLIR Oryx; 2448x2048, 3.45 um, 12 bit, 162 Hz, CMOS GlobalShutter | live |
Camera_HighRes |
Camera |
flir_oryx_31mp |
Housing |
31 MP FLIR Oryx; pixel 3.45 um; other settings pending | live (settings pending) |
Camera_Selector |
LinearStage |
schunk_lptm_30 |
Housing |
Schunk LPTM 30; Pos.0=20, Pos.1=15; stage settings pending | live (settings pending) |
Scintillator |
Scintillator |
(microscope catalog) | Housing |
thickness 100 um, decay 0.07 us | live |
Microscope-bound Models (turret motor, Mitutoyo MPLAPO kit, FLIR Oryx, Crytur LuAG) live on the Microscope deployment page. The kohzu_sa16a binding for LaminographyPitch is on the Sample tower page.
Settings¶
Per-asset settings the source spells out in prose. Open-item tags (DRIVE-1, DRIVE-2) kept inline.
| Asset | Settings |
|---|---|
SampleTable |
axis_layout=translation_xyz; direct motors 2bmb:m24 Y, 2bmb:m20 Z, 2bmb:m21 X-up, 2bmb:m22 X-down |
DetectorTable |
axis_layout=virtual_pose; virtual_record=2bmb:table3; geometry=SRI: 3 Y-supports, 2 X-supports, 1 Z-support |
MirrorTable |
axis_layout=virtual_pose; virtual_record=2bma:table1; geometry=SRI support table; X axes M0X/M2X driven by energy-change IOC. Stale: upstream removed the 2bma:table1 record on 2026-06-15, so this virtual-pose layout no longer matches the beamline; re-modelling onto the raw motors is open as MODE-3 |
Monochromator |
dmm_insertion=inserted (closed enum inserted | retracted, MODE-2); DMM Y motors 2bma:m26 / m27 / m29 to 0 in (Mono) / -10 mm out (Pink); driven by FrontEndDrive |
RotaryDrive |
serial_number=730792/1; firmware_version=unknown-pending-confirmation (DRIVE-2); axis_count=1; protocol=Aerotech_Native; installed in RotaryDriveChassis |
RotaryDriveChassis |
altids: serial 160591-A-1-1 (SerialNumber), order 730578 (Other); drawing 630D2079 REV-H; inventory-only, no command surface |
PropagationDistanceDrive |
serial_number=228849-02; firmware_version=unknown-pending-confirmation (DRIVE-2); axis_count=1; protocol=Aerotech_Native; IOC handle 2bmbAERO (EPICS_PV altid); addressed 2bmbAERO:m1 |
SampleStageDrive |
serial_number=unknown-pending-confirmation (DRIVE-1); firmware_version=unknown-pending-confirmation (DRIVE-2); axis_count=91; protocol=OMS_VME; crate ioc2bmb, no IP (VME-bus) |
FrontEndDrive |
serial_number=unknown-pending-confirmation (DRIVE-1); firmware_version=unknown-pending-confirmation (DRIVE-2); axis_count=91; protocol=OMS_VME; crate ioc2bma, no IP (VME-bus) |
HexapodDrive |
serial_number=486125-01; firmware_version=unknown-pending-confirmation (DRIVE-2); axis_count=6; protocol=Aerotech_Native; Automation1-iXR3 in separate rack |
Timing |
firmware_version=2.0 (softGlueZynq gateware/bitstream); serial_number=unknown (IOC-admin only, not beamline-retrievable); output_channel_count=unknown (IOC-admin only, not beamline-retrievable); protocol=EPICS; 2bmbMZ1:SG: |
Rotary |
min_position=-360 deg; max_position=360 deg; max_speed=720 deg/s (operational soft limit); max_speed_datasheet=3000 deg/s (500 rpm); encoder_resolution=0.000676 deg; homing_offset=0 deg; aperture=35 mm; accuracy_rotation=2 arcsec; repeatability_rotation=1 arcsec; load_capacity_axial=66 kg; load_capacity_radial=36 kg; load_capacity_tilt=28 Nm; stage_mass=15.6 kg; altid serial 146853-A-1-1-X; part ABRS-250MP-M-AS; datasheet on file (#164) |
SampleTop_X |
min_position=-10 mm; max_position=10 mm; max_speed=1 mm/s; encoder_resolution=0.0005 mm; channel 2bmb:m18 |
SampleTop_Z |
same Model kohzu_cyat070 + controller as SampleTop_X; channel 2bmb:m17 |
Hexapod |
travel_x=55 mm, travel_y=60 mm, travel_z=25 mm, travel_a=15 deg, travel_b=15 deg, travel_c=30 deg; max_speed_translation=25 mm/s, max_speed_rotation=15 deg/s; resolution_translation=20 nm, resolution_rotation=0.2 urad; accuracy_translation=1 um, accuracy_rotation=10 urad; load_capacity_vertical=45 kg, load_capacity_horizontal=21 kg; stage_mass=12 kg; altid serial 486060-01; part HEX300-230HL-E1-PL4-TAS; datasheet on file (Hex300-Data-Sheet-D20250203). The speed and accuracy pairs are dominant-axis envelope figures, not per-DoF measurements |
Scintillator |
thickness=100 um; decay_time=0.07 us |
Camera |
sensor_width=2448 pixel; sensor_height=2048 pixel; pixel_size=3.45 um; bit_depth=12 bit; max_framerate_hz=162 Hz; sensor_kind=CMOS; readout_mode=GlobalShutter; altids model Oryx ORX-10G-51S5M, serial 19173710, firmware 1710.0.0.0, EPICS 2bmSP1: |
Camera_HighRes |
model Oryx ORX-10G-310S9M; serial 22150530; firmware 1904.0.72.0; EPICS 2bmSP2:; pixel_size=3.45 um; remaining Camera-schema settings pending |
Camera_Selector |
Schunk LPTM 30 (2bmb:m5); Pos.0=20, Pos.1=15; min/max/max_speed/encoder_resolution pending |
Turret |
min_position=-60.3784 mm; max_position=59.2300 mm; encoder_resolution=0.0016 mm; Nanotec ST4118M1404-B, Heidenhain ERO 1420 encoder; MCTOptics resolves the (lens x camera) position (DET-11), Camera 0 column: 1.1x=-59.8184 mm, 2x=-0.5734 mm, 10x=58.8707 mm |
Objective_10x |
magnification=10.0; numerical_aperture=0.28; working_distance=33.5 mm |
Objective_2x |
magnification=2.0; numerical_aperture=0.055; working_distance=34 mm |
Objective_1.1x |
magnification=1.1; numerical_aperture=0.03; working_distance=50 mm |
Vendor catalog¶
Models bound to non-microscope 2-BM Assets. Model ids are derived from (manufacturer, part number), so one vendor product converges on one id. Microscope-housing Models are on the Microscope deployment page.
Generated from the catalog
This table is generated from catalog/catalog.yaml. Edit the catalog, not this table.
| Model | Manufacturer | Part number | Used by |
|---|---|---|---|
aerotech_hex300 |
Aerotech | HEX300-230HL-E1-PL4-TAS |
Hexapod |
aerotech_abrs250mp |
Aerotech | ABRS-250MP-M-AS |
Rotary |
aerotech_ensemble_ml |
Aerotech | ENSEMBLEML 10-40-IO-MXH |
RotaryDrive |
aerotech_automation1_ixr3 |
Aerotech | Automation1-iXR3-VL1-VB4-VB4-SB0CT222222-P1P1P1P1P1P1-CO-LC1MT1PSO6-SI0-TAS |
HexapodDrive |
aerotech_ensemble_hle |
Aerotech | EnsembleHLe10-40-A-IO-MXH |
PropagationDistanceDrive |
aerotech_pro225sl |
Aerotech | PRO225SL-1000 |
PropagationDistance |
aerotech_tm3a |
Aerotech | TM3-A-20B VDC-20B VDC / NO SPLIT / PS24-1 / C1ML-06 / C2ML-09 / US-115VAC |
RotaryDriveChassis |
oms_vme58 |
Oregon Micro Systems | VME58 |
SampleStageDrive, FrontEndDrive |
kohzu_cyat070 |
Kohzu | CYAT-070 |
SampleTop_X, SampleTop_Z |
piezosystem_jena_nv200d |
Piezosystem Jena | NV200D/NET |
ApertureFineDrive |
Controller back-references: RotaryDrive->Rotary.controller_id; HexapodDrive->Hexapod.controller_id; PropagationDistanceDrive->PropagationDistance.controller_id (IOC 2bmbAERO); SampleStageDrive->SampleTop_X (2bmb:m18) / SampleTop_Z (2bmb:m17) + 89 further motors on ioc2bmb; FrontEndDrive->Mirror, Monochromator, ConditioningSlit, SampleSlit, Filter on ioc2bma. The Objective_Selector (2bmb:m1) and Camera_Selector (2bmb:m5) steppers run through the SampleStageDrive OMS crate, not distinct controller Assets. The six Hexapod_* DoF facets bind no Model (the physical Hexapod carries aerotech_hex300).
Engineering drawings¶
One canonical (system, number, revision) triple per Asset, except Rotary, which cites both its per-unit vendor drawing and the ABRS family datasheet. Optique Peter MAN-11863 (rev 0521-0465-A) is the shared housing manual covering every Microscope-bound constituent.
| Asset | Drawing | System |
|---|---|---|
Hexapod |
Hex300-Data-Sheet rev D20250203 |
EDMS |
Rotary |
630C2125 rev (-) |
EDMS |
Rotary |
ABRS series datasheet (2021-01) | Aerotech |
RotaryDriveChassis |
630D2079 rev H |
EDMS |
PropagationDistance |
MAN-11863 rev 0521-0465-A |
EDMS |
Turret |
MAN-11863 rev 0521-0465-A |
EDMS |
Objective_10x |
MAN-11863 rev 0521-0465-A |
EDMS |
Objective_2x |
MAN-11863 rev 0521-0465-A |
EDMS |
Objective_1.1x |
MAN-11863 rev 0521-0465-A |
EDMS |
Scintillator |
MAN-11863 rev 0521-0465-A |
EDMS |
StationShutter |
41050401-410003 rev (-) (P6-50 shutter element; assembly 41050401-500000) |
ICMS |
Mask |
4102020101-240000 (M3-24 front-end exit mask; RSS 02-BM-A-F-01) |
ICMS |
Window_W4_20 |
4105090804-200000 (front-end Be window W4-20) |
ICMS |
Window_W4_60 |
4105090804-600000 (front-end Be window W4-60) |
ICMS |
Window_DS |
4102020106-400000 (front-end Be window, unlabelled, downstream-most) |
ICMS |
Not yet cited: Kohzu CYAT-070 datasheet (SampleTop_*), a FLIR Oryx datasheet (Camera).
Signal wiring¶
Trigger and step signals are modelled as typed ports plus wires resolved at Plan-bind time. Executable model: apps/api/tests/integration/scenarios/test_2bm_trigger_wiring.py.
Fine-positioning piezo controllers¶
ApertureFineDrive= two Piezosystem Jena NV200D/NET single-channel controllers (staff item_028), one per axis (X10.54.113.126, Y10.54.113.125), EPICS IOCJenaNV200Don hostarcturus. They fine-position theAperturecoded-mask via a nanoSXY 120 CAP XY flexure stage (partT-223-06D, 120 um nominal / 100 um closed-loop per axis, 12.5 mm clear aperture); the axes step under FPGA trigger for compressive-sensing dithered sampling (PIEZO-1/2/4).- The Jena NV100D (formerly the provisional
OpticsFineDrive, IOCJenaNV100D) is physically present but not in operational use at 2-BM: it lacks the external trigger mode tomoscan fly-scan needs, so no Run drives it. Recorded as provenance, not modelled as an active controller. - The driven X/Y
LinearStageaxis Assets and theApertureidentity registration are deferred to a follow-up slice. The FPGAout2/out3-> X/Y cable map is confirmed (PIEZO-5, see below).
NV200D trigger wiring¶
| Asset | Port | Direction | signal_type |
|---|---|---|---|
Timing |
out2, out3 |
OUTPUT | step_trigger_ttl |
ApertureFineDrive |
step_x_in, step_y_in |
INPUT | step_trigger_ttl |
- Wires:
Timing.out2 -> ApertureFineDrive.step_x_in,Timing.out3 -> ApertureFineDrive.step_y_in; up to 1024 positions/axis. - Per-axis chain, confirmed end to end by a physical patch-panel trace on 2026-07-28 (PIEZO-5, staff item_020):
| Axis | FPGA out | softGlue signal | Gate-delay PV | NV200D TRG IN |
|---|---|---|---|---|
| X | out2 |
JenaX |
2bmbMZ1:SG:GateDly-2_DLY |
10.54.113.126 |
| Y | out3 |
JenaY |
2bmbMZ1:SG:GateDly-3_DLY |
10.54.113.125 |
- CORA previously recorded the two gate-delay PVs with their axes reversed and flagged the result as a cable-map contradiction. There was no contradiction: the axis comments in staff
item_028were themselves wrong, and the same trace corrected them (2bm-docsa3aa6be0). The cable map was right throughout, so the wires above are unchanged; only the delay-PV association moved. An operator screen still carrying the old annotation would point at the wrong axis's delay, which is why the binding is recorded per axis rather than as a PV list. - Ports sit on the controller box today; they migrate onto per-axis Assets when registered.
Camera trigger wiring¶
| Asset | Port | Direction | signal_type |
|---|---|---|---|
Timing |
out1 |
OUTPUT | frame_trigger_ttl |
Camera |
trigger_in |
INPUT | frame_trigger_ttl |
- One wire:
Timing.out1 -> Camera.trigger_in.frame_trigger_ttl(start exposure) is distinct from the piezostep_trigger_ttl(advance a motion step). - Signal path (TIME-2):
PSO -> MUX2-1 -> GateDly1 -> outTrig -> FPGA out1 -> FLIR Oryx Line2. The port is named for the pin, matchingout2/out3;outTrigis the softGlue signal carried on it, andLine2is the camera-side input for both installed Oryx bodies. - Pulse shaping on this leg is the
GateDly1block, whose PV fields are dot-separated record fields (2bmbMZ1:SG:GateDly1.DLY,.Width) where the two piezo legs use flat underscore names (GateDly-2_DLY,_WIDTH). The three blocks are peers in function but not in PV form, so each is recorded verbatim rather than derived from a template. They are not registered as Assets: nothing yet needs to address a gate-delay block by identity. - softGlue
Width/DLYcount 10 MHz clock cycles (100 ns/count, soWidth=100= 10 us pulse); per-scan values are Method/Plan config.
Computed axes¶
The PseudoAxis Assets whose position is computed from the motors underneath, divided by who owns the math: firmware SolverReference (hexapod), an edge IOC with no rule (detector table), or a Calibration-backed LookupTable (energy axes and foil selector). Executable models cited per subsection.
Hexapod DoF model¶
One physical Device (vendor-sealed Aerotech HEX300; inverse kinematics in firmware solver 2bmHXP). Six DoF surfaced as PseudoAxis sub-modules, each carrying a SolverReference partition rule; per-DoF envelope stays on the Hexapod settings, not duplicated onto facets.
| DoF Asset | Kind | Axis | Vendor label | EPICS channel |
|---|---|---|---|---|
Hexapod_X |
translation | along X | n/a | 2bmHXP:m1 |
Hexapod_Y |
translation | along Y | n/a | 2bmHXP:m2 |
Hexapod_Z |
translation | along Z | n/a | none (no operator handle) |
Hexapod_Roll |
rotation | about X | A (travel_a) |
2bmHXP:m5 |
Hexapod_Pitch |
rotation | about Y | B (travel_b) |
2bmHXP:m4 |
Hexapod_Yaw |
rotation | about Z | C (travel_c) |
none (no operator handle) |
- Z and Yaw exist physically but are not exposed as operator channels in 2-BM's current EPICS (no
m3/m6); CORA still models all six (deployment-configuration limit, not a device one). - Constituent-port wiring: each DoF reads feedback from
HexapodviaPlan.wires(not a partition-rule field).Hexapodexposesx/y/z_feedback_out(position_feedback_linear_mm) androll/pitch/yaw_feedback_out(position_feedback_rotation_deg); each facet has oneconstituent_inINPUT plus one<axis>_outsetpoint OUTPUT. Six wires, one per DoF (Hexapod.<axis>_feedback_out -> Hexapod_<Axis>.constituent_in).validate_pseudoaxis_fanoutexemptsSolverReferencefrom the arity check; decomposition is owned by the firmware solver. - Dial-to-user coordinate convention,
user = dial home + OFFSET, confirmed 2026-07-28 (HXP-8). Y is the axis where the two differ: it homes at dial 350 withOFFSET = -350, so a homed Y reads user 0. The other axes carry their own pair. The source states the Y numbers without a unit; they are recorded as given rather than assigned one. This is calibration state, not an advisory: it replaces an earlier Caution that described a manual post-reboot dial correction which is no longer performed. What re-homes the axes is HXP-9.
Detector table axes¶
Six virtual axes on the 2bmb:table3 record, modelled as PseudoAxis sub-Assets of DetectorTable. No partition rule and no constituent wiring: the table_full IOC computes the pose from six support motors (M0X / M0Y / M1Y / M2X / M2Y / M2Z) in SRI geometry. Addressing is a direct ControlPort write to the table3.* PV (spine/edge seam). Model: apps/api/tests/integration/scenarios/test_2bm_optical_tables_setup.py.
| Axis Asset | Kind | table3 field |
Raw label |
|---|---|---|---|
DetectorTable_X |
translation | .X |
n/a |
DetectorTable_Y |
translation | .Y |
n/a |
DetectorTable_Z |
translation | .Z |
n/a |
DetectorTable_Pitch |
rotation | .AX |
AX |
DetectorTable_Yaw |
rotation | .AY |
AY |
DetectorTable_Roll |
rotation | .AZ |
AZ |
Angular mapping (AX=pitch, AY=yaw, AZ=roll) is staff-confirmed (STAGE-9).
Energy-tracking optic axes¶
Setting energy is a discrete coordinated move. The staff energy-change IOC stores per-energy positions (store_0 saved table) and drives ~15 motors. Each per-axis relationship is modelled as a continuous curve: a PseudoAxis carrying a LookupTable partition rule converting energy (unit_in=keV) to axis position, pinning a Calibration revision by id (energy_position_curve quantity). Each axis carries a Mono curve (beam_mode=mono, the active rule) and a sibling Pink curve (beam_mode=pink, parked constant). invertible is per-axis: the Bragg arms + M2Y are monotonic in energy (invertible=True); the slit blades (constant 20 mm aperture, non-monotonic centre walk) and the flag Y (flat at the top of its range) are invertible=False with readback_aggregator_kind=Identity. Coordinating operation = the energy_setting Procedure, which accepts a free keV value between saved points. Models: test_2bm_energy_curves_setup.py (curves) + test_2bm_energy_setting.py (operation).
Configured Mono energies (the curve x-points, real): 13.374, 13.574, 18.0, 20.0, 25.0, 25.584 keV; Pink: 30, 40, 50, 60 keV (axes parked). Pink mode bypasses the monochromator. Beam-mode switching itself is on the Procedures page, not a virtual axis.
| Axis Asset | Motors / handle | Curve | unit_out |
|---|---|---|---|
Monochromator_BraggArmUpstream |
dmm_us_arm |
energy -> upstream Bragg arm | deg |
Monochromator_BraggArmDownstream |
dmm_ds_arm |
energy -> downstream Bragg arm | deg |
Monochromator_M2Y |
dmm_m2_y |
energy -> M2 vertical offset compensator | mm |
SampleSlit_VerticalTop |
b_slit_top |
energy -> top blade beam-walk | mm |
SampleSlit_VerticalBottom |
b_slit_bot |
energy -> bottom blade beam-walk | mm |
DiagnosticFlag_Y |
energy_move_flag (2bma:m44) |
energy -> flag height (Mono), parked out in Pink | mm |
Mirror_StripeReachX |
m1_horizontal (2bma:m3) |
held at stripe a in Mono (m3 1.0), swept per Pink energy (3.039/13/39/49) | mm |
- Slit aperture is held constant at 20 mm; only the centre tracks the beam walk (non-monotonically). The centre and aperture are modelled as derived axes:
SampleSlit_VerticalCenter(AggregationMidRange) andSampleSlit_VerticalAperture(AggregationDifference) over the two blades.Aggregationis one-way (computed from constituents), so they are read-only views. The rules declare the relationship; binding the two specific blades via constituent port wiring (the hexapod-pose pattern) is deferred with the rest of the per-facet conduct wiring. - DMM insert/bypass (MODE-2): the DMM is physically inserted in Mono and retracted in Pink. This two-state, mode-keyed position is NOT a per-energy curve; it is the
dmm_insertionsetting on theMonochromator(closed enuminserted|retracted, theTable.axis_layoutpattern), with the three DMM Y motors (2bma:m26/m27/m29, driven together to0in /-10mm out) documentary inbeamline.yaml. The coordinated move that drives it is the deferredbeam_mode_change(MODE-3 / MIRROR-1). - Mirror coating stripe (MIRROR-1 / MODE-3): the stripe selector
m1_horizontal(2bma:m3) is held at stripe a in Mono (constant m3 1.0) and swept per Pink energy (3.039 / 13 / 39 / 49 mm at 30 / 40 / 50 / 60 keV), modelled as theMirror_StripeReachXfacet (constant Mono curve + swept Pink sibling,invertible=False). The named-stripe-to-position map (a Pt / b,c,d W-Si) is in theMirrorstripeslist inbeamline.yaml. The coordinated mirror-table X move (m1mox/m1m2x=2bma:m1/m4) that stripe d needs at 60 keV stays deferred to itsMirrorTablevirtual_pose axes (2bm-docs#171); the mirror angle is constant 2.615 mrad across all modes/energies. - Not energy axes:
crystal2_z(M2 Z,2bma:m8) is a setup translation the IOC does not drive, so it carries no curve. - DMM substrate stripe is a one-time setup, not a per-energy selector (ENERGY-6, settled): the substrate carries two W-B4C/Si multilayer stripes (periods 24 and 13.8 angstrom, 4 mm apart), recorded as the
Monochromatorstripeslist withactive_stripe=24.0inbeamline.yaml. The 24 angstrom stripe is the in-beam one (inferred from Bragg-arm geometry); the 13.8 angstrom stripe is never calibrated intostore_0. The lateral X motors2bma:m25/2bma:m28are constant alignment positions in both modes (ENERGY-5), not stripe selectors, so CORA models no DMM stripe-selector axis. Switching stripes would be a 4 mm lateral move plus a full recalibration, outside any current move. - Curves carry the REAL saved
store_0positions (ENERGY-1/2, FLAG-1): full 6-energy Mono curves plus parked Pink curves. Runtimeeval_lookup_tableis wired; out-of-range refuses (extrapolation_kind=Error, staff-confirmed ENERGY-4: the inter-mode band 25.584-30 keV is not bridgeable by interpolation). - Recalibration updates these curves in place: the
energy_characterizationProcedure (channel-cut rocking curve, item_022) re-saves the corrected positions as a new revision of the affectedenergy_position_curve,MeasuredSource-cited, preserving the prior revision as history. There is no separate energy offset (ENERGY-8).
Filter foil selection¶
Discrete "pick one of N" move. Two PseudoAxis facets under Filter (Filter_FoilSelector_Upstream for the operational 2bma:m17, Filter_FoilSelector_Downstream for the 2bma:m18), each carrying a LookupTable rule with interpolation_kind=Nearest backed by its own index_position_table Calibration. extrapolation_kind=Error (cannot select an absent foil); invertible=False with readback_aggregator_kind=Identity. The downstream m18 paddle failed 2026-06-19 (parked 107.19 mm), modelled condition Faulted with bindings retained and lifecycle still Active; m17 is the sole operational selector. Runtime proven end-to-end in apps/api/tests/integration/test_pseudoaxis_roundtrip.py; model: test_2bm_filter_foil_setup.py.
Upstream paddle (2bma:m17), the operational selector, slot positions (REAL, from the 2filter_setup.adl admin screen):
| Slot index | Material | Position |
|---|---|---|
| 0 | 1 mm C |
2 |
| 1 | 150 um Al |
25 |
| 2 | 600 um Al |
52 |
| 3 | 1 mm Al |
79 |
| 4 | None |
106 |
Downstream paddle (2bma:m18), Faulted since 2026-06-19, bindings retained, slot positions (REAL, staff-published):
| Slot index | Material | Position |
|---|---|---|
| 0 | 600 um Al |
0 |
| 1 | 150 um Al |
26 |
| 2 | 300 um C |
53 |
| 3 | 50 um C |
80 |
| 4 | None |
106 |
The slot index is the selector's own index, 0 to 4, and the position is where that slot sits on the paddle in mm. Command the index, never the position. The two columns are not interchangeable and the runtime cannot catch the confusion for you: extrapolation_kind=Error refuses only an index outside 0 to 4, so a mistyped 53 is rejected, but a position that happens to fall inside that range is not. Commanding 2 on the upstream paddle selects slot 2 (600 um Al), not the slot sitting at position 2 mm (1 mm C). The downstream unit is staff-confirmed (caget 2bma:m18.EGU, FOIL-1); the upstream positions come from the 2filter_setup.adl admin screen in the same mm unit. Foil ATTENUATION (Attenuable) and the energy-dependent mirror coating stripe (2bma:m3) are deliberately out of scope here (the stripe is modelled with the beam-mode work).