Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

System Architecture

This chapter provides a deeper look at how AutoCore works internally. You don’t need to understand all of this to use AutoCore, but it will help you debug issues and make better design decisions.

Architecture Diagram

┌─────────────────────────────────────────────────────────────────┐
│                        AutoCore Server                           │
│                                                                   │
│  ┌──────────┐ ┌──────────┐ ┌────────────┐ ┌──────────────────┐ │
│  │  System   │ │    GM    │ │  Datastore  │ │   Module IPC     │ │
│  │ Servelet  │ │ Servelet │ │  Servelet   │ │   Server         │ │
│  └─────┬─────┘ └─────┬────┘ └──────┬─────┘ └────────┬─────────┘ │
│        │              │             │                 │           │
│        ▼              ▼             ▼                 ▼           │
│  ┌─────────────────────────────────────────────────────────────┐ │
│  │               Shared Memory (autocore_cyclic)                │ │
│  │  ┌──────────┐  ┌───────────┐  ┌─────────────┐  ┌─────────┐ │ │
│  │  │ Variables │  │  Signals  │  │   Direct    │  │ Events  │ │ │
│  │  │ (I/O)    │  │  (Tick)   │  │   Mapping   │  │ (Sync)  │ │ │
│  │  └──────────┘  └───────────┘  └─────────────┘  └─────────┘ │ │
│  └──────────▲─────────────────────────────▲────────────────────┘ │
│             │   Zero-Copy R/W             │   Zero-Copy R/W      │
│             │   (every cycle)             │   (every cycle)       │
└─────────────┼─────────────────────────────┼──────────────────────┘
              │                             │
   ┌──────────┴──────────┐    ┌─────────────┴──────────────┐
   │   Control Program    │    │      External Modules       │
   │   (your program.rs)  │    │  (EtherCAT, Modbus, etc.)  │
   │                      │    │                              │
   │  autocore-std        │    │  mechutil IPC client         │
   └──────────────────────┘    └──────────────────────────────┘
              │                             │
              ▼                             ▼
   ┌──────────────────────┐    ┌──────────────────────────────┐
   │   Web Console / HMI   │    │    Field Devices              │
   │   (Browser, ws://)    │    │  (Drives, Sensors, I/O)      │
   └──────────────────────┘    └──────────────────────────────┘

Shared Memory Model

Shared memory is the heart of AutoCore’s performance. Instead of sending data through network protocols or message queues, all processes access the same memory region directly.

  1. Allocation: When the server starts, it creates a shared memory segment called autocore_cyclic based on the variables in project.json.
  2. Mapping: The control program and all enabled modules map this segment into their own address space.
  3. Synchronization: The server generates a tick event. The control program waits for this event, reads the memory, processes one cycle, and writes back.

This zero-copy architecture means that I/O data exchange takes nanoseconds, not milliseconds.

The Module System

External modules extend AutoCore’s hardware capabilities. Each module:

  1. Is spawned as a child process by the server on startup
  2. Receives three CLI arguments: --ipc-address, --module-name, and --config
  3. Connects to the server’s IPC port (default 9100)
  4. Receives lifecycle commands: initialize, configure_shm, finalize
  5. Maps shared memory variables to exchange cyclic data
  6. Handles commands routed by the server based on the module’s domain name

Built-in modules:

  • autocore-ethercat: EtherCAT fieldbus master
  • autocore-modbus: Modbus TCP client
  • autocore-labelit: Camera and label inspection

Configuration: config.ini

The config.ini file contains machine-specific settings that stay the same across projects. It is located at:

  • Linux: /opt/autocore/config/config.ini
  • Development: specified with --config flag when running the server
[console]
port = 11969                                        # WebSocket port for CLI and web clients
www_root = /srv/autocore/console/dist               # Path to web console static files

[general]
projects_directory = /srv/autocore/projects          # Root directory for all projects
module_base_directory = /opt/autocore/bin/modules    # Directory containing module executables
port = 8080                                          # HTTP port for the web server
autocore_std_directory = /srv/autocore/lib/autocore-std  # Path to the autocore-std library
disable_ads = 1                                      # Disable TwinCAT ADS compatibility
ipc_port = 9100                                      # TCP port for module IPC
project_name = default                               # Project to load on startup

[modules]
modbus = ${general.module_base_directory}/autocore-modbus
ethercat = ${general.module_base_directory}/autocore-ethercat
labelit = ${general.module_base_directory}/autocore-labelit

The [modules] section maps module names to executable paths. This keeps project.json portable — the same project file works on different machines where modules may be installed in different locations.

The CommandMessage Protocol

All communication in AutoCore — between web clients and the server, between the CLI and the server, and between modules and the server — uses the CommandMessage protocol. Understanding this protocol helps you debug communication issues and write effective HMI code.

A CommandMessage is a JSON object with the following fields:

{
  "transaction_id": 101,
  "timecode": 1768960000000,
  "topic": "gm.motor_speed",
  "message_type": 2,
  "data": null,
  "crc": 0,
  "success": false,
  "error_message": ""
}
FieldTypeDescription
transaction_idnumberUnique ID for matching responses to requests. The server echoes this back. For broadcasts, this is 0.
timecodenumberTimestamp in milliseconds since UNIX epoch.
topicstringThe FQDN (Fully Qualified Domain Name) of the resource. The first segment routes to the appropriate module or servelet (e.g., gm, modbus, ethercat, datastore).
message_typenumberThe operation to perform (see table below).
dataanyThe payload. For a Write, this is the value to set. For a Read Response, this is the value retrieved.
crcnumberOptional CRC32 checksum for message integrity verification. Defaults to 0.
successbooleantrue if the operation succeeded, false if it failed. Only meaningful in responses.
error_messagestringHuman-readable error description if success is false. Otherwise empty.

Message Types

NameValueDescription
NoOp0No operation. Used for connection testing / ping.
Response1Reply to a previous request. The transaction_id matches the original.
Read2Request to read the current value of topic.
Write3Request to update the value of topic.
Subscribe4Request to receive updates whenever topic changes.
Unsubscribe5Stop receiving updates for topic.
Broadcast6Unsolicited push from server to client (live variable update).
Heartbeat7Keepalive signal.
Control8System control message (initialize, finalize, configure).
Request10Generic RPC call. The topic implies the action, data contains arguments.

The protocol follows a REST-like pattern: the topic is the resource (like a URL path), and the message_type is the verb (like an HTTP method).

Common Workflows

Reading a variable:

// Request (Client → Server)
{ "transaction_id": 101, "topic": "gm.motor_speed", "message_type": 2, "data": null }

// Response (Server → Client)
{ "transaction_id": 101, "topic": "gm.motor_speed", "message_type": 1, "data": 1500, "success": true }

Writing a variable:

// Request
{ "transaction_id": 102, "topic": "gm.motor_speed_setpoint", "message_type": 3, "data": 1200 }

// Response
{ "transaction_id": 102, "topic": "gm.motor_speed_setpoint", "message_type": 1, "success": true }

Subscribing to live updates:

// Subscribe request
{ "transaction_id": 103, "topic": "gm.motor_speed", "message_type": 4, "data": {} }

// Confirmation
{ "transaction_id": 103, "topic": "gm.motor_speed", "message_type": 1, "success": true }

// Subsequent broadcasts (sent automatically when value changes)
{ "transaction_id": 0, "topic": "gm.motor_speed", "message_type": 6, "data": 1485, "success": true }

FQDN Routing

The topic string determines where a message is routed. The first segment (before the first .) is the domain, which maps to a servelet or module:

DomainRoutes ToExample Topics
gmGlobal Memory serveletgm.motor_speed, gm.cycle_counter
systemSystem serveletsystem.get_domains, system.new_project, system.full_shutdown
datastoreDatastore serveletdatastore.calibration.offset
modbusModbus modulemodbus.vfd_01.speed_setpoint
ethercatEtherCAT moduleethercat.clearpath_0.rxpdo_5.controlword
pythonPython serveletpython.run_script

Glossary

TermDefinition
FQDNFully Qualified Domain Name. A dot-separated hierarchical address for any resource in the system. Example: ethercat.servo_drive.rxpdo_1.controlword
PDOProcess Data Object. The cyclic data image exchanged with fieldbus devices every scan cycle.
SDOService Data Object. A request/response protocol for reading or writing individual configuration parameters from a device. Used for acyclic (on-demand) access.
Cyclic dataData exchanged at a fixed interval (every tick). PDO data from EtherCAT slaves is cyclic. Requires deterministic timing.
Acyclic dataData exchanged on demand or at variable intervals. Modbus register reads, SDO access, and CommandMessage requests are acyclic.
Process imageThe complete set of input and output data for all devices on a fieldbus, updated each scan cycle.
Scan cycleOne complete exchange of process data with all fieldbus devices. At a 1 ms cycle time, there are 1,000 scan cycles per second.
ServeletAn internal module within autocore-server that handles a specific domain of messages (e.g., GM servelet, Datastore servelet, System servelet).