まずはきちんと浮かせることが出来るかどうかを検証しました。
空気室はホームセンターで調達の発泡丼、そこにモーターとプロペラ固定用のアダプタを3Dプリンタで造形して嵌め込み。
外部電源で4.8V(単三のNiH電池四直を想定)を与えると、元気に浮き上がりました。元気すぎてひっくり返りますが、
空気室への取り付け方と、全体(4個の空気室)の結合方法考えて、改善したものを4個と全体保持機構(これはアイディアこれから)を作ります。
admin
la vie libre
Rustには例外処理もnullもありませんが、これはRustの思想そのもの。例外処理やnullが無い代わりに、その機能をサポートする手段として、enumとしてのResultやOptionがあるということになります。
https://doc.rust-lang.org/std/option/
を参照すると、”Type Option
represents an optional value: every Option
is either Some
and contains a value, or None
, and does not.“であり、Rustでは標準的に使われる機能になります。
とありますが、Optionは実は、以下のようなenumになっていて要素としてはNoneとSome(T)が存在してます。
pub enum Option {
None,
Some(T),
}
通例では、Optionはパターンマッチングと一緒に使われて、rust-lang.orgの以下のサンプルコードを見ると、match resultでマッチング処理を行なっています。
fn main(){
fn divide(numerator: f64, denominator: f64) -> Option {
if denominator == 0.0 {
None
} else {
Some(numerator / denominator)
}
}
// The return value of the function is an option
let result = divide(10.5, 1.5);
// Pattern match to retrieve the value
match result {
// The division was valid
Some(x) => println!("Result: {x}"),
// The division was invalid
None => println!("Cannot divide by 0"),
}
}
Optionに限らずResultも類似のやり方で処理されます。
いずれにしてもRust固有の記法というように見えます。
admin
モーターの次は回転制御のためのレギュレーターですが、中国本土から出荷で到着予定日をかなり過ぎてから到着。
二個使いで、一個でモーター二個の制御ができます。
アプリケーションノートは、
https://logikara.blog/raspi-pico-dcmotor/
あたりが接続の参考になりそうです。
admin
micro:bitで制御するホーバークラフト用のパーツとして、まずドローン用のモーターとプロペラを購入。
https://www.amazon.co.jp/gp/product/B078GM6PRN/ref=ppx_yo_dt_b_asin_title_o01_s00?ie=UTF8&psc=1
ブラシモーターですが、まあ寿命とか気にするわけではないので。
cwとccwの識別は配線の色、もしくはキャップ部分の色で識別可能です。
PWM制御用のレギュレーターは中国本国から出荷のようで来週になるでしょう。
https://www.amazon.co.jp/gp/product/B07P2TL2SF/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1
見たところ、パワー系の部品が見当たらないので、これでPWM制御で使えるのかと思いますが、事例を見る限りは問題なさそうです。
admin
Maker Faireで見た人が乗れるホーバークラフトですが、
ドローンに比較すると相対的には少ないエネルギーで浮上できるし、落下の危険性もないから安全だと思うのでmicro:bit使って制御する模型を作ろうかと思っていますが、進行制御はどうするのか?
シンプルに考えれば、ファンを4個持つドローンのような制御方法を考えれば、反転方向の回転速度を落とせば時計方向、半時計方向のターンができるし、片側2個の回転速度を上げれば反対方向に進むように思うけれどもこれでうまくいくのか。
まあ、やってみるしかないからドローン用のモーターを買ってみようと思う。
電池はLi-ionでなくともNiMH使っても重量増加は、これも問題ないように思う。
admin
本日初めて行ってきました。オレイリージャパンの主催でスポンサーも多数、出展は個人レベルから趣味のグループ、大学が主体でメーカーは少ない印象です。
そのうちのいくつかの作品から、全部の写真は多すぎなのでおいおい整理、
1 静電容量方式でキータッチすると音階を指定できるキーボード。
2 自作のMRI、液体窒素冷却とかしなくとも解像度が低くなるけれども核磁気共鳴はセンスできるそうです。画像に落とし込むソフトも全部自作だそうです。おそらく標準のライブラリはあるでしょうが。
3 両手で持って、リングのように見えるのが弦相当で演奏できる電子楽器。
会場の作品を見ると、多くはラズパイ、M5Stackを使っています。これはM5Stackのブース。
全部を細かく見だすと、到底一日ではカバーできそうもないので最後は結構駆け足になってしまいました。
個人的に会場の作品制作などを見て、あれば良さそう(欲しい)と思ったのは、レーザーカッターと多軸関節ロボットアーム。どちらも10万円以下で個人でなら使えそうなものが手にはいる。
admin
println!とかvec!はRustにおける頻繁に使われるマクロですが、マクロは多くの言語が持つ機能でそれはコンパイル時には展開されます。じゃRustのマクロがどのように展開されるか?を見るためのツールにcargo expandがあります。
https://crates.io/crates/cargo-expand
cargo initで作成されるmain.rsで見てみます。
<ソース>
fn main() {
println!("Hello, world!");
}
マクロを含んだソースコードを対象にするならば、*.rsファイルの存在するディレクトリでcargo expandを実行します。
<展開後>
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
fn main() {
{
::std::io::_print(format_args!("Hello, world!\n"));
};
}
展開されたコード中には、さらにformat_args!というマクロが見えています、まあマクロからマクロは呼び出しできるから。
format_argsマクロを検索すると、以下のように記述されています。
https://doc.rust-lang.org/std/macro.format_args.html
macro_rules! format_args {
($fmt:expr) => { ... };
($fmt:expr, $($args:tt)*) => { ... };
}
という事で、引数がいくつかある場合にそれを展開してprint形式を作り出すマクロです。
実はcargo expandはパラメタ指定でソースコードではなくてバイナリからもマクロが展開されたソースコードの出力ができます。ソースコードからexpandしたものと全く同じに見えますが。
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
fn main() {
{
::std::io::_print(format_args!("Hello, world!\n"));
};
}
使い道はカスタムに作られたマクロのソースコード確認用になるでしょうか。
admin
メモリ管理を厳密に実行できるRustではスレッド間通信にmutexを使うのも現実的のように思います。おそらくchannelよりは軽量だろうと想像されるから。
https://doc.rust-jp.rs/book-ja/ch16-03-shared-state.html
を参考にchannel版からmutex版に書き換えてみます。
https://isehara-3lv.sakura.ne.jp/blog/2023/10/10/スレッド間通信でchannelを使うrust/
肝は追加されたクレートのMutexとArcになるでしょう。Rcはスレッドセーフではないので多少処理は遅くなるけれどもArcが用意されているようです。
以下のコードではchannel版をコメントアウトしてmutexに置き換えています。
use std::sync::{Mutex, Arc};
use std::thread;
use std::time::Duration;
//use std::sync::mpsc;
fn main() {
//let (tx, rx) = mpsc::channel();
let count = Arc::new(Mutex::new(0));
let mut handles = Vec::new();
for i in 0..3 {
//let thread_tx = tx.clone();
let count = Arc::clone(&count);
let handle = thread::spawn(move || {
for j in 1..10 {
println!("hi number {} {} from the spawned thread!", i, j);
thread::sleep(Duration::from_millis(1));
}
//thread_tx.send(i).unwrap();
let mut num = count.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for i in 1..5 {
println!("hi number {} from the main thread!", i);
thread::sleep(Duration::from_millis(1));
}
for handle in handles {
handle.join().unwrap();
}
//drop(tx); // without drop(), this program doesn't terminate, wait for tx forever
/*
for received in rx {
println!("Got from the threads : {}", received);
}
*/
println!("Result: {}", *count.lock().unwrap());
}
mutexで定義した変数の型は整数型ではない(VScode上では:Arc<Mutex[i32; 1]>>と表示されている)ので、unwrap()してやらないといけないのはRust特有ですが、Rustのスレッド間通信(共有)でmutexも選択肢に入りそうです。
admin
Rustの場合にはchannelを使わなくても、メモリ管理がきちんとされているのでmutexでも良さそうなのですが、channelの方が使うのは簡単だと思う。ほぼGolangと同等の機能ですが、rx/txを同時に定義するのは異なります。Golangは -> もしくは <- でインアウトを切り替えるし、channelのサイズも指定しますが、RustではFIFOのように動作します。
以下のコードは、
https://isehara-3lv.sakura.ne.jp/blog/2023/10/06/並行処理rust/
にスレッド起動後にスレッドの番号をchannelに送るようにしたもの。一点注意すべきはtxはmainスレッド中で生成されているので、for received in rx処理はdrop(tx)しないと無限待ちになること。もしクロージャー中ならば、そのライフが終わった時点でdrop()されますが。
use std::thread;
use std::time::Duration;
use std::sync::mpsc;
fn main() {
let (tx, rx) = mpsc::channel();
let mut handles = Vec::new();
for i in 0..3 {
let thread_tx = tx.clone();
let handle = thread::spawn(move || {
for j in 1..10 {
println!("hi number {} {} from the spawned thread!", i, j);
thread::sleep(Duration::from_millis(1));
}
thread_tx.send(i).unwrap();
});
handles.push(handle);
}
for i in 1..5 {
println!("hi number {} from the main thread!", i);
thread::sleep(Duration::from_millis(1));
}
for handle in handles {
handle.join().unwrap();
}
drop(tx); // without drop(), this program doesn't terminate, wait for tx forever
for received in rx {
println!("Got from the threads : {}", received);
}
}
出力の最後部分だけ、
~~~~~~
hi number 0 9 from the spawned thread!
hi number 2 9 from the spawned thread!
Got from the threads : 0
Got from the threads : 1
Got from the threads : 2
P.S. 同じスレッド間での通信になっていたので修正(2023/10/11)
送信エンドポイントはclone()しないとコンパイルが通りません(moveしたものをdrop()はできないから)。clone()して複数の送信エンドポイントから送信でもrxに集約されるようです。
admin