Cur: 2023-08-21 (Mon) 01:17:20 takaboo ![]() |
|||
---|---|---|---|
Line 1: | Line 1: | ||
+ | TITLE:頒布版PicoSHIELDについて | ||
+ | ここでは専ら音を鳴らす事を紹介。 | ||
+ | **内容物 [#k6744e15] | ||
+ | |item|qty|h | ||
+ | |[[Raspberry Pi Pico>https://www.raspberrypi.com/products/raspberry-pi-pico/]]|1| | ||
+ | |[[BTE110 PicoSHIELD]]|1| | ||
+ | |[[BTE097 DX Busrepeater]]|1| | ||
+ | |[[enclosure with speaker (3D pdf)>https://www.besttechnology.co.jp/download/3D/E208_with_enclosure_3D.pdf]]|1| | ||
+ | |Robot Cable-X4P 100mm|1| | ||
+ | |[[Qwiic cable>https://akizukidenshi.com/catalog/g/gC-15884/]]|1| | ||
+ | |[[pin socket 2x6>https://akizukidenshi.com/catalog/g/gC-16795/]]|1| | ||
+ | 頒布版はPicoはPicoSHIELDにピンソケットを介して装着し、スピーカを内蔵した電気的な絶縁を目的としたエンクロージャーに封入。 | ||
+ | **使う前に[#e89893df] | ||
+ | 音を鳴らすなら市販のオーディオプレーヤーで十分事足りる。少なくともPicoSHIELDのドキュメントを読んだ上で何ができるかを考察すること。 | ||
+ | |||
+ | ***エンクロージャー [#u037ac8c] | ||
+ | 基板の短絡保護のためエンクロージャ(PLA+で生成)を作った上で2個のスピーカを内蔵し、PicoSHIELDのオーディオアンプに接続。基板に直接アクセスする際に分解する際は、ケーブル長が短いので断線させないよう少しずつこじ開ける事。 | ||
+ | #ref(enc.png) | ||
+ | ちなみに少々まとめて出力したため、一部に変形がある。また嵌合力は積層同士の摩擦によるもので、開閉を繰り返したり熱を加えると弱まる。 | ||
+ | |||
+ | ***Raspberry Pi Pico [#m44e078c] | ||
+ | PicoとPicoSHIELDの間はさほど長くない[[ワイヤで接続>BTE110 PicoSHIELD#z88b7800]]してあるので、余程の事が無い限り分離しない事。~ | ||
+ | またPico WはArduino Picoライブラリにおける対応が不十分なところが見受けられるため、込み入った用途の場合は推奨しない。 | ||
+ | |||
+ | ***電源 [#x4012edd] | ||
+ | PicoのUSBコネクタへ供給するUSBバスパワーでも運用できるが、オーディオへのノイズの流入が激しい。PicoSHIELDの[[CN2>BTE110 PicoSHIELD#h21c7c1d]]から安定した電源を給電する事を推奨する。 | ||
+ | |||
+ | ***Qwiic(I2C)とPmod(I2C/SPI/UART/GPIO) [#be4d2c75] | ||
+ | これらはPicoSHIELDを参照の事。 | ||
+ | |||
+ | ***DX Busrepeater [#l94b3e07] | ||
+ | PicoSHIELDはDynamixel XシリーズのRS-485 I/F版を想定しているが、TTL I/F版を使用したい場合は同梱のDX BusrepeaterでI/Fを使って変換する。 | ||
+ | |||
+ | ***プログラムの転送 [#r3f35d75] | ||
+ | 通常はPicoに備わっているBOOTSELボタンで動作モードを切り替えるが、その場合は電源の操作が強いられる。PicoSHIELDでは[[PB1>BTE110 PicoSHIELD#z88b7800]]の操作のみでPicoの動作モードを切り替える事ができる。 | ||
+ | |||
+ | PB1を長押ししてPicoのブートローダをUSB接続のストレージ状態にし、コンパイル済みの*.uf2ファイルをそのストレージにコピーするだけなのだが、Arduino IDEを介すと転送に失敗するケースが散見される。~ | ||
+ | とりあえず転送に失敗するのと何かと面倒なため、こちらではArduino IDEではコンパイルだけを行い(メニューのスケッチ→コンパイル済みバイナリをエクスポート)、転送は個別に行うという手法が確立している。また転送する際はボリュームラベルを頼りにコピーするコマンドをあつらえた(Windows用のみ)。 | ||
+ | #ref(rp2040_cpybyvol.7z) | ||
+ | コンパイル済みバイナリがエクスポートされたフォルダに展開し同梱の cp.cmd を起動すると、同じフォルダにある*.uf2ファイルをPicoのストレージを見つけた上でコピーしてくれる。 | ||
+ | |||
+ | ***シリアル通信 [#m5305d58] | ||
+ | PicoのUSB(Serial)・UART0(Serial1)・UART1(Serial2)を使用して外部とのコミュニケーションを行う。起動時はUSBだが、何かしら受信したポート側に切り替わる。~ | ||
+ | -USB(CDC-ACM)~ | ||
+ | USBはPicoのUSBコネクタを介し、ホストでは仮想シリアルポートとして扱う。またUSBバスパワーがオーディオアンプとRS-485トランシーバに供給される。 | ||
+ | #ref(com_cdcacm.png) | ||
+ | -UART0(Logic)~ | ||
+ | UART0は[[PicoSHIELDのCN1>BTE110 PicoSHIELD#b2f7f3d1]]を介して使用し、3.3Vロジックレベルの信号を扱う。CN1はランドのみなので適宜コネクタ等を装備して使用する事。CN1から外部電源を供給してはならない。 | ||
+ | |pin|function|h | ||
+ | |CN1-2|GP12(TXD0)| | ||
+ | |CN1-3|GP13(RXD0)| | ||
+ | |CN1-5|GND| | ||
+ | #ref(com_uart.png) | ||
+ | -UART1(RS-485)~ | ||
+ | UART1は[[PicoSHIELDのCN2>BTE110 PicoSHIELD#h21c7c1d]]を介して使用し、RS-485 I/Fに準拠した信号を扱う。外部からCN2へ電源を供給する事も可能。 | ||
+ | #ref(com_rs485.png) | ||
+ | |||
+ | ***アンプ [#m00a4690] | ||
+ | 2chのPWMを活性化し、単純に高速でデータを転送しているだけ。PWM周波数が低いとアンプが発熱するという理由だけで可聴領域よりもはるかに高い220.5kHzのキャリア周波数を選んでいる。これより低い周波数でPWMを出力すると、平滑時のリプルにより無音であってもアンプが発熱、場合によってはエンクロージャーが熱により変形する。~ | ||
+ | 後に紹介する数十kHzの音データを出力する際は、わざわざ逓倍して出力する事になる。またキャリア周波数が高いため、実質的な分解能は落ちる。 | ||
+ | |||
+ | ***microSDカードスロット [#ucb0b435] | ||
+ | PicoSHIELDにはmicroSDカードスロットが備わっているが、エンクロージャーに封入すると抜き差しできない。 | ||
+ | #ref(microsd.png) | ||
+ | |||
+ | ***音データの扱い [#n87d8c80] | ||
+ | 様々なフォーマットを扱うのが面倒だったのでここではRAWデータのみを扱うが、データを保存する場所はメモリのサイズに依存する。~ | ||
+ | Picoのフラッシュはコードを含む2Mbyteが上限となる。~ | ||
+ | Picoのフラッシュに入り切らない程の音ネタを使うまでも無いと思うが、どうしてもと言う場合はmicroSDカードに保存して利用する事も可能。 | ||
+ | ---- | ||
+ | 音ネタのフォーマットをRAWファイルに変換するには、[[SoX>https://sox.sourceforge.net/]]を使うと簡単。とりあえずMP3からRAWデータに変換するバッチを含む実行ファイルを置いておく。 | ||
+ | #ref(SoX.7z) | ||
+ | 例えば44.1kHzステレオ符号付き16ビットRAWファイルに変換する場合は、同梱の conv_mp3_to_stereo44kraw.cmd に対して変換したいMP3ファイルをドラッグドロップする(複数も可)とconvertedフォルダにRAWファイルが生成される。 | ||
+ | ---- | ||
+ | 音ネタの編集は音屋なら自前の物で、無い場合は[[Audacity>https://www.audacityteam.org/]]や[[Wavacity>https://wavacity.com/]]で編集すると良いだろう。 | ||
+ | |||
+ | **デモプログラム [#z1d8557f] | ||
+ | そもそもPicoをArduino IDEで使う事が間違いではあるが、いろいろなプラットホームに対応しているのでそれを使用する前提とする。もちろんPicoは単なるマイコンボードなのでプログラムなしに動く事はない。 | ||
+ | |||
+ | 間違いやすいのがArduino IDEにインストールするPico用のライブラリ。必ず[[こちらのリンク>https://github.com/earlephilhower/arduino-pico]]のライブラリを適用する事。~ | ||
+ | |||
+ | いずれのデモのアーカイブファイルのbuildフォルダ配下にコンパイル済みのバイナリと転送用のバッチが含まれているので、とりあえずArduino IDEが無くても動作確認は可能。 | ||
+ | |||
+ | 本来ならUSBカードリーダ化してmicroSDカードを挿抜せずともデータをPCから更新させるし、MP3等のフォーマットにも対応させるのだが、SDカードへのアクセスが致命的に遅いので止めている。MicroPythonを使ったとしても同様の制約を受けるのでイマイチ。 | ||
+ | |||
+ | いずれにしても至極簡単かつ手抜きなツクリなので、適宜改造して活用してもらえればと。 | ||
+ | |||
+ | ***デモ1 [#q246f240] | ||
+ | 本デモにおけるSerialの使い方の紹介。~ | ||
+ | 3つのSerialのうち使用者がどれを選択するか分からないために、とりあえずどれか1つを自動的に選択するようにした。選択の条件は外部から送信がなされたポートかforceselで選択したポート。デフォルトはUSBでハードフロー制御を無効にするためにignoreFlowControl()を呼んでいる。 | ||
+ | #html{{ | ||
+ | <pre class="brush:cpp;"> | ||
+ | #include "SerialMulti.hpp" | ||
+ | // インスタンス化 | ||
+ | CSerialMulti SerialM; | ||
+ | |||
+ | // 115.2kbpsで初期化 | ||
+ | SerialM.begin(115200); | ||
+ | |||
+ | // 書式化文字列送信 | ||
+ | SerialM.printf("uhoho\n"); | ||
+ | |||
+ | // 送信バッファフラッシュ | ||
+ | SerialM.flush(); | ||
+ | |||
+ | // 受信データ数取得 | ||
+ | int n = SerialM.available(); | ||
+ | |||
+ | // 受信データ読み出し | ||
+ | char c = SerialM.read(); | ||
+ | |||
+ | // ポートの強制選択 (0=Serial, 1=Serial1, 2=Serial2) | ||
+ | SerialM.forcesel(2); | ||
+ | </pre> | ||
+ | }} | ||
+ | #ref(demo1.7z) | ||
+ | |||
+ | ***デモ2 [#zdc017fd] | ||
+ | Picoに搭載されたフラッシュ上に配したRAWデータの再生。~ | ||
+ | フラッシュのサイズの都合もあるので、音データのフォーマットは無圧縮11.025kHzモノラル符号付き8ビットRAWデータとするが、再生時に周波数を変換できるので周波数はあまりこだわらない。フォーマットに従った音データを1.raw~9.rawの名前でファイルにし、コンパイル時にそれらのファイルを一緒にリンクして実行ファイルを生成する。~ | ||
+ | #html{{ | ||
+ | <pre class="brush:cpp;"> | ||
+ | #include "RAWAudioPlayer.hpp" | ||
+ | CRAWAudioPlayer RAWAudioPlayer; | ||
+ | |||
+ | // 指定されたファイルをリンク | ||
+ | INCBIN("hoge.raw", fuga); | ||
+ | |||
+ | // リンクしたファイルを音データとして登録 | ||
+ | std::vector<CRAWAudioPlayer::TPCMInfo> PCMInfo{ | ||
+ | { (int8_t *)& fuga, (int)& _size_fuga, -1, 256, 127 }, | ||
+ | }; | ||
+ | // 初期化 | ||
+ | RAWAudioPlayer.begin(& PCMInfo); | ||
+ | |||
+ | // 0番目に登録したファイルをデフォルトの24(ド)の周波数で再生 | ||
+ | RAWAudioPlayer.play(0, 24, 64); | ||
+ | </pre> | ||
+ | }} | ||
+ | 異なる音源を合成して同時再生させる事ができるが、単純に足し算しているだけなので音割れに注意。またArduino IDEはソースをテンポラリにコピーした上でコンパイルするため、今回のような外部ファイルをリンクさせる際のファイル名として相対パスが使えない。 | ||
+ | #ref(demo2.7z) | ||
+ | |||
+ | ***デモ3 [#k84f59bd] | ||
+ | RAWファイルが保存されたmicroSDカードをPicoSHIELDの[[CN4>BTE110 PicoSHIELD#pe487ae7]]に装着し再生。~ | ||
+ | 音データのフォーマットは再生能力めいっぱいの無圧縮44.1kHzステレオ符号付き16ビットRAWデータ固定としている。そのフォーマットに従った音データを1.raw~9.rawの名前でファイルにし、予めmicroSDカードのルートに保存されている前提。~ | ||
+ | #html{{ | ||
+ | <pre class="brush:cpp;"> | ||
+ | #include "SDAudioPlayer.hpp" | ||
+ | CSDAudioPlayer SDAudioPlayer; | ||
+ | |||
+ | // 初期化 | ||
+ | SDAudioPlayer.begin(); | ||
+ | |||
+ | // 指定されたファイルを再生 | ||
+ | SDAudioPlayer.play("hoge.raw"); | ||
+ | </pre> | ||
+ | }} | ||
+ | microSDカードはFAT32フォーマット(32GB以下)限定、使い倒したものは推奨せず、USBバスパワーではmicroSDカードへのアクセス時にアンプへ過度なノイズが加わるので外部電源推奨。 | ||
+ | #ref(demo3.7z) | ||
+ | |||
+ | ***デモ4 [#c2d6e620] | ||
+ | 音つながりでPicoを昔ながらのサウンドチップ化しピコピコ音を鳴らす。~ | ||
+ | 元ネタは[[DXMIOのサンプル>BTE098 DXMIO with IMU#la4263e0]]で、PCMデータと合わせて簡易的なMMLを用いて楽曲を再生可。もともとシングルソースだったものを無理矢理分割したので少々強引。 | ||
+ | #html{{ | ||
+ | <pre class="brush:cpp;"> | ||
+ | #include "RAWAudioPlayer.hpp" | ||
+ | #include "Synth.hpp" | ||
+ | #include "TinyMusicSq.hpp" | ||
+ | |||
+ | // インスタンス化 | ||
+ | CRAWAudioPlayer RAWAudioPlayer; | ||
+ | CTinyMusicSq MSq[_MAX_MUSICSQ]; | ||
+ | |||
+ | // 初期化 | ||
+ | RAWAudioPlayer.set_synthfunc(mixnote); | ||
+ | |||
+ | // 波形設定 | ||
+ | SetWaveForm(0, (const int8_t[]){ 0, -8, -16, -24, -32, -40, -48, -56, -64, -72, -80, -88, -96, -104, -112, -120, -128, 120, 112, 104, 96, 88, 80, 72, 64, 56, 48, 40, 32, 24, 16, -8 }, 32); | ||
+ | // 再生 | ||
+ | ConvertAndStartMusic(1, "t5@0o4l4v58$,50,100, [ cdefgab<cdefgab ]"); | ||
+ | </pre> | ||
+ | }} | ||
+ | 必要以上に無駄な事をしているのとサボり気味なので、鳴らなかったらご愛敬。 | ||
+ | |||
+ | #ref(demo4.7z) | ||
+ | |||
+ | ***デモ5 [#l7236c18] | ||
+ | ロボット等の姿勢を検出するためにはIMUは必須だろうという事で、Qwiicに対応した[[adafruitのモジュール>https://www.adafruit.com/product/4754]]と通信するプログラム。~ | ||
+ | #ref(4754.png) | ||
+ | bno085monクラスは[[CEVA提供のライブラリ>https://github.com/ceva-dsp/sh2]]を使ってBNO085と通信し、バックグラウンドでデータを取得し続けるためにFreeRTOSでタスクを生成している。~ | ||
+ | デモは取得を指示したデータの殆どをターミナルに吐き出す。また加速度・ジャイロ・地磁気のダイナミックキャリブレーションを有効にしてあるので、[[BNO08X Sensor Calibration Procedure>https://www.ceva-dsp.com/wp-content/uploads/2019/09/BNO080-BNO085-Tare-Function-Usage-Guide.pdf]]を行う事でキャリブレーションが可能。 | ||
+ | |||
+ | #ref(demo5.7z) | ||
+ | |||
+ | ***デモ6 [#f7228729] | ||
+ | せっかくなのでDynamixelと通信するプログラムを作成。~ | ||
+ | デモに同梱したDXLIBははDynamixelのモデルを意識すること無くかつ物理値での指令に対応する追加APIが使用でき、それを利用して俗に言うモーションを簡単に再生するDXLMotionクラスを作った。 | ||
+ | #html{{ | ||
+ | <pre class="brush:cpp;"> | ||
+ | #include "DXLMotion.hpp" | ||
+ | // インスタンス化 | ||
+ | DXLMotion motion; | ||
+ | |||
+ | // 対象IDの一覧 | ||
+ | const std::vector<uint8_t> my_id_list {1,2,3}; | ||
+ | |||
+ | // サーボの初期化 | ||
+ | const DXLMotion::TServoInfo servo_info = { | ||
+ | {1, 4, 0x4}, | ||
+ | {2, 4, 0x4}, | ||
+ | {3, 4, 0x4} | ||
+ | }; | ||
+ | motion.init_servo(& servo_info); | ||
+ | |||
+ | // モーションデータの再生 | ||
+ | const DXLMotion::TMotion motion1 = { | ||
+ | my_id_list, | ||
+ | { | ||
+ | { { 0, 0, 0 }, 1.0 }, | ||
+ | { { 45, 90, 30 }, 1.5 }, | ||
+ | { { -30, 30, 0 }, 0.5 }, | ||
+ | { { 123,-123, 270 }, 2.2 } | ||
+ | } | ||
+ | }; | ||
+ | motion.play(& motion1); | ||
+ | </pre> | ||
+ | }} | ||
+ | デモは1MbpsでID=1~8のDynamixel X/Pシリーズを対象、モーションを再生する前に'i'を送信して接続されたDynamixelの検索と初期化が必須、Dynamixelは1台でもOK、モーションのフレーム切り替えにFreeRTOSを使用。 | ||
+ | #ref(BTE110 PicoSHIELD/E208_BASIC_CONNECTION.png,100%) | ||
+ | #ref(demo6.7z) | ||
+ | |||
+ | ***デモ7 [#rfcfa11c] | ||
+ | Pico W限定だが、ソケットとRS-485間をブリッジさせるプログラムで、PCと装置をUSBシリアル変換器等で接続している部分を無線化する。 | ||
+ | #ref(wifi_uart_bridge.png,45%) | ||
+ | 基本的に単純なソケットサーバで、ポート番号23で待ち受け、ソケットで受信したデータをRS-485に送信、RS-485から受信したデータをソケットに送信するだけ。~ | ||
+ | APMODEのマクロでPico WそのものをWiFiのアクセスポイントにするか、Pico Wを既存のWiFiルータに接続するかを選択できる。詳細はソースにて。~ | ||
+ | COMポートを介して通信する既存のWindowsのアプリケーションを無線化する場合は、任意のIPアドレスとポート番号を割り当ててCOMポートを追加できる[[USR-VCOM>https://www.pusr.com/support/downloads/usr-vcom-setup-software.html]]が使える。その場合はボーレート等の変更にも対応。~ | ||
+ | なおネットワーク環境やPCの負荷に大きく依存するため、既存のアプリの設定(特に受信タイムアウト)では正常に通信できない事も起こり得る。それを以てしても無線化する恩恵が大きい場合にのみ、本構成を検討する事。 | ||
+ | |||
+ | #ref(demo7.7z) |