SOEM
SOEM is an open source EtherCAT master library developed by volunteers. Unlike TwinCAT, it runs on a regular Windows PC, so real-time performance is not guaranteed. Therefore, it is recommended to use TwinCAT. SOEM should be used only if there is no other choice or only during development. On the other hand, SOEM is cross-platform and easy to install.
If you are using Windows, install npcap in WinPcap API compatible mode. If you are using Linux/macOS, no special preparation is required.
NOTE: If you are using
SOEM
, be aware that it takes about 10-20 seconds after openingController
for the EtherCAT slaves to synchronize with each other. This period is subject to individual differences and changes depending on the synchronization signal/transmission cycle. During this period, the ultrasound synchronization between devices is not guaranteed.
SOEM link API
Following options can be specified for SOEM link.
use std::num::NonZeroUsize;
use std::time::Duration;
use autd3_link_soem::{SOEM, TimerStrategy, Status, ThreadPriority};
#[cfg(target_os = "windows")]
use autd3_link_soem::ProcessPriority;
#[allow(unused_variables)]
fn main() {
let builder =
SOEM::builder()
.with_ifname("")
.with_buf_size(NonZeroUsize::new(32).unwrap())
.with_err_handler(|slave, status| {
eprintln!("slave [{}]: {}", slave, status);
if status == Status::Lost {
// You can also wait for the link to recover, without exitting the process
std::process::exit(-1);
}
})
.with_state_check_interval(Duration::from_millis(100))
.with_sync0_cycle(Duration::from_millis(1))
.with_send_cycle(Duration::from_millis(1))
.with_timer_strategy(TimerStrategy::SpinSleep)
.with_sync_tolerance(Duration::from_micros(1))
.with_sync_timeout(Duration::from_secs(10))
.with_thread_priority(ThreadPriority::Max)
;
#[cfg(target_os = "windows")]
{
let builder =
builder
// Only available on Windows
.with_process_priority(ProcessPriority::High)
;
}
}
#include<autd3.hpp>
#include <iostream>
#include <autd3_link_soem.hpp>
int main() {
(void)
autd3::link::SOEM::builder()
.with_ifname("")
.with_buf_size(32)
.with_err_handler([](const uint16_t slave,
const autd3::link::Status status) {
std::cout << "slave [" << slave << "]: " << status << std::endl;
if (status == autd3::link::Status::Lost()) {
// You can also wait for the link to recover, without exiting the
// process
exit(-1);
}
})
.with_sync0_cycle(std::chrono::milliseconds(1))
.with_send_cycle(std::chrono::milliseconds(1))
.with_timer_strategy(autd3::link::TimerStrategy::SpinSleep)
.with_state_check_interval(std::chrono::milliseconds(100))
.with_sync_tolerance(std::chrono::microseconds(1))
.with_sync_timeout(std::chrono::seconds(10))
.with_thread_priority(autd3::link::ThreadPriority::Max)
.with_process_priority(autd3::link::ProcessPriority::High)
;
return 0; }
using AUTD3Sharp;
using AUTD3Sharp.Link;
using AUTD3Sharp.Gain;
using AUTD3Sharp.Modulation;
using AUTD3Sharp.Utils;
var autd = Controller.Builder([new AUTD3(Point3.Origin)]).Open(
SOEM.Builder()
.WithIfname("")
.WithBufSize(32)
.WithErrHandler((slave, status) =>
{
Console.Error.WriteLine($"slave [{slave}]: {status}");
if (status == Status.Lost)
{
// You can also wait for the link to recover, without exiting the process
Environment.Exit(-1);
}
})
.WithStateCheckInterval(Duration.FromMillis(100))
.WithSync0Cycle(Duration.FromMillis(1))
.WithSendCycle(Duration.FromMillis(1))
.WithTimerStrategy(TimerStrategy.SpinSleep)
.WithSyncTolerance(Duration.FromMicros(1))
.WithSyncTimeout(Duration.FromSecs(10))
.WithThreadPriority(AUTD3Sharp.Link.ThreadPriority.Max)
.WithProcessPriority(ProcessPriority.High)
);
import os
from pyautd3 import Duration
from pyautd3_link_soem import (
SOEM,
ProcessPriority,
Status,
ThreadPriority,
TimerStrategy,
)
def err_handler(slave: int, status: Status) -> None:
print(f"slave [{slave}]: {status}")
if status == Status.Lost():
# You can also wait for the link to recover, without exiting the process
os._exit(-1)
SOEM.builder()\
.with_ifname("")\
.with_buf_size(32)\
.with_err_handler(err_handler)\
.with_state_check_interval(Duration.from_millis(100))\
.with_sync0_cycle(Duration.from_millis(1))\
.with_send_cycle(Duration.from_millis(1))\
.with_timer_strategy(TimerStrategy.SpinSleep)\
.with_sync_tolerance(Duration.from_micros(1))\
.with_sync_timeout(Duration.from_secs(10))\
.with_thread_priority(ThreadPriority.Max)\
.with_process_priority(ProcessPriority.High)
ifname
: Network interface name. The default is blank, and if it is blank, the network interface to which the AUTD3 device is connected is automatically selected.buf_size
: Send queue buffer size. Usually, you don't need to change it.err_handler
: Callback when an error occurs. The callback function takes the device number where the error occurred, the type of error, and the error message as arguments.state_check_interval
: Interval to check if there is an error. The default is .sync0_cycle
: Synchronization signal cycle. The default is .send_cycle
: Send cycle. The default is 2 is .SOEM
may become unstable when a large number of devices are connected1. In this case, increase the values ofsync0_cycle
andsend_cycle
. These values should be as small as possible without causing errors. The value depends on the number of devices connected. For example, if there are 9 devices, set the value to or .
timer_strategy
: Timer strategy. The default isSpinSleep
.StdSleep
: Use standard library sleep.SpinSleep
: Use spin_sleep crate.SpinWait
: Use spin loop. High resolution but high CPU load.
sync_mode
: Synchronization mode. See Beckhoff's explanation for details.
RemoteSOEM
This link is used to separate the server PC running SOEM
and the client PC running the user program.
To use RemoteSOEM
, you need to prepare two PCs.
In this case, one PC must be able to use the SOEM
link.
This PC is called the "server" here.
On the other hand, there are no particular restrictions on the PC on the development side that uses the SDK, and it is sufficient to be connected to the same LAN as the server.
This is called the "client" here.
First, connect the server and the AUTD device. Then, connect the server and the client on different LANs2. Then, check the IP of the LAN between the server and the client. For example, suppose the server is "172.16.99.104", and the client is "172.16.99.62".
AUTD Server
To use RemoteSOEM
, install AUTD Server
first.
The AUTD server's installer is distributed on GitHub Releases.
When you run AUTD Server
, the following screen will appear, so open the "SOEM" tab.
Set port number and click "Run" button.
RemoteSOEM link API
RemoteSOEM
constructor takes
use autd3::prelude::*;
use autd3_link_soem::RemoteSOEM;
#[allow(unused_variables)]
fn main() -> Result<(), Box<dyn std::error::Error>> {
let autd = Controller::builder([AUTD3::new(Point3::origin())])
.open(
RemoteSOEM::builder("172.16.99.104:8080".parse()?)
)?;
Ok(())
}
#include<autd3.hpp>
#include <autd3_link_soem.hpp>
int main() {
auto autd = autd3::ControllerBuilder({autd3::AUTD3(autd3::Point3::origin())})
.open(
autd3::link::RemoteSOEM::builder("172.16.99.104:8080")
);
return 0; }
using System.Net;
using AUTD3Sharp;
using AUTD3Sharp.Link;
using AUTD3Sharp.Gain;
using AUTD3Sharp.Modulation;
using AUTD3Sharp.Utils;
var autd = Controller.Builder([new AUTD3(Point3.Origin)]).Open(
RemoteSOEM.Builder(new IPEndPoint(IPAddress.Parse("172.16.99.104"), 8080))
);
from pyautd3_link_soem import RemoteSOEM
RemoteSOEM.builder("172.16.99.104:8080")
SOEMAUTDServer
You can set options for SOEM
with the option argument of SOEMAUTDServer
.
Please see SOEMAUTDServer --help
for details.
Firewall
If you get a TCP-related error when using RemoteSOEM
, it may be blocked by the firewall.
It is looser than TwinCAT, and sometimes it works normally.
It can be used even with wireless LAN.