-
Notifications
You must be signed in to change notification settings - Fork 20
BECKHOFF minimal example motor #967
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
e41207f
e1a9cc3
c0803db
eaed8ed
e24a262
30782fd
2511201
1f829ff
ca80909
f741af0
ad05f82
87b9f32
a66e517
3946aef
1ad4337
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,4 +7,5 @@ build.sh | |
| shell.nix | ||
| node_modules/ | ||
| runtime_metrics.csv | ||
| compile_metrics.csv | ||
| compile_metrics.csv | ||
| .idea/ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,251 @@ | ||
| # Minimal Example — Beckhoff EL7031-0030 Stepper Motor Integration | ||
| A complete hardware + software walkthrough | ||
|
|
||
| --- | ||
|
|
||
| ## Table of Contents | ||
| 1. [Introduction](#1-introduction) | ||
| 2. [Requirements](#2-requirements) | ||
| 3. [Hardware Setup](#3-hardware-setup) | ||
| - [3.2 EK1100 Wiring](#32-ek1100-wiring) | ||
| - [3.2.1 Safe Wiring Procedure](#321-safe-wiring-procedure-beckhoff-recommended) | ||
| - [3.2.2 Wiring (EL7031-0030)](#322-wiring-el7031-0030) | ||
| - [3.3 Safety Warning](#33--safety-warning) | ||
| 4. [Software Setup](#4-software-setup) | ||
| - [4.1 Installing on Linux](#41-installing-on-linux-this-depends-on-your-distro) | ||
| - [4.2 Running the Backend](#42-running-the-backend) | ||
| - [4.3 Running the Frontend](#43-running-the-frontend) | ||
| 5. [Demo](#5-demo) | ||
| - [5.1 Assigning Devices in the Dashboard](#51-assigning-devices-in-the-dashboard) | ||
| 6. [Documentation](#6-documentation) | ||
| 7. [Software Architecture](#7-software-architecture) | ||
|
|
||
| --- | ||
|
|
||
| ## 1. Introduction | ||
|
|
||
| This project documents the successful integration of a **Beckhoff EL7031-0030 Stepper Motor Terminal** into the QiTech control software stack. | ||
| The goal was to control a 24V stepper motor via EtherCAT using a custom Rust backend and a React/Electron frontend. | ||
|
|
||
| --- | ||
|
|
||
| ## 2. Requirements | ||
|
|
||
| ### Software | ||
| - Rust toolchain | ||
| - Node.js + npm | ||
| - Git | ||
| - QiTech Control repository | ||
| - EtherCAT HAL (included inside repo) | ||
|
|
||
| ### Hardware | ||
| - **EtherCAT Master:** Linux PC | ||
| - **Bus Coupler:** EtherCAT Beckhoff EK1100 | ||
| - **Stepper Driver:** Beckhoff EL7031-0030 (THIS IS DIFFERENT FROM EL7031) | ||
| - **Motor:** Standard 4-wire Stepper Motor | ||
| - **Power Supply:** 24V DC | ||
| - **Ethernet Cable:** Standard Ethernet cable | ||
| - **Wiring Tools:** Screwdriver, wires | ||
|
|
||
| --- | ||
|
|
||
| ## 3. Hardware Setup | ||
|
|
||
| ### 3.2 EK1100 Wiring | ||
|
|
||
| This wiring configuration powers the EL7031-0030. | ||
| It is not the only possible wiring but is the **simplest functional setup**. | ||
|
|
||
| #### ⚠️ Safety Warning | ||
| Always disconnect power before wiring. | ||
| Working on live EtherCAT terminals can cause serious damage or electrical shock. | ||
|
|
||
| --- | ||
|
|
||
| #### 3.2.1 Safe Wiring Procedure (Beckhoff Recommended) | ||
|
|
||
| 1. Insert a screwdriver **straight** into the square release hole. | ||
| 2. Insert the stripped wire into the round opening. | ||
| 3. Remove the screwdriver — the spring clamp locks the wire. | ||
|
|
||
|  | ||
|
|
||
| --- | ||
|
|
||
| We supply power using a **DC hollow-plug adapter**, like this one: | ||
| https://www.amazon.de/dp/B093FTFZ8Q | ||
|
|
||
| Perform the following wiring on the EK1100: | ||
|
|
||
| 1. Red wire **(+24 V)** → Terminal **2** | ||
| 2. Black wire **(0 V)** → Terminal **3** | ||
| 3. Jumper wire from **Terminal 1 → Terminal 6** | ||
| 4. Jumper wire from **Terminal 5 → Terminal 7** | ||
|
|
||
| After wiring, your module should look like **Figure 1**. | ||
|
|
||
| --- | ||
|
|
||
| #### **Figure 1 — EK1100 Minimal Wiring** | ||
| <img src="../assets/ek1100.jpeg" width="400"> | ||
|
|
||
| --- | ||
|
|
||
| #### **Figure 2 — EL7031-0030 Terminal** | ||
|
|
||
| <img src="../assets/EL7031_0030.jpg" width="300"> | ||
|
|
||
| Slide the EL7031-0030 onto the right side of the EK1100 until it locks. | ||
| The EtherCAT E-Bus and power contacts connect automatically — **no wiring required**. | ||
|
|
||
| --- | ||
|
|
||
| #### **Figure 3 — Motor** | ||
| <img src="../assets/motor.jpg" width="300"> | ||
|
|
||
| --- | ||
|
|
||
| #### **Figure 4 — Motor Wiring** | ||
| <img src="../assets/motor_wiring.jpg" width="300"> | ||
|
|
||
| Now the motor is wired via the pins 4, 5, 12, 13 on the EL7031-0030. | ||
|
|
||
| --- | ||
|
|
||
| #### **Figure 5 — EL7031 Integration Connected** | ||
|
|
||
| <img src="../assets/EL7031_0030_connected.jpg" width="400"> | ||
|
|
||
| That's what the pin should look like. | ||
|
|
||
| --- | ||
|
|
||
| ### 3.2.2 Wiring (EL7031-0030) | ||
|
|
||
| **Crucial:** The EL7031 requires two power sources: E-Bus (side contacts) for logic, and Front Terminal (6 & 14) for motor power. | ||
|
|
||
| | Terminal Point | Function | Cable Color (Example) | | ||
| | :------------- | :--------------- | :-------------------- | | ||
| | **4** | Motor Coil A1 | Red | | ||
| | **12** | Motor Coil A2 | Blue | | ||
| | **5** | Motor Coil B1 | Green | | ||
| | **13** | Motor Coil B2 | Black | | ||
| | **6** | **Power +24V** | PSU Red (+) | | ||
| | **14** | **Power 0V/GND** | PSU Black (-) | | ||
|
|
||
| --- | ||
|
|
||
| ### 3.3 ⚠️ Safety Warning | ||
|
|
||
| - **Mandatory Power Supply:** Without 24V connected to **Pin 6 (+24V)** and **Pin 14 (GND)**, the terminal will remain in `PREOP` state or show a "Warning" LED (No Power). The motor will **not** move without this external supply. | ||
|
|
||
| #### Risk of Destruction (Short Circuit): | ||
| - **Never** connect the 24V Power Supply to the Motor Output pins (**4, 5, 12, 13**). This will instantly destroy the terminal (causing pins 12 & 13 to glow red/burn). | ||
| - Ensure strict separation: **Pins 4/5/12/13 are for the MOTOR ONLY**. | ||
| - **Pins 6/14 are for POWER ONLY**. | ||
|
|
||
| Also, see the documentation of the EtherCAT terminal ([EL7031-0030](https://download.beckhoff.com/download/document/io/ethercat-terminals/el7031-0030de.pdf)) for the different power modes (page 46 ff.) | ||
|
|
||
| --- | ||
|
|
||
| ## 4. Software Setup | ||
|
|
||
| ### 4.1 Installing on Linux (this depends on your distro) | ||
|
|
||
| Paste this into your terminal: | ||
|
|
||
| ```bash | ||
| # Press Enter when prompted | ||
| curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh | ||
|
|
||
| sudo apt update | ||
| sudo apt install -y npm nodejs git | ||
|
|
||
| git clone [email protected]:qitechgmbh/control.git | ||
| cd control/electron | ||
| npm install | ||
| ``` | ||
|
|
||
| ### 4.2 Running the Backend | ||
|
|
||
| ```bash | ||
| ./cargo_run_linux.sh | ||
| ``` | ||
|
|
||
| This script: | ||
| - Builds the backend | ||
| - Grants required system capabilities (raw sockets) | ||
| - Starts EtherCAT communication | ||
|
|
||
| Sometimes an error like this appears: | ||
|
|
||
| ```bash | ||
| .... | ||
| 37: <alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once | ||
| at /rustc/ed61e7d7e242494fb7057f2657300d9e77bb4fcb/library/alloc/src/boxed.rs:1985:9 | ||
| 38: std::sys::thread::unix::Thread::new::thread_start | ||
| at /rustc/ed61e7d7e242494fb7057f2657300d9e77bb4fcb/library/std/src/sys/thread/unix.rs:126:17 | ||
| 39: start_thread | ||
| 40: __clone3 | ||
| 14:10:46.906 INFO ThreadId(04) server::socketio::init: 167: Socket connected to namespace socket=FXdsVyRVGiN1nLXJ namespace=/main | ||
| ``` | ||
|
|
||
| Re-run the code until the QiTech UI appears. | ||
|
|
||
| ### 4.3 Running the Frontend | ||
|
|
||
| ```bash | ||
| # move to the control directory | ||
| cd electron | ||
| npm run start | ||
| ``` | ||
|
|
||
| This launches the QiTech Control dashboard. | ||
|
|
||
| --- | ||
|
|
||
| ## 5. Demo | ||
|
|
||
| ### 5.1 Assigning Devices in the Dashboard | ||
|
|
||
| Once the backend + frontend are running, you should see: | ||
|
|
||
|  | ||
|
|
||
| Make sure that under "Assign" → "Machine Assignment" | ||
| the correct serial number is selected (each device should have the same one, here it is 1). | ||
| Under "Machine" select your new Machine however you named it (I named it "TestMotor V1"), else it will detect that there is something connected to it but the connection won't work. | ||
|
|
||
|  | ||
|
|
||
| **NOW THE MOTOR SHOULD TURN!** | ||
|
|
||
| In the interface "TestMotor" on the left side, you can now control the motor (its state and its speed). | ||
|
|
||
|  | ||
|
|
||
| --- | ||
|
|
||
| ## 6. Documentation | ||
|
|
||
| Use the official documentation of the EL7031-0030 for more information: | ||
| [Beckhoff EL7031-0030 Documentation](https://download.beckhoff.com/download/document/io/ethercat-terminals/el7031-0030de.pdf) | ||
|
|
||
| --- | ||
|
|
||
| ## 7. Software Architecture | ||
|
|
||
| ### Backend (Rust) | ||
| Located in [machines/src/ethercat_beckhoff/](../../machines/src/ethercat_beckhoff/). | ||
|
|
||
| 1. **`mod.rs`**: Defines the `MotorTestMachine` struct and holds the state (driver wrapper, enabled state, target velocity). | ||
| 2. **`api.rs`**: Handles incoming JSON commands from the frontend (Enable/Disable, Set Velocity) via WebSockets/SocketIO. | ||
| 3. **`act.rs`**: The real-time control loop. It updates the `StepperVelocityEL70x1` driver wrapper in every cycle based on the current state. | ||
| 4. **`new.rs`**: Initializes the hardware. | ||
|
|
||
| ### Frontend (TypeScript/React) | ||
| Located in [electron/src/machines/ethercat_beckhoff/](../../electron/src/machines/ethercat_beckhoff/) and [electron/src/routes/routes.tsx](../../electron/src/routes/routes.tsx). | ||
|
Comment on lines
+239
to
+247
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All three links are dead. I suggest using absolut paths. On github |
||
|
|
||
| 1. **`useTestMotor.ts`**: Custom hook managing the optimistic state and communication with the backend. | ||
| 2. **`TestMotorControlPage.tsx`**: The UI using QiTech UI components (`ControlCard`, `EditValue`, `SelectionGroupBoolean`) to match the look and feel of the Winder2. | ||
| 3. **Routing**: Integrated into `routes.tsx` using TanStack Router, ensuring the machine appears in the sidebar and navigation works correctly. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| import { ControlCard } from "@/control/ControlCard"; | ||
| import { Page } from "@/components/Page"; | ||
| import React from "react"; | ||
| import { ControlGrid } from "@/control/ControlGrid"; | ||
| import { SelectionGroupBoolean } from "@/control/SelectionGroup"; | ||
| import { EditValue } from "@/control/EditValue"; | ||
| import { Label } from "@/control/Label"; | ||
| import { useTestMotor } from "./useTestMotor"; | ||
|
|
||
| export function TestMotorControlPage() { | ||
| const { state, setMotorOn, setVelocity } = useTestMotor(); | ||
|
|
||
| // Fallback, falls state noch null ist | ||
| const safeState = state ?? { motor_enabled: false, motor_velocity: 0 }; | ||
|
|
||
| return ( | ||
| <Page> | ||
| <ControlGrid columns={2}> | ||
| {/* rundsteuerung */} | ||
| <ControlCard title="Motor Status"> | ||
| {/* An/Aus Schalter */} | ||
| <Label label="Power State"> | ||
| <SelectionGroupBoolean | ||
| value={safeState.motor_enabled} | ||
| // Icon Mapping für True/False | ||
| optionTrue={{ children: "Enabled", icon: "lu:Play" }} | ||
| optionFalse={{ children: "Disabled", icon: "lu:CirclePause" }} | ||
| onChange={(val) => setMotorOn(val)} | ||
| /> | ||
| </Label> | ||
| </ControlCard> | ||
|
|
||
| {/* Geschwindigkeit */} | ||
| <ControlCard title="Settings"> | ||
| {/* Velocity Eingabe mit Einheit */} | ||
| <Label label="Target Velocity"> | ||
| <EditValue | ||
| title="Velocity" | ||
| value={safeState.motor_velocity} | ||
| unit="rpm" | ||
| min={0} | ||
| max={1000} // Limit | ||
| step={1} | ||
| onChange={(val) => setVelocity(val)} | ||
| // Zeigt den Wert (hier ganze Zahl) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. pls all comments in english |
||
| renderValue={(v) => v.toFixed(0)} | ||
| /> | ||
| </Label> | ||
| </ControlCard> | ||
| </ControlGrid> | ||
| </Page> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| import { Topbar } from "@/components/Topbar"; | ||
| import { testMotorSerialRoute } from "@/routes/routes"; | ||
| import React from "react"; | ||
|
|
||
| export function TestMotorPage() { | ||
| // Hier ist der Zugriff erlaubt, weil diese Funktion erst später aufgerufen wird | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. translate |
||
| const { serial } = testMotorSerialRoute.useParams(); | ||
|
|
||
| return ( | ||
| <Topbar | ||
| pathname={`/_sidebar/machines/testmotor/${serial}`} | ||
| items={[ | ||
| { | ||
| link: "control", | ||
| activeLink: "control", | ||
| title: "Control", | ||
| icon: "lu:CirclePlay", | ||
| }, | ||
| ]} | ||
| /> | ||
| ); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Imo, this is pretty much useless to the reader. Rather show the EtherCAT init success message with the correct number of devices.