Getting Started with Adapnex
Welcome to Adapnex!
If you are coming from the world of Industrial Automation, you likely know the pain of proprietary "walled gardens": specialized IDEs, licensing dongles, and the struggle to use modern version control like Git.
If you are coming from Software Development, you might be wondering why controlling a machine isn’t as simple as writing a C++ program and hitting "Run."
Adapnex bridges this gap. It is a streamlined C++ SDK that runs on Real-Time Linux, allowing you to build deterministic industrial control applications easily using the tools you already know and love: VS Code, CMake, Git, and CI/CD.
What We Are Building
In this guide, we will build the "Hello World" of hardware: a "Blinky" application. We will take a simple button input and use it to toggle an LED output.
|
Don’t have a PLC on your desk?
No problem. One of Adapnex’s superpowers is simulation. We will show you how to write and verify your control logic purely in software on your local machine before we ever talk about cables and wires. |
1. Project Setup: Standard Tools, Industrial Power
Adapnex projects use CMake, the industry standard for C++ build automation. This means your project is portable and works with any major IDE (VS Code, CLion, Visual Studio, etc.).
Create a new folder for your project and add a CMakeLists.txt file.
cmake_minimum_required(VERSION 3.25)
project(example_x20)
# Create the executable application
# 'adapnex_executable' handles toolchains and dependencies automatically.
adapnex_executable(example_x20 main.cpp)
# Register the test suite
# This sets up the test target for simulation.
adapnex_tests(example_x20_tests main_test.cpp)
|
Key Takeaway
You don’t need to manually configure complex compiler flags for Real-Time Linux. The |
2. Defining Control Logic
In Adapnex, your control logic is encapsulated in Tasks. A Task is simply a C++ class that contains your variables and your logic. Crucially, this task doesn’t know about the hardware yet. It operates on pure software variables, making it easy to test and reuse.
Create a header file named main_task.h.
#pragma once
#include "adapnex.h"
// Inherit from 'Task' to create a standard automation block
class MainTask final : public Task {
public:
// --- Interface Variables ---
// These are simple C++ booleans, not hardware addresses!
bool button = false;
bool blink = false;
// --- Logic Blocks ---
// Instantiate a standard Square Wave Generator (Function Block)
SquareWaveGenerator generator;
// --- The Control Loop ---
// This function will run cyclically (e.g., every 20ms)
void Update() override {
// Use the button as the enable signal
// Configure: 200ms ON, 200ms OFF
// Output result to 'blink'
generator(button, 200ms, 200ms, blink);
}
};
|
Key Takeaway
This looks like standard C++ because it is standard C++. However, the |
3. Verification: Testing Without the Machine
Before we configure any hardware drivers, let’s prove our logic works. Because Adapnex is native C++, we can use standard testing frameworks like Google Test.
The Adapnex Simulation fixture allows you to "fast forward" time, running your real-time logic instantly on your PC.
Create a file named main_test.cpp.
#include "adapnex.h"
#include <gtest/gtest.h>
#include "main_task.h"
// Define a test using the standard 'Simulation' fixture
TEST_F(Simulation, MainTask) {
// 1. Setup the Scheduler
// Create a virtual task group running every 20ms
const auto main_group = Application::CreateCyclicTaskGroup(20ms, 0);
// Instantiate the logic task within this group
const auto main_task = main_group->CreateTask<MainTask>();
// 2. Simulate User Input (Press Button)
main_task->button = true;
// 3. Advance Time by 100ms
Simulate(100ms);
// Check: Output should be ON (start of wave)
ASSERT_TRUE(main_task->blink);
// 4. Advance Time by another 200ms
Simulate(200ms);
// Check: Output should have toggled OFF (period is 200ms)
ASSERT_FALSE(main_task->blink);
}
You can run this test using ctest or the "Run Tests" button in your IDE.
|
Key Takeaway
You just verified your real-time control logic without waiting for hardware delivery, wiring a cabinet, or risking a machine crash. |
4. Connecting to the Physical World
Now that we know the logic is sound, let’s deploy it to a real machine. For this example, we are using a B&R X20 System, but the code would look nearly identical for Wago, Phoenix Contact, or other supported platforms.
We perform this configuration in main.cpp. This file acts as the "wiring diagram," connecting your software variables to hardware drivers.
#include "adapnex.h"
#include "main_task.h"
// The 'setup' function is the entry point for Adapnex applications
void setup() {
// --- 1. Configure the Scheduler ---
// Create a Cyclic Task Group (20ms cycle time, priority 0)
const auto main_group = Application::CreateCyclicTaskGroup(20ms, 0);
// Instantiate our control logic
const auto main_task = main_group->CreateTask<MainTask>();
// --- 2. Configure Hardware Drivers ---
// Add the Bus Controller (The "Brain" of the IO slice) as a task
const auto io_driver = main_group->CreateTask<X20BC0087Driver>();
// --- 3. Wiring (Mapping) ---
// Add the Digital Output Module
const auto do8 = io_driver->AddModule<X20DO8322>();
// Hardwire Output 1 to true (acts as 24V power source)
do8->DO1.value() = true;
// Output Mapping: Connect logic 'blink' -> Hardware DO2
do8->DO2 << main_task->blink;
// Add the Digital Input Module
const auto di8 = io_driver->AddModule<X20DI8371>();
// Input Mapping: Connect Hardware DI1 -> logic 'button'
di8->DI1 >> main_task->button;
}
|
Key Takeaway
Notice how clean the separation is. |
5. Build and Deploy
Adapnex includes deployment tools that handle connections and binary transfers. In VS Code or CLion, this is as simple as clicking "Run" on the remote target.
Conclusion: The Future of Your Control Systems
Congratulations! You have just built a real-time industrial control application. But unlike traditional approaches, you have achieved several significant milestones:
-
Hardware Independence: You verified the logic with
main_test.cppbefore configuring a single driver. -
Modern Workflow: You used Git-friendly text files (
.cpp,.h,.txt) instead of binary blobs. -
Developer Experience: You did industrial control programming on a standard IDE that naturally comes with autocomplete, refactoring tools, and AI assistants.
-
Clean Implementation: You used the power and flexibility of Real-Time Linux without having to deal directly with complicated Real-Time Linux system calls.
Next Steps
From here, the sky is the limit. Because you are in C++, you can easily integrate:
-
Advanced Control: Use existing C++ libraries for PID control, Motion Planning, or Signal Processing.
-
IoT & Cloud: Send telemetry to Grafana, AWS, or Azure with a few lines of code.
-
CI/CD: Set up a GitHub Action to run your simulation tests automatically on every commit.
Welcome to the new era of Industrial Software Development (IDX).