Motion Master 6.0.0-alpha.86
Next-generation motion control software
Loading...
Searching...
No Matches
mm::example::ExampleCyclicTask Class Reference

Copy-me starter for a Tier 3 extension: your own code inside the real-time loop. More...

#include <example_cyclic_task.h>

Inheritance diagram for mm::example::ExampleCyclicTask:
[legend]
Collaboration diagram for mm::example::ExampleCyclicTask:
[legend]

Classes

struct  Config
 Everything the task needs to know, so nothing is hard-coded in execute. More...
 

Public Member Functions

 ExampleCyclicTask (mm::node::DeviceManager &deviceManager, Config config)
 Binds the task to a device manager. Registers nothing and touches no device — a task is constructed before the bus exists and must tolerate that.
 
void execute (const mm::core::CycleContext &ctx) noexcept override
 Runs one cycle. Non-blocking, non-allocating, lock-free.
 
- Public Member Functions inherited from mm::core::CyclicTask
virtual ~CyclicTask ()=default
 Virtual destructor.
 

Detailed Description

Copy-me starter for a Tier 3 extension: your own code inside the real-time loop.

This is the counterpart of example_routes.h, which extends the HTTP API (Tier 2). Where a route plug-in runs on an HTTP thread and may block, a CyclicTask runs on the RT thread, once per cycle, and may not: no locks, no allocation, no bus I/O, and it must return well inside the cycle period (1 ms by default). Everything below honours that, and the rules it follows are the whole point of reading it.

What it does — a very naive thermal interlock. It brings one drive into cyclic synchronous velocity mode, enables it, and runs it at a fixed velocity; if the drive's temperature goes over a limit it issues a quick stop, and it will not enable again until the temperature falls, at which point it climbs back up by itself. Naive is the word: a real interlock has hysteresis, an alarm path, and a considered answer for every sensor failure mode. What is realistic here is the shape — read state, decide, command, once per cycle, with nothing that can block.

Warning
**Uncommenting this in main.cc will spin a motor.** It does not wait for anyone to enable the drive; enabling is its job. Check Config against your bus first.

The three rules a cyclic task lives by, each visible in execute:

  1. Resolve the device every cycle; never cache the pointer. A rescan publishes a new device set, and pointers held across cycles do not follow it. Resolving costs a walk over a handful of devices. GameLoop enters the cycle before it calls execute, which is what makes the pointer valid for the body — a task takes no guard and checks nothing.
  2. A device that is not there is not an error. It simply is not driven this cycle, and the task picks it up again when it returns. That is what lets a machine be powered up in stages.
  3. **Read and write values through Device::value<T>() / setValue<T>().** Both are a hash lookup plus one atomic load or store, and neither can tell whether an object rides the process image or is polled over SDO in the background. Whether the temperature is PDO-mapped is a commissioning decision, and this code does not change if it flips.

Driving the CiA402 state machine from here is the right place for it, not a liberty. Mode of operation, controlword and statusword are all in the process image and all exchanged every cycle, so the climb (Switch On Disabled → Ready To Switch On → Switched On → Operation Enabled) is one write per cycle with the wire doing the waiting — where an off-RT caller has to sleep and poll for the same result. What must stay off the RT thread is the EtherCAT AL state (INIT / PRE-OP / SAFE-OP / OP): seconds of mailbox and register traffic, done through the HTTP API. A task runs in OP and never touches it.

One value here is not free. Config's temperature object is SDO-only on most drives, so nothing refills it cyclically — MonitoringManager::keepFresh has to be called once, off the RT thread, before the loop starts. Without it the read never produces a value, the interlock treats that as unsafe, and the drive never spins. main.cc shows the call.

Constructor & Destructor Documentation

◆ ExampleCyclicTask()

mm::example::ExampleCyclicTask::ExampleCyclicTask ( mm::node::DeviceManager deviceManager,
Config  config 
)

Binds the task to a device manager. Registers nothing and touches no device — a task is constructed before the bus exists and must tolerate that.

Member Function Documentation

◆ execute()

void mm::example::ExampleCyclicTask::execute ( const mm::core::CycleContext ctx)
overridevirtualnoexcept

Runs one cycle. Non-blocking, non-allocating, lock-free.

Implements mm::core::CyclicTask.


The documentation for this class was generated from the following files: