Controller

ここでは, Controllerに存在するAPIを紹介する.

fpga_state

FPGAの状態を取得する. これを使用する前に, ReadsFPGAStateで状態取得を有効化しておく必要がある.

use autd3::prelude::*;
#[allow(unused_variables)]
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut autd = Controller::open([AUTD3::default()], autd3::link::Nop::new())?;
autd.send(ReadsFPGAState::new(|_dev| true))?;

let info = autd.fpga_state()?;
Ok(())
}
#include<autd3.hpp>
#include<autd3/link/nop.hpp>
int main() {
using namespace autd3;
auto autd =
Controller::open({AUTD3{}}, link::Nop{});
autd.send(ReadsFPGAState([](const auto&) { return true; }));

const auto info = autd.fpga_state();
return 0; }
using AUTD3Sharp;
using AUTD3Sharp.Link;
using AUTD3Sharp.Utils;
using var autd = Controller.Open([new AUTD3()], new Nop());
autd.Send(new ReadsFPGAState(_ => true));

var info = autd.FPGAState();
from pyautd3 import Controller, AUTD3, ReadsFPGAState
from pyautd3.link.nop import Nop
autd = Controller.open([AUTD3()], Nop())
autd.send(ReadsFPGAState(lambda _: True))

info = autd.fpga_state()

ReadsFPGAStateコンストラクタの引数はFn(&Device) -> boolで, デバイス毎に状態取得を有効化するかどうかを指定する.

有効化していないデバイスに対してfpga_stateNoneを返す.

FPGAの状態としては, 現在以下の情報が取得できる.

  • is_thermal_assert: ファン制御用の温度センサがアサートされているかどうか
  • current_mod_segment: 現在のModulation Segment
  • current_stm_segment: 現在のFociSTM/GainSTM Segment
  • current_gain_segment: 現在のGain Segment
  • is_gain_mode: 現在Gainが使用されているかどうか
  • is_stm_mode: 現在FociSTM/GainSTMが使用されているかどうか

send

デバイスにデータを送信する.

データは単体か2つのみ同時に送信することができる.

sender

送信時の設定をsender経由で指定できる.

use autd3::prelude::*;
use std::time::Duration;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut autd = Controller::open([AUTD3::default()], autd3::link::Nop::new())?;
let mut sender = autd.sender(
    SenderOption {
        send_interval: Duration::from_millis(1),
        receive_interval: Duration::from_millis(1),
        timeout: None,
        parallel: ParallelMode::Auto,
        strict: true
    },
    FixedSchedule::default(),
);
let d = Null {};
sender.send(d)?;
Ok(())
}
#include<chrono>
#include<autd3.hpp>
#include<autd3/link/nop.hpp>
int main() {
using namespace autd3;
auto autd = Controller::open({AUTD3{}}, link::Nop{});
auto sender =
    autd.sender(SenderOption{.send_interval = std::chrono::milliseconds(1),
                             .receive_interval = std::chrono::milliseconds(1),
                             .timeout = std::nullopt,
                             .parallel = ParallelMode::Auto,
                             .strict = true},
                FixedSchedule{});
const Null d;
sender.send(d);
return 0; }
using AUTD3Sharp;
using AUTD3Sharp.Link;
using AUTD3Sharp.Gain;
using AUTD3Sharp.Utils;
using var autd = Controller.Open([new AUTD3()], new Nop());
var sender = autd.Sender(
    new SenderOption
    {
        SendInterval = Duration.FromMillis(1),
        ReceiveInterval = Duration.FromMillis(1),
        Timeout = null,
        Parallel = ParallelMode.Auto,
        Strict = true,
    },
    new FixedSchedule()
);
var d = new Null();
sender.Send(d);
from pyautd3 import AUTD3, Controller, Duration, Null, SenderOption, FixedSchedule, ParallelMode
from pyautd3.link.nop import Nop
autd = Controller.open([AUTD3()], Nop())
sender = autd.sender(
    SenderOption(
        send_interval=Duration.from_millis(1),
        receive_interval=Duration.from_millis(1),
        timeout=None,
        parallel=ParallelMode.Auto,
        strict=True
    ),
    FixedSchedule(),
)
d = Null()
sender.send(d)

ここで,

第2引数は送受信間隔を調整する構造体であり, 以下から選択する.

  • FixedSchedule: 送信処理にかかった時間にかかわらず, 前回の送信開始時刻から指定した間隔で次の送信を開始する.
  • FixedDelay: 送信処理が完了してから指定した間隔で次の送信を開始する.

これらの構造体は, どのようにスレッドをスリープさせるかを指定する以下の構造体を持つ.

なお, Controller::sendController::default_sender_option (変更可能) とデフォルトのFixedSchedule(SpinSleeper)を使用した場合と等価である.

送信データのチェックについて

タイムアウトの値が

  • 0より大きい場合, 送信データがデバイスで処理されるか, 指定したタイムアウト時間が経過するまで待機する. 送信データがデバイスで処理されたのが確認できなかった場合にエラーを返す.
  • 0, かつ, strict=falseの場合, send関数は送信データがデバイスで処理されたか確認できなくてもエラーを返さない.

確実にデータを送信したい場合はこれを適当な値に設定しておくことをおすすめする.

SenderOptionで指定しない場合, デフォルト値 () が使用される.

複数をまとめて送信する場合は, それぞれのデータのタイムアウト値の最大値が使用される.

並列計算について

各データの内部での計算は, デバイス単位で並列に実行することができる.

ParallelMode::Onを指定すると並列計算を有効化, ParallelMode::Offを指定すると無効化する.

ParallelMode::Autoの場合, デバイスの数が以下に示す各データの並列計算スレッショルド値を超える場合に並列計算が有効化される.

並列計算スレッショルド値
Clear/GPIOOutputs/
ForceFan/PhaseCorrection/
ReadsFPGAState/SwapSegment/
Silencer/Synchronize/
FociSTM (焦点数が4000未満)/
Modulation
18446744073709551615
PulseWidthEncoder/
FociSTM (焦点数が4000以上)/
/GainSTM/Gain
CPUのコア数

inspect (Rustのみ)

GainModulation, GainSTM, FociSTMの計算は並列化やメモリアロケーションを最小にするために遅延されており, 計算結果は送信フレーム内に直接構成される. そのため, これらの計算結果を送信前に直接確認することはできない.

Controller::inspectを使用することで, 送信することなく, これらの計算結果を確認することができる.

use autd3::prelude::*;
#[allow(unused_variables)]
fn main() -> Result<(), Box<dyn std::error::Error>> {
let autd = Controller::open([AUTD3::default()], autd3::link::Nop::new())?;
let r = autd.inspect(Null {})?;
dbg!(&r[0]); // result of device 0
// &r[0] = Some(
//     GainInspectionResult {
//         name: "Null",
//         data: [
//             Drive {
//                 phase: 0x00,
//                 intensity: 0x00,
//             },
//             ︙
//             Drive {
//                 phase: 0x00,
//                 intensity: 0x00,
//             },
//         ],
//         segment: S0,
//         transition_mode: None,
//     },
// )

Ok(())
}