3Dプリンタでニンテンドースイッチのスタンドを作った!

久々の更新です。

大学四年になりました。就活の時期ですが、最近、ニンテンドースイッチでゼルダをするのにハマっています…!
スイッチはテレビでも遊べますし、ポータブルにもなります。もう本当に素晴らしいゲーム機です。充電しながら立てられないこと以外は!

スイッチをお持ちの方はわかると思いますが、本体から生えているスタンドは充電しながら立てることができません。

ライセンス商品として、プレイスタンドがあるのは知っていますが、僕の持っているキャリングケースには収まらない気がして買うのを控えていました。(収まったよ!と言う方コメントお願いします。買います)

そんなわけで、3Dプリンターでスタンドを作ってみようと調べていたら、海外の方が超画期的なスタンドを自作しているのを見つけました。

紹介動画

※動画投稿者と3Dデータの製作者は異なるっぽいです。 www.youtube.com

ジョイコンを差し込むところに付けられる分割型のスタンドです。薄いのでキャリングケースにも余裕で入ります。本当に天才的な発想です。
早速プリントして使ってみたのですが、いくつか問題がありました。

問題点

3Dプリンターの設定が難しい。

動画の通り、スタンドは上から差し込みます。なので、スイッチ本体の重さで落ちてしまうのです。
f:id:takumus:20170416113513g:plain
素材を厚めにプリントすれば摩擦も大きくなるので落ちる心配は無くなります。ただ、本体の重さを支えるほどの摩擦なので、装着時にレールに大きめの負荷がかかると思います。

長く使えない。

初めは固定されたとしても、何度も使うことで素材が削れて滑るようになるかもしれません。

純正の充電ケーブルを使うと足が浮いてしまう。

海外の方も動画内で、純正のケーブルだと使いにくいから別のなら使えると紹介しています。
足が短いので端子が地面についてしまいます。

これらの問題を解決するため、基本構造をパクリつつ、俺バージョンを作ってみました!

パクって作った俺バージョン

※カチッと言う音が鳴るので音あり推奨です。 www.youtube.com Fusion 360で作成しました。 f:id:takumus:20170415133038p:plain スライド用のT時の部分は海外の方のものとほぼ同じです。それに加えて先端にロックをつけました。つまんでいる間はロックが外れるようになっています。ジョイコンの仕組みと同じです。
f:id:takumus:20170415133140p:plain f:id:takumus:20170415171653p:plain CAD初心者が頑張って作るとこんなスケッチになるので本当にすみません。
f:id:takumus:20170415140343p:plain

改善点

プリンターの設定や精度に依存しにくくなった気がする。

あそびを多く取って設計しました。そのためスムーズにスライドします。でも滑り落ちることはありません。ロックがついているのでカチッと止めることができます。

長持ちすると思う。

遊びが多いので、スライドをしても負荷がかかりにくいと思います。ジョイコンよりも緩く設計したつもりです。そのためスライドによってパーツが削れることも少なくなったのではないでしょうか。

純正ケーブルでも大丈夫でしょう。

長めに取ったので問題はなさそうです。 f:id:takumus:20170415134049p:plain

純正キャリングケースに入った。

これは改善点ではなく、長くはなりましたが一応入りますという報告です。

3Dデータ

こちらからダウンロードできます。
www.thingiverse.com 現状、ノーマル版とミニ版があります。
※ノーマル版を推奨しますが、もしもお持ちのプリンターに入りきらない場合はミニ版を使用してください。
ミニ版は少し短いため充電ケーブルがやや干渉します。そのためノーマル版よりも傾斜があります。

これから

もう少し機能追加版を作ってみたい。

角度が変えられたり、ケーブルをまとめられたり等。色々思いつきますが、 高品質なプリンターでしかプリントできないような細かいギミックはもう少し検討しようと思います。
そういうバージョンとして別に出すと言うのもアリですね。
※私はGenkei社のLepton 2を使用しています。

Fusion 360

装着部分だけ3Dモデルを切り離すことに成功しました。Fusion 360難しいです。
ですがこれでスタンドのバリエーションを増やすのも楽になりそうです。
f:id:takumus:20170415170603p:plain

自転車のホイールにお絵描きした

まえがき

なぜ作ったか

 私の通う大学には1年間かけてグループで何かを作る「プロジェクト」というものがあり、私は「自転車をスマートに!」というテーマのプロジェクトに参加しました。
 他のメンバーは、自転車にウインカーを付けたり、自動変速機(開発担当の記事へのリンク)を付けたり。私もそれらを手伝う予定だったのですが、急に思いついてしまったので残像ディスプレイというものを考案しました。残像ディスプレイと言うのは私が名付けたのですが、簡単に言うと、数十個のledの列が回転しながら点滅して残像で絵や文字を表示するものです。既にそのような製品は割とあるので、ご存知の方は多いかもしれません。

f:id:takumus:20161223234036j:plain

既にあるのになぜ作ったか

 既にある製品は、自転車のタイヤに絵を描画するためにsdカードなどのメディアを経由するものが多く、車輪を一時的に停止する必要があります。(後日調べたらbluetoothで転送するタイプの物がありました。まじで悔しいです)
 そこで、スマートフォンなどで描いた絵や文字をリアルタイムで転送する仕組みを取り入れたらもっと面白くなるのでは!と思い制作しました。

プロジェクト発表会での展示

お絵描き体験

www.youtube.com スローはこちら
 PCに表示したQRコードを読み取り、スマートフォンで描いた絵がタイヤに反映されているのがわかります。プロジェクト発表会は、それぞれのブースに見学者が見にくる形式なので、自分のスマホで描いた絵をタイヤに送信できるという体験をして貰うことにしました。

具体的な説明

写真

全体像です。 f:id:takumus:20161221142546p:plain ラズベリーパイとモバイルバッテリーが積んであります。 f:id:takumus:20161221142923j:plain シフトレジスタとLEDを付けた基板です。 f:id:takumus:20161221142910j:plain 半田頑張りました。 f:id:takumus:20161221142935j:plain 基板からのケーブルはラズベリーパイに刺せるようにしています。 f:id:takumus:20161223112515j:plain タイヤから外した全体像です。 f:id:takumus:20161223112600j:plain ※ケーブルの色が違いますが、写真を撮った時期が違うのです。

ハード面

 LED表示部分の基盤はシフトレジスタを大量に使用し、5本位の線で制御しています。またリードスイッチと磁石を組み合わせる事で回転数を取得し、LED点灯のタイミングを制御しているので、低速でも高速でも乱れる事なく表示ができます。
 ラズベリーパイにつながっているケーブルはリードスイッチとLED制御線のみで、開発においてはハード面よりもソフトウェア面の方が大変でした。

ソフトウェア面

 今回、展示用にQRコードを読み取ってもらい、ブラウザから絵が描けるという体験を実現させました。ブラウザからタイヤにデータを送るのに、そこそこ多くのレイヤーを挟んでいます。

お絵描きツールと、お絵かきサーバー

f:id:takumus:20161221154608p:plain  見学者にすぐ絵を描いてもらうためには、ブラウザという選択肢一択でした。canvasは直接触るのは大変なので、PIXI.jsを使ってお絵描きツールを作りました。このお絵かきツールは描いた線の座標情報をサーバーに送信する機能しかありません。座標情報は、node.jsで立てたhttpサーバーに送られ、そこから動画右下に置かれたPCに送られます。
 線を描くごとに(タッチリリース時に)データ送信をしているのですが、時々失敗するので一応送信ボタンもあります。ちなみにこのお絵かきツールの自転車のホイールイラストはスクリプトで描いています笑

 今回展示用という事でたくさんの人がQRコードを読み取り絵を描きます。しかしこの仕様だと、例えば体験を終えて部屋の外に出た後もそのURLから絵を送信する事ができてしまうので、いろいろと問題になります。 今回それらを徹底的に対策しました。
 QRコードで取得できるURLを、http://~~.com/?hogehogeこうしました。最後にハッシュ値を加えています。そして見学者が入れ替わるごとにハッシュ値を更新し、QRコードを再生成します。クライアントは送信時にこのハッシュ値をサーバーに送り照合します。サーバーはそのハッシュ値が最新のものでないと絵の受信を拒否する仕組みにしました。これで問題は解決です。 f:id:takumus:20161221155141p:plain

お絵かきデータの変換

 お絵描きサーバーから送られた座標データは動画右下に置かれたPCで残像ディスプレイ用データに変換されます。この変換ソフトはAS3で書き、AIRアプリケーションとして動作しています。変換には、やや重い処理が必要になるのでWorker(スレッド)を立てて処理しています。
 変換自体もサーバーでやりたかったのですが、時間がなかったので自分が得意なAS3で実装することになりました。それ以外にも色々な理由はありますが!
 変換されたデータはいよいよラズベリーパイへ送ります。ラズベリーパイはPCと同じネットワークにつながっているのでローカルネットワーク上でデータをやり取りしています。

LED制御

 PCが送信したデータはラズベリーパイ上で走るnode.jsサーバーが受信します。サーバーはchildprocessとしてC++で書いたled制御プログラムを走らせていて、受信したデータをchildprocessへ標準入力で渡します。
 C++で書いたled制御プログラムは、複数スレッドで構成されています。データ受信スレッド、回転数検知用スレッド、led点灯用スレッドが主なスレッドです。なので回転しながらスムーズにデータを受信したり、回転数にあわせてledを点灯する事ができます。回転数に合わせてledを制御する細かいロジックについて解説すると、とても長くなってしまうので省略させていただきます。最後に貼ったソースをご覧ください。

さいごに

ソース

github.com 終盤追い込みで開発したので、ソースや設計が汚いのと、階層がぐだぐだなので許してください。
一応少し大まかに階層を分けておくので、興味のある方はご覧ください。

ラズベリーパイ側のC++とnode.js部分

/server/src

PCで絵を変換する部分

/client

お絵描き用のWebページ部分

/web_client

お絵描き用のサーバー部分

/web_server

お礼

 ここまでお読みいただきありがとうございました。質問などございましたら、me(あっ)takumus.comまたは@takumusまで。

ListUI for as3を作った。

FLASHer その2 Advent Calendar 2016の20日目の記事です。

github.com

どんなライブラリなの!

 タッチでスクロールが出来てドラッグで並べ替えが出来る気持ちの良いListUIライブラリです。リストのセルや右側に出るスクロールバー等、すべてが拡張(自作)することを想定して作られているため、使用のハードルがやや高いかもしれません。デフォルトスキンなどが存在しません。作ってください!
 最近は特にflashはオワコン!とか言われてはいますが、AIR等を使ったアプリやソフト。そういったものは意外と世の中で生きています。(展示物系等でも多いです。)そういった部分で必要になったので作りました。
 as3がある程度分かる人に向けた解説になります。分かる人はgithubのサンプルのソース読んでください笑。

サンプルを用いて解説

サンプルを用意しました。
サンプルの機能:
・セルをタッチすると、そのデータがログに出る。
・右の方をドラッグで並べ替え。
・左の方クリックで削除。
・ドラッグや削除でデータに変更があるとログに出る。

f:id:takumus:20161219182319p:plain

demo : http://takumus.com/labs/list-ui-for-as3/samples/demo/
demoのソース : github.com

Listクラス

demoのメインクラスである、Demo.asから重要な部分を切り出しました。
gist.github.com  Listクラスは、初期化時にセルクラス、セルの高さ、セル同士の間隔、スクロールバークラスを要求します。 必須なのはセルクラス、セルの高さだけです。セルクラスについての説明は下で行います。
 Listにデータをセットするにはlist.setDataを呼びます。Arrayを渡すだけです。demoでは、A~Uまでを渡しています。
 セルから送られてくるメッセージを受け取るには、ListEvent.MESSAGEを追加します。メッセージについても下で解説します。
 Listのデータに変更があった場合、ListEvent.UPDATEが発火されます。この時、変更後のデータはlist.getData()で取得できます。

ListCellクラス

 demoのSimpleCell.asを見てみましょう。これはDemoのセルクラスです。削除ボタンや、ソートボタン、そしてラベルなどが配置されているのが分かります。List初期化時に渡していたセルクラスとはこれの事です。ListCellを継承して作ったオリジナルのセルです。このように渡すことで、Listはこれを生成し画面に配置してくれます。

resizeメソッド

 ListCellにはresizeというメソッドがあります。これはCellがレスポンシブであるために用意されたもので、Listのresize時に呼ばれます。SimpleCellでもresizeをオーバーライドして、テキストやボタンの位置、背景の再描画を行っています。基本的にはresizeはオーバーライドしてください。

setDataメソッド

 ListCellにはsetDataというメソッドがあります。これはセルのデータが更新された時に呼ばれます。今回、ListにsetData("ABCDEFGH...".split(""))という具合でStringの配列を渡したので、setData(data:CellData)のdata.dataはStringになります。(ジェネリクス使った方が良かったですね。今度直します。)
 例えば今回のSimpleCell.asで、setDataメソッドは
_label.text = data.data.toString();
と実装されています。dataはCellDataなのでdata.dataとしなければいけない事に注意してください。

クリック、タッチ、そしてmessage、remove、sort...

 細かい解説の前に、注意点があります。タッチイベント、マウスイベントはどちらも必ずListCellMouseEventを使います。bodyに対して通常のマウスイベントやタッチイベントを追加してはいけません
 その理由として、例えばスクロールのためにセルをドラッグしてリリースする過程で、通常のイベントは、タッチもしくはクリックを発行します。スクロールしたときはイベントが出ないようにしたり、その他おかしな挙動が起こらないようなListCellMouseEventを定義してあります。なのでこちらを使いましょう。  SimpleCell.asに、このような記述があります。これはCellがマウスや指によって押された時の処理です。 gist.github.com  まずListCellMouseEvent.MOUSE_DOWN時に、マウスが右の方(ドラッグアイコンの位置)だったら、beginSort()を呼んでいます。これはListCellのメソッドで、as3で言うstartDrag()のようなもので、ドラッグアンドドロップによるソートを開始するというものです。マウスやタッチが解除され次第、勝手に終了するので、ソートを開始させたいボタン等がListCellMouseEvent.MOUSE_DOWNされた時にbeginSort()を呼べばdemoのような挙動をします。ソート完了時、ListEvent.UPDATEを発火します。
 次に、ListCellMouseEvent.CLICK時に、マウスが左の方(削除アイコンの位置)だったらremove()が呼ばれています。これもListCellのメソッドで、このセルを削除するという命令を出すものになっています。これが呼ばれた瞬間削除されます。削除確認ボタンを点けたい場合は、自前で実装してください。※削除完了時に、ListEvent.REMOVEを発火します。
 また、マウスがセル自体をクリックした場合にmessage()が呼ばれています。これは、ListCellからListへメッセージを渡すことが出来るListCellのメソッドです。引数に何らかのデータを入れることも出来ます。
 今回、message("Hi. My data is [" + data.data + "]")となっていますので、demoではセルタッチ時にログにこのようなメッセージが出ると思います。これは、Listクラスのインスタンスに対し、ListEvent.MESSAGEでハンドル出来ます。Demo.asを見ていただければ分かると思います。

スクロールバーのカスタマイズ

 正確にはバー自体をドラッグでスクロールする事はできないので、ただのスクロール(する位置を示す)バーですが!
 これについては、SimpleScrollBar.asを見ていただきたいと思います。
 resize時にレンダリングするようにresizeをオーバーライドするだけで完了です。new List()するときに4番目にそのインスタンスを渡せばよいです。

ListCellのインスタンス生成数とデータ数の関係について(割と重要)

 今回のUIは、ListCellのインスタンス数を極力減らすように心がけています。画面内に収まる最低の個数だけ生成し、データ数が1万件あろうが画面に5セルしか表示できないのであれば5つのインスタンスしか生成しません。
 これにより、パフォーマンスの向上を実現しています。一つのセルインスタンスとデータは対になっている訳ではないので、設計時は注意が必要です。setDataが全てです。

謝罪

 ライブラリの開発経験も浅く、自分のライブラリの説明などしたことが無いので随分とごちゃごちゃしてしまいました。それでも使用してくださる方がおりましたら、長い時間をかけてサンプルを見て解読していただくか、私に連絡していただけると幸いです! → me(あっ)takumus.com

ArduinoでDVDドライブのステッピングモーターを回す(スイッチでキャリブレーションする)

DVDドライブのモーターの回路は↓で紹介しています。 blog.takumus.com ステッピングモーター制御ライブラリSuteppaについては↓です。 blog.takumus.com

 DVDドライブのモーターがSuteppaを使って回せる!という事は紹介しました。そこで今回はもっと実用的なデモを行います。

私が手に入れたDVDドライブの仕様

 キャリブレーションの前に、まず私の手元にあるDVDドライブの仕様を調べましょう。以下のようになっています。
f:id:takumus:20161016124250p:plain  センサー部分が上下に動くように、軸がネジ状になっています。また、一番下に一番端に来たことを調べるためのスイッチが付いていました。
 一番下から上まで大体488ステップ(1-2相励磁で)必要なことも分かりました。ではこの仕組みをそのまま利用してセンサーを上下させてみたいと思います。

キャリブレーションする

 ステッピングモーターが現在の角度を把握できない(ロータリーエンコーダーなしで)という事はご存知だと思います。そんなステッピングモーターを制御するにはまず初期角度を設定する必要があります。こういった処理をキャリブレーションと言います
 今回は、とりあえず最大まで回してスイッチに触れたらそこをhomeとする。みたいなキャリブレーションを行いたいと思います。

スイッチへの食い込み?

 注意しなければならないことがあります。既にスイッチに深く食い込んでしまった状態でキャリブレーションを行うと、キャリブレーション開始と同時にその地点がhomeになります。モーターの力とスピードでスイッチを押した時と、元々押されたスイッチとで、homeにずれが生じます。

スイッチへの食い込み対策

 それを解決する方法として思いついたのが、まずスイッチ方向へゆっくり近づくのは同じですが、スイッチを押したら少し逆回転させ、再びスイッチを探す。というものです。確実にスイッチをモーターの力とスピードで押す。こうすることで正確なキャリブレーションが行えます。

スイッチへの食い込み対策の利点

 この方法を取る利点はもう一つあります。キャリブレーションは正確に行うため、基本低速で行うべきなのです。しかし、バーがスイッチから遠かった場合、スイッチに到達するまでとても時間がかかります。そこで今回の方法のように2度スイッチを押すことで、1度目のキャリブレーションを高速化し、スイッチを押したら2度目はその場所から少し戻り、ゆっくりキャリブレーションをするという事が出来ます。

ソース

gist.github.com

動画

 右側にスイッチがあります。一度右端に行って、ちょこっと戻る動作が確認できると思います。これがキャリブレーションです。その後は、紙で作った矢印とマーカーの位置から、正確に動いていることが分かると思います。
 Arduinoをリセットしてキャリブレーションからやり直させる。というのを何度か行っています。 www.youtube.com

Arduinoでステッピングモーターを制御するライブラリ「Suteppa」

このライブラリ開発記録のその1はこちらです。

 ライブラリの改良等をしていたため少し書くのが遅くなりましたが、公開できるレベルにはなったので公開したいと思います。

github.com

Suteppaとは

 Suteppaは、Arduinoでのステッピングモーターの制御を助けるためのライブラリです。注意して頂きたいのは、このライブラリ自体にステッピングモーターを回転させる機能は無いという事です。少しややこしいですが、実際にモーターを回すコードを貼ります。

「1回転→1秒→逆に1回転→1秒」を繰り返すソース

gist.github.com

解説

void step(int d)
{
    static const int hs[8] = {省略};
    static int i;
    i += d;
    if(i > 7) i = 0;
    if(i < 0) i = 7;
    byte b = hs[i];
    digitalWrite(IN1, bitRead(b, 0));
    digitalWrite(IN2, bitRead(b, 1));
    digitalWrite(IN3, bitRead(b, 2));
    digitalWrite(IN4, bitRead(b, 3));
}

 stepという関数がありますが、これは1-2相励磁でステップさせるために用意した関数です。この関数をSuteppaのinitに渡しています。Suteppaは渡されたstepを使って回転させます。このような設計にした理由は、1-2相励磁以外のいろいろな方法に対応する為です。ほかの励磁方法や、またマイクロステップをさせたい場合もあると思います。そういった場合に備えてステップを刻む関数は自分で作って渡してもらう事にしました。
 引数のint dですが、これはステップ方向を示しています。Suteppaがstepを呼ぶとき、dには-11が入ります。dによって回転方向が変わるような設計にしてください。

s.init(4096, step);

 ここでSuteppaをinitしています。一回転のステップ数と、上で説明したstep用関数を渡しています。1回転のステップ数は用途によっては必要ですが、分からない場合や、DVDのモーターのような回転せずスライドするタイプの場合等は0でも良いです。これが必要になるケースは後ほど説明しますが、基本的に0で良いと考えてください。

//100ステップを加減速に使い, 開始速度は2000us
s.beginSmooth(100, 2000);
//通常速度は700us
s.setSpeed(700);

 beginSmoothメソッドは加減速をスムーズに行うための設定用メソッドです。ここでは、加減速に最大100ステップ(合わせて200ステップ)を使い、開始速度は2000usという設定にしています。
 setSpeedで通常の速度を設定します。つまり今回の場合、100ステップかけて2000usから700usまで加速し、100ステップかけて700usから2000usまで減速します。

※usが小さい方が早く、大きい方が遅く回るので注意です。

//4096ステップ回転
s.rotate(Suteppa::RELATIVE, 4096);
delay(1000);

//0ステップへ戻る
s.rotate(Suteppa::ABSOLUTE, 0);
delay(1000);

 rotateメソッドは第1引数で回転モードを、第2引数にはステップを指定ます。ステップは負にすれば逆回転します。
 Suteppa::RELATIVEは相対ステップで、Suteppa::ABSOLUTEは絶対ステップで回転させます。よって今回の場合、現在の位置から、4096ステップ回し、その後0ステップに戻る。という事になります。  第3引数を含めた詳しいrotateの解説は下で行います。以上でデモのソースコードの解説を終わります。

rotateメソッドとtick

 rotate(int mode, long step, bool sync)

Suteppa::RELATIVE

 相対ステップです。現在の位置から相対的にステップします。

Suteppa::ABSOLUTE

 絶対ステップです。デフォルト位置からのステップへ移動します。

Suteppa::ABSOLUTE_SKIP

 同じく絶対ステップですが、最短で移動します。たとえば、一回転360ステップのモーターの場合、270ステップ地点から、0ステップへ移動するためには、+90ステップするか、-270ステップするかの2通りがあります。このモードでは、+90して最短で移動します。注意すべきはここでステップは0になります。360にはなりません。

tick

 rotateメソッドのsyncは省略できます。デフォルトではtrueです。ただ、このままだとモーターが1台しか制御できないという問題点があります。以下がその例です。s1s2の2台のモーターを制御します。

Suteppa s1;
Suteppa s2;
//初期化省略
s1.rotate(Suteppa:ABSOLUTE, 100);
s2.rotate(Suteppa:ABSOLUTE, 100);
Serial.println("ok");

 しかし、これだとs1の回転が完了した後にs2が回転します。同時には回転しません。rotateメソッドが処理を止めてしまうのです。
 この問題を解決すべく、tickで回転を行うという方法を用意しました。

s1.rotate(Suteppa:ABSOLUTE, 100, false);
s2.rotate(Suteppa:ABSOLUTE, 100, false);
while(s1.tick() || s2.tick()){}
Serial.println("ok");

 こうするとs1s2が同時に回ります。tickはモーターを回すためのメソッドで、回転中はtrueを返し、完了すればfalseを返します。回転完了後にtickを呼び続けても平気です。それ以上回転することはありません。
 ソースを見ればわかりますが、rotateメソッドはsyncがtrueだった場合最後にwhile(tick()){}をしています。tickを呼ぶ周期は可能な限り短い方が良いです。最低でも50usごとには呼んでほしいです。それ以上だとスムーズな加減速が出来なくなります。

スピードとスムーズモード

 最初のサンプルコードでも使っていますが、スムーズモードがこのライブラリの特徴です。加減速を調整することで脱調を防ぐことが出来ます。またステッピングモーターを確実に最高速度で回すことが出来ます。

setSpeed(通常速度us);
beginSmooth(ステップ数, 開始速度us);

 開始速度usから通常速度usまでステップ数分のステップでスムージングします。

スムーズモードの有効化と無効化

s.setSpeed(900);
s.beginSmooth(100, 2000);
s.rotate(Suteppa::RELATIVE, 1024);
s.endSmooth();
s.rotate(Suteppa::RELATIVE, -1024);

 スムーズモードはbeginSmoothメソッドで有効化します。endSmoothメソッドを呼ぶことでスムーズモードを解除できます。上記の場合、1024ステップをスムーズモード(2000usから900usまでを100ステップでスムーズに変化)で移動し、スムーズを無効化したのち1024ステップ戻ります。

脱調する場合

 脱調は、急な加速や減速が原因なので、脱調する場合はステップ数を増やすか、開始速度usを下げます(数値を上げます)。ただし開始速度us通常速度usの差が開きすぎるのも良くありません。その分ステップ数を増やせばよいですが、そこらへんは調整してください。基本的にステッピングモーターが始動できる速度を開始速度usに当てはめるのが良いでしょう。

デフォルトスムーズ

 頻繁にスムーズモードを有効化したり無効化する場合、いちいち値をセットするのは面倒です。そこでsetDefaultSmoothを用意しました。

s.setDefaultSmooth(ステップ数, 開始速度us);
//色々省略
s.beginSmooth();
s.rotate(省略);
s.endSmooth();
s.rotate(省略);
s.beginSmooth();
s.rotate(省略);
s.endSmooth();

 一度defautSmoothをセットすればbeginSmoothするだけでスムーズモードを有効化できます。

基準点のセット

 setHomeメソッドを用意しました。このメソッドを呼んだ位置が0ステップとしてセットされます。キャリブレーションを行う時に使えます。例えば以下のように。

s.rotate(Suteppa::RELATIVE, -9999, false);
while(s.tick()){
    if(digitalRead(SW) == 1){
        break;
    }
}
s.setHome();
s.rotate(Suteppa::ABSOLUTE, 1024);

 先頭につけたスイッチ(SW)を押すまでマイナスへ回り続けます。tickごとにdigitalRead(SW)で先頭スイッチが押されたかを確認します。押されたらwhileを抜けて回転を中止。その位置をhomeにセット。その後1024絶対ステップで回す。という流れです。キャリブレーションも簡単に実装できますね。キャリブレーションのデモは別記事で詳しく書く予定です。

おまけ

static const int RELATIVE = 0;
static const int ABSOLUTE = 1;
static const int ABSOLUTE_SKIP = 2;

こうなっているので、長くて面倒な場合は数字でも良いです。

ステッピングモーター制御ライブラリを作りたい(その5)「脱調防止できるのか実験!」

その1はこちらです。

 前回のDVDのステッピングモーターで脱調防止実験を行います。実験は現在開発中のライブラリを用いて行いますが、すいません!前回、ライブラリの説明も次回行うと言いましたが、ボリュームがたっぷりになってしまうので、ライブラリの説明自体は今回は省略させてもらいます。が一応貼っておきます。
github.com

回路

前回同様です。

ソース

 実験用ソースは一応貼りますが、ライブラリの解説がないと分かりにくいので、今回はソースの説明はしません。次回ライブラリの解説をするときにこのソースの解説も行う予定です。長いので最後に貼ります。

いざ実験

まず、このお手本をご覧ください。

2000マイクロ秒 通常モード(お手本)

YouTube


 このお手本は、ライブラリによる脱調防止機能をオフにして撮影しています。ステップとステップの時間は2000マイクロ秒です。この時点では脱調防止機能オフでも正確な位置決めが出来ています。これと同じ動きを少し早くしてやってもらいます。

1300マイクロ秒 通常モード

YouTube


 こちらは1300マイクロ秒にしたバージョンですが、途中で脱調していることが分かると思います。お手本と同じ動きをしているつもりなのですが、脱調しているためぐちゃぐちゃになっています。

ここからが本番です

 通常モードでは1300マイクロ秒で脱調してしまいました。ここからは脱調を防止したライブラリを使用したスムーズモードでの実験となります。

1300マイクロ秒 スムーズモード

YouTube


 どうでしょうか。通常モードでは脱調してしまった1300マイクロ秒を難なく突破です。スムーズモードは動画ではわかりにくいですが加減速をしています。最高速度はしっかりと1300マイクロ秒に達しています。

スムーズモードについての詳しい説明は、その2で行っています。S字加速を使用した方式ですので是非ご覧ください。

950マイクロ秒 スムーズモード

YouTube


 どこまでいけるかと思い下げていくと、950が限界のようです。ですが、スムーズモードだとここまで高速に動けることが分かります。

おまけ

 スムーズモードが動画だと分かりにくいので、加減速をより強調した設定にして動かしてみました。この動画だと加減速がはっきりわかると思います。

YouTube


次回

ライブラリの説明とソースコードの説明を行います。

ソース

gist.github.com

その6(最後)はこちらです。

ステッピングモーター制御ライブラリを作りたい(その4)「28BYJ-48とDVDのモーターをArduinoで回す。」

その1はこちらです。

 ライブラリがどうにか形になりました。ライブラリのテスト用に注文した28BYJ-48と、DVDのレーザー移動用ステッピングモーターを使います。ということで、ライブラリの説明より前にステッピングモーターをコントロールする回路の説明から入ります。今回は複雑にしないためにも制作中のライブラリは使わないで行います。
 ここでは細かい説明はしないので114.ステッピングモータを動かすこちらのページが参考になると思うので、ぜひ読んでみてください。

28BYJ-48を回す

 28BYJ-48のモジュールのIN1 IN2 IN3 IN4をそれぞれ9 10 11 12に割り当てました。このモーターは5端子のユニポーラ型なので、モジュールと言ってもただのトランジスタの集合です。ユニポーラは回路が単純なので扱いやすいですね!

ソース

gist.github.com  このソースですが、私はArduinoIDEではなくplatformIOにてC言語で開発しているため、先頭にincludeがありますが不要な場合は除いてください。
 今回は1-2相励磁で回しているので、1-2相励磁で刻むように上に配列を定義しています。回転はstep関数で行っています。stepの引数には方向を示すint dを与えます。1-1です。
 stepごとに挟んでいるdelayMicrosecondsですが、ここでは900にしています。このモーターは900位が限界っぽいです。

動画

www.youtube.com

DVD用ステッピングモーターを回す

 DVD用ステッピングモーターはバイポーラ型なので、28BYJ-48に比べて回路が面倒です。今回ステッピングモーター用のICを持っていなかったので困りました。ただ、Hブリッジが二つあれば良いので探していたら家にありました。TA7291Pです。正転反転できるタイプのモータードライバでPWMで速度も変えられます。が、今回はこれをただのHブリッジとして使います。 f:id:takumus:20160913185640j:plain f:id:takumus:20160913182917p:plain  こんな感じの回路になりました。多分TA7291Pを二つも使ってステッピングモーターを回すという、もったいないことをしたのは僕くらいだと思います!
 回路を裏から見た図です。少し灰色の線は表側を通しているという意味です。また、TA7291Pの向きですが、左上が少し欠けているのでそれが目印です。
 そこそこ適当な回路ですが動作確認は取れました。図の左側が入力、右側が出力です。左側の+1 +2 -ですが、モーターを外部電力で回す場合は+1には外部を入れ、+2にはArduinoを入れます。GNDはどちらも-へつなぎます。入力のA1 A2 B1 B2ですが、ArduinoへはA1 B1 A2 B2の順番で9 10 11 12へ繋ぎました。
 今回のような小さなモーター(大きさで判断するのは良くない)は大したことなさそうだったので、+1 +2を一緒にして両方ともArduinoに繋ぎましたが問題なく動作しました。

ソース

 28BYJ-48と同様ですがこっちのモーターは低速回転なので、delayMicromecondsが900だと完全に脱調しました。最低でも2000が安定するようです。

動画

www.youtube.com

次回

次回は制作中のライブラリを実際に使ってみます。

その5はこちらです。