|
APIs, concepts, guides, and more
|
Capture positions, velocities, I/O, and any other controller value sample-exactly in real-time RMP firmware, then collect the records from the non-real-time host by polling or interrupts for tuning, debugging, and analysis.
A Recorder is a data logger that runs inside the RMP firmware, in real-time. You tell it which values to capture (a list of firmware addresses) and how often to capture them (every N samples). From then on, the firmware copies those values into a buffer in controller memory as part of its deterministic real-time cycle. Every record is sample-exact, with no gaps and no host-side jitter.
Your host application, on the other hand, is not real-time. Windows and Linux thread scheduling makes no timing guarantees, and with a Recorder it never needs any. Because the real-time firmware has already captured every sample into the buffer, the host has no trouble getting data for every single sample: it simply drains the buffer at whatever pace the operating system allows, by polling or by waiting on interrupts.
That split is the whole point: the real-time firmware guarantees perfect capture timing, while the non-real-time host only has to keep up on average and still receives every record.
| At a glance | |
|---|---|
| Recorders per controller | Up to 128 (RecorderCountMaximum) |
| Values per record | Up to 32 addresses, captured together in the same sample |
| Record period | 0 to 32,767 samples between records (RecorderPeriodSet) |
| Buffering | One-shot (stop when full) or circular (RecorderCircularBufferSet) |
| Start / stop | Manual, or automatic on Axis / MultiAxis motion (RecorderConfigureToTriggerOnMotion) |
| Collection | Host polling, or RECORDER_HIGH / RECORDER_FULL / RECORDER_DONE interrupts |
Reading values from your application loop works for casual monitoring, but your application is not real-time: the operating system schedules your loop, not the sample clock. Host-side polling skips samples, jitters, and aliases exactly when things get interesting. A Recorder moves the capture into the real-time firmware, which logs every sample deterministically, so even a non-real-time host collects a complete, sample-exact record by draining the buffer at its leisure. That makes the Recorder the right tool whenever timing fidelity matters:
If you want the firmware to act on values rather than record them, you are looking for a different tool:
| You want to... | Use |
|---|---|
| Log values every sample for later analysis | Recorder (this page) |
| Trigger an action when a condition is met | User Limits |
| Compute new values in firmware each sample | Math Blocks |
| Latch a position on a hardware input edge | Capture |
Every Recorder follows the same five steps: allocate, configure, start, collect, stop.
Firmware ships with zero recorders enabled. Reserve however many you need with RecorderCountSet:
When code you do not control may also use recorders (RapidSetup's tuning tools do, for example), append rather than assume recorder 0 is free:
Tell the recorder how often to record, how many values per record, and the address of each value:
Anything with a firmware address can be recorded. The usual sources:
| Source | Method | Examples |
|---|---|---|
| Axis values | AddressGet with RSIAxisAddressType | Actual/command position, velocity, position error |
| Controller values | AddressGet with RSIControllerAddressType | Sample counter, timing deltas, user buffer, sync group state |
| I/O points | AddressGet | Digital/analog inputs and outputs |
| Network PDO data | NetworkInputAddressGet / NetworkOutputAddressGet | Any cyclic input or output on the EtherCAT network |
Recorded values are raw firmware memory, so you must know each value's type to interpret it. Query it with AddressDataTypeGet (or the equivalent on any RapidCode object) and see the retrieval methods in step 4.
Start recording manually with RecorderStart, or arm the recorder to follow motion automatically, as described in Triggering on Motion below. RecorderEnabledGet reports whether a recorder is currently recording.
Poll RecorderRecordCountGet to learn how many records are waiting, retrieve them one at a time (or in bulk), then read each value out of the retrieved record by index:
Prefer RecorderRecordDataFirmwareValueGet: it returns a FirmwareValue union you can read as the recorded value's actual type (.Double, .Int32, ...), matching what AddressDataTypeGet reported. To move a burst of records host-side in one call, use RecorderRecordDataRetrieveBulk.
For an event-driven alternative to polling, see Collecting via Interrupts below.
RecorderStop stops recording; RecorderReset restores the recorder's pointers and counters so the next RecorderStart begins a fresh recording. If you appended a temporary recorder, release it by lowering the count again with RecorderCountSet.
| Allocate | |
|---|---|
| RecorderCountGet / RecorderCountSet | How many recorders the firmware processes. Firmware default is 0. |
| RecorderBufferSizeGet / RecorderBufferSizeSet | Size of a recorder's buffer, in records. |
| ExternalMemorySizeGet | How much controller memory is available for buffers. |
| Configure | |
|---|---|
| RecorderPeriodSet | Samples between records (0 to 32,767). |
| RecorderDataCountSet | Number of values per record (up to 32). |
| RecorderDataAddressSet / RecorderDataAddressesSet | The firmware address recorded at each index / all indexes at once. |
| RecorderCircularBufferSet | true: keep recording (overwriting oldest) when full. false: stop when full. |
| RecorderBufferHighCountSet | Records stored before a RECORDER_HIGH interrupt (1 to 32,767). |
| Run | |
|---|---|
| RecorderStart / RecorderStop | Begin / end recording. |
| RecorderEnabledGet | Whether the recorder is currently recording. |
| RecorderConfigureToTriggerOnMotion / RecorderTriggerOnMotionGet | Arm / query automatic start-stop on motion. |
| RecorderReset | Restore pointers and counters for a fresh recording. |
| Collect | |
|---|---|
| RecorderRecordCountGet | Records stored and ready for reading. |
| RecorderRecordMaxCountGet | Maximum records the buffer can store. |
| RecorderRecordDataRetrieve / RecorderRecordDataRetrieveBulk | Pull the next record (or many) from the buffer. |
| RecorderRecordDataFirmwareValueGet | Read one value from the retrieved record as a typed FirmwareValue. |
| RecorderRecordDataValueGet / RecorderRecordDataDoubleGet | Read one value as a raw int32 / double. |
RecorderConfigureToTriggerOnMotion ties a recorder's start and stop to an Axis or MultiAxis motion supervisor. When a motion starts, the controller starts the recorder automatically; when the motion is done (see settling), the recorder stops and a RECORDER_DONE interrupt fires. This is the easiest way to log every relevant variable for exactly the duration of a move, with no host-side timing required.
Instead of polling for records, sleep in InterruptWait and let the controller tell you when to collect. Enable interrupt delivery with InterruptEnableSet (the RapidCodeInterrupt methods are available on the MotionController), then wait for these events:
| RSIEventType | Fires when |
|---|---|
| RECORDER_HIGH | The record count reaches the threshold set by RecorderBufferHighCountSet. This is your cue to drain the buffer. |
| RECORDER_FULL | The buffer is full. A non-circular recorder has stopped; a circular one is now overwriting the oldest records. |
| RECORDER_DONE | The recorder stopped (for example, a motion-triggered recording's motion completed). |
MotionController interrupts can also latch up to six arbitrary firmware values at the moment the recorder event fires; see InterruptUserDataAddressSet.
Recorder buffers live in controller memory and are dynamically allocated. The defaults are fine for most uses; size a larger buffer with RecorderBufferSizeSet when recording is fast and collection is slow:
For a recording longer than the memory available, configure a circular buffer with RecorderCircularBufferSet and drain it continuously. The host only has to copy records to RAM faster than the buffer rolls over, which is not an issue on most systems. Check how much controller memory is available with ExternalMemorySizeGet.
Record an axis position together with a digital input, then scan the records to find the position at the moment the input triggered.
Append a recorder at runtime and capture firmware and network timing deltas to characterize system performance.