デストラクト(@Rust)

デストラクト(destructuring)は紛らわしいのですが、Rustの変数がスコープを外れた時に廃棄されるデストラクター(destructor)とは別物です。

ではデストラクトとは何かというと、

https://exercism.org/tracks/rust/concepts/destructuring

に記載あるように、タプルや構造体の要素の初期化です。

About Destructuring

Destructuring is the process of breaking down items into their component parts, binding each to smaller variables.

例えばタプルの初期化ならば、

Destructuring Tuples

Destructuring tuples is simple: just assign new variable names to each field of the tuple:

let (first, second) = (1, 2);

というふうに、機能的にはJavaScriptの分割代入 (Destructuring assignment) 構文と同じに見えます。

Rust by exampleでは、

https://doc.rust-lang.org/stable/rust-by-example/flow_control/match/destructuring.html

が公式ドキュメントです。

 

admin

構造体リテラル更新記法におけるString型(@Rust)

構造体のインスタンス作成時に、すでに作成済みのインスタンを使用するということですが、以下の例でdivの型をString型とするとコンパイルが通りません。

何故なら、divをString型にするとemp2で..emp1でdivを使用した瞬間に所有権がemp1からemp2に移動してしまうためです。数値はプリミティブ型なのでそのようなことは起きないのですが。

#[derive(Debug)]
struct Employee<'lt> {
    name: String,
    age: u8,
    grade: u8,
    div: &'lt str,
}

fn main() {
    let div: &str = "sales";
    let emp1 = Employee{name: String::from("John"), age: 30, grade: 3, div: div};
    let emp2: Employee = Employee{name: String::from("Bill"), age: 25, ..emp1};
    println!("{:?}, {:?}", emp1, emp2);
}

つまり構造体でフィールドとして参照を持つ場合、参照フィールドには必ずライフタイムが必要ということです。

以下のようにstatic宣言にしてプログラム実行中のライフサイクルにしても良いですが、永続的なライフタイムを持つすなわちメモリをずっと占有してしまいます。

struct Employee {
    name: String,
    age: u8,
    grade: u8,
    div: &'static str,
}

Rustでは所有権にまつわる規則がどこかで必ず現れてきます。

 

admin

 

 

電源オンオフスケジュール用のGUIがある時点から無くなってる(MacBook)

昔の設定がMacOSのアップデートで設定が引き継がれていただけですが、以前はGUIでリブート設定していたものが、今はコマンドラインで設定するように変わっていた。ずっと変えてなかったから気づいていなかったけど。

pmsetコマンドで現在の設定を見てみると、

@MacBook-Pro ~ % pmset -g sched
Repeating power events:
restart at 5:00AM every day

こんな感じになっているから、最後の行のパラメータをpmsetコマンドで打ち込めばいいんだろう。使い方は、

% man pmset

で見れます。

 

admin

 

 

 

マイクラEEでmaze

maze(迷路)の作成アルゴリズムには色々ありますが、一番単純なアルゴリズムが棒倒し法です。棒倒し法のアルゴリズムは他で参照していただくとして、それをマイクラEE(教育エディション)で実装してみます。bedrock版でもプラグイン使うとMakecodeと連携できるようですが、マイクラEEではデフォルトでcode builder(中身はMakecodeと同じに見えます)が使えますからエージェントに迷路を作成させてみます。

いきなりですが、作成した画像は、

こんな感じです。

動画版は、

code builderのソースは以下のリンクから、

https://minecraft.makecode.com/88632-58071-51947-80905

① 初期化処理(『最初だけ』)で周りの囲いと一つおきに棒(以下ブロック)の配置をするための配列(リスト)を作成、リストを二つ作るのはブロックの重複置きチェックのために倒したブロックの配置を記憶しておくためです

② チャットコマンド”maze”を入力したときに、最初に枠と棒倒しの基準になるブロックを置き、次に迷路作成のための”make_wall”を呼び出しています

③ make_wall中では最初のブロックと二番目以下のブロックでは倒せる方向の可能性が違うので、引数で処理を分けて実際の棒倒し処理(“random_block”)を呼び出します。

④ random_block中では乱数で倒す方向を決めて、もし倒す方向に既にブロックが存在していれば、他の倒し先を乱数で決定して倒しますが、この処理も最初のブロック列と二番目以下のブロック列では処理が異なるのでロジックを分けて記述必要です

簡単に書くとこのような処理を行なっていますが、code builderのブロック言語でそこそこ長いコードを記述すると、コードの見通しが良くないので、実際のロジックの検証はPythonあるいはJavaScriptに展開されてコードで行うのが現実的。あとデバッグ機能のようなものも存在しないのでそこが不便なのと、変数のスコープがいまいちすっきりしないので、関数へはsize(正方形のサイズ)以外は引数渡しにしてローカル変数のごとく使っています。

これ以上に複雑なmazeロジックの記述はおそらく大変、

 

admin

 

ホバークラフト(浮上力向上させた)

発泡丼では空気室の面積が不足で、浮上力が思ったように出ないから、電池電圧が低下すると浮き上がらない。

対策は設置面積を増やすことですが、あまり大きすぎると重量制約も出てくるだろうから、ホームセンターで発泡板を上質紙で挟んだ軽量のボードを買ってきて組み込み。

組み上げるとこんな感じ、

スカート用の素材に使えそうなもの(テープ付き養生シート)があったので、それを貼り付けます。ただしスカートが開かないように左右を紐で抑えるため両面テープで貼り付け。x/y方向でそれぞれ3本づつ使いました。

動かしてみているところ、

マイムービー – SD 480p

 

回転モーメントが発生しているようで、自然にUFOのごとく自転しています。おそらくモーターの回転数がアンバランスではないかと思われますが。

ようやくスタートポイントといったところですね、

P.S. 2024/2/2

回転の原因はモーターの回転数変えてみて、回転数が支配的ではなくて、傾いて取り付けられていることによる横方向の力がおそらく原因。したがって取り付け角度のコントロールが必要ですが、構造作り替え必要です。横方向の力が働くので、回転すると同時に移動も発生していると思われます。

 

admin

Volumio2でSpotifyのプラグインを使う

SpotifyをPremiumプランにしたので、Bluesound Node(Spotify connectが実装されている)だけでなく、Volumio2(raspberry pi zero)でSpotifyのプラグインを使って音出ししてみた。

Spotifyを再生するだけならAirPlayでもいいですが、当然ですが音質は落ちます。

Spotify connectを使うと音楽ファイルをWi-Fiで飛ばすことなくVolumioから直接Spotifyの音源を取り込むので音質的にはベストです。

インストールは簡単で、プラグインメニューでVolumio Spotify Connectをインストールしてアクティブにすると、

Spotifyのアプリ画面からVolumio2(そういう名前にしてます)が追加されるので、

Volumio2に切り替えれば、あとはブラウザから演奏中の曲情報が見えます。

 

CD qualityで再生されています。一点気になるのはゲインが固定ではなくて可変できてしまうことでしょうか。–> プラグイン入れる前からそうなってただけ

BluOSからアクセス(プレイ)するとSpotify connectがNodeに切り替わるので当然コントロールは排他的です。

改めてVolumioは優秀なソフトです。I2S DACは、

https://www.allo.com/sparky/miniboss-rpi-zero.html

を使ってます。

P.S. 気づき(2024/1/24)

① アルバムの途中で中断して、再度のSpotify connect後に新たなアルバムをプレイすると、ブラウザ上には旧いアルバムの表示がされて、次の曲が始まった時点で新たなアルバムに切り替わり

② Volumioの再生を二十分(仕様は10分?)ぐらい停止するとSpotify connectは切断されます

 

admin

ホバークラフト(レビュー)

ちょっと触ってみた感触ですが、

① 電池電圧が満充電状態ではおよそ4.1V程度あってモーターの風量も多いけれども、3.9Vぐらいになると明らかに浮力が落ちる

② 本体の重量測ると207g程度で電池が二個で35g、合計でおよそ240gだから、Telloのほぼ3倍の重量だから結構重い

③ ファンの空気の抜けがイマイチの感

ファンとモーターの取り付けのV2設計図ですが、ドローンも概ねこんな感じだから作り替えが必要と思う。

④ 9軸センサーなしではやはり姿勢制御は辛い、micro:bitで使えそうなのは回転をコントロールできる方角センサーだけだろうから

 

垂直方向がないだけで、実質はほぼドローンと類似の制御が必要ということだろうから、V2の設計を始めてみるか。

 

admin

 

ホバークラフト浮上した

ドローン用のLi-ion電池はパワーがあるので、電池一個でモーター2個駆動は余裕がありそうです。(まだ電池は固定していない)電池の公称容量は750mAhなので実働15分ぐらいは動きそうです。

 

micro:bitのラジオ機能使って、もう一台のmicro:bitで動作をコントロールするようにしてみました、今は浮上と停止機能のみの実装ですが。

以下のムービーを見ると分かるように、同じ電圧でモーター駆動しているにも関わらず全体のバランスは取れてないだろうからドリフトします。チューニングでほぼ固定状態に持っていけるだろうと思いますが。ドローンならば自分の位置をセンスしてフィードバックしているはずですが、micro:bitにはそのような機能はありません。

マイムービー – SD 480p

 

admin

電池と接続ケーブルがようやく揃った

NiH電池(単三)では電力不足でプロペラ回らないので、大陸からほぼ一月かけて電池と接続ケーブルを入手。

電池の充電はコネクタの接続が全く安定しないので、接続ケーブル(オス)に付け替えて安定動作(ちゃんと充電)するようになりました。

ただし、USBコネクタ繋いだ状態で電池繋いでも充電開始されず、電池を繋いだ状態でUSBコネクタを繋ぐと充電開始されますが、そう言うふうにできているんでしょう。

これでホーバークラフトのモーターとMicro:bitに繋ぐとちゃんと動くはずだろうけど、テスターの電池切れて使えなくなったので(LR44)電池待ち。

ケーブルはオスメスで、これでホーバークラフト本体に接続して充電時は取り外し。こちらのケーブルはちゃんと出来てる。

 

admin

所有権と借用について(@Rust)

Rustのメモリ管理の特徴の最大の機能と言えるものが所有権ですが、所有権(以下ではほぼ借用についての記述)と参照借用の特徴的なところを簡単なコードで説明できるようにしてみました。まあ、オリジナルのドキュメント読めばわかることですが。

以下のコメントでcase1~4がそれに該当するところです。

case1 : mutableな変数(ここではString型)をmutableで参照借用すると、元の変数は変更ができなくなるし、一度借用したらその後の複数借用もできない。変更を伴うと制限が出てくるのは、所有権に類似してます。

case2 : mutableにできる変数をimmutableで扱う場合は変更される可能性がないので、参照処理はcopyになり尚且つ複数のcopyも許容されます。

case3 : mutableにできない静的領域に格納される変数の場合には参照(&)を付加しなくとも暗黙で参照(copy)できます。文字型(char)はcopy traitを実装しているから。(ヒープを利用するString型のcopyにはclone()を使います)

case4 : 参照と非参照の比較はできないので、参照戻し処理(*の付加)が必要になります。case1でも参照型で使える関数の制限で参照戻しを使っていますが、

fn main() {
    // case1 : borrow in "String":mutable case
    //
    let mut aa = String::from("abc");       // variable length "String"
    let bb = &mut aa;
    bb.push_str("gh");
    let cc = format!("{}{}", "ko", bb);    // Linking "Strings"
    println!("mutable case (bb, cc) : {}, {}", bb, cc);

    //aa += "refa";     // error ; second mutable borrow occurs here, after first borrow you can't change the original content
    *bb += "refb";      // you can't use `+=` on type `&mut String`, use reference return
    println!("updated bb : {}", bb);

    // case2 : immutable case
    //
    let aa_i = String::from("kile");
    let bb_i1 = &aa_i;
    let bb_i2 = &aa_i;
    println!("immutable case (bb_i1, bb_i2) : {}, {}", bb_i1, bb_i2);

    // case3 :  literal(immutable) case in "str"
    //
    let aa_c = "abc";
    let bb_c = aa_c;    // refrence in immutable case, you can eliminate "&"
    //bb_c.push_str("gh");  // "push_str" is not found in `&&str` since bb_c is immutable
    let cc_c = format!("{}{}", "ko", bb_c); // linked output is a "String"
    println!("bb_c, cc_c : {}, {}", bb_c, cc_c);

    // case4 : reference return
    //
    let original = String::from("def");
    let reference = &original;
    if original == *reference {        // comparing "String == &String" causes compile error, if "*" is not used
        println!("equal");
    } else {
        println!("not equal");
    }
}

所有権の本質は、ある変数(ヒープ上の変数、静的領域上の変数に対しては所有権の概念は無い)を変更できるのは所有権を持っている唯一の変数だけだよといっていますが、借用は所有権は移動せずに参照/変更する権利は有すると言うことになります。変更できる借用(可変借用)は実質的には所有権を移動することと同等なので、掛かる制限が出てくると言うことになります。

 

admin