Raspberry Piのセットアップ
はじめに
今回は完全に趣味のためです.最近はTRPGにはまってて,「どどんとふ」っていうオンセツールを使ったりするんですけど,自分で用意したサーバーに導入してみたいな~って思ってたんですよ.
そしたら,ラズパイでもどどんとふを稼働させることができるらしいので,頑張って導入してみたいと思います.
OSをインストールするまで
Raspberry Piと周辺機器の準備
Raspberry Pi3 Model Bでは,仕様として無線LAN,Bluetooth4.1を搭載しています.そのため,Wi-Fiや周辺機器への接続は無線で容易にやり取りできます.
OSイメージをダウンロード
Raspberry PiのOSイメージをダウンロードします.
Raspberry PiのOSは非公式のものも数えると,現時点(2019/03)で13種類のOSが公開されています.今回は公式が用意している基本OSであるRaspbianをインストールしたいと思います.
www.raspberrypi.org
ダウンロードページにアクセスして,イメージをダウンロードしました.
SDカードにOSデータを配置
SDカードのフォーマット要領やRaspberry Pi起動ディスクの作成要領については,非常にわかりやすく記事にされている方々がいらっしゃるので,そちらの記事を参照してください.
Raspberry Pi 3(RASPBIAN JESSIE)OSインストールから初期設定【セットアップ前編 】 - 環境構築メモ
Raspberry Pi SDカードに関するノウハウ一覧 | アラコキからの Raspberry Pi 電子工作
OSの起動と初期設定
SDカードをRaspberry Piに差し込みます.microUSBケーブルで電源を供給すると,そのまま起動します.初回起動時には初期設定のウィザードが出てくるので,指示に従って設定を行います.
まず,【Set Country】で言語設定をします.
Country: | Japan |
Language: | Japanese |
Timezone: | Tokyo |
次に,【Change Password】パスワードの設定をします.
Enter new password: | xxxxxx |
Confirm new password: | xxxxxx |
また,必要があれば【Select WiFi Network】で使用するWi-Fiの設定もします.
その後,【Check For Updates】でNextを選択します.“sudo apt-get update”や“sudo apt-get upgrade”をしていたようなことを,こちらでアップデートできるようです.
セットアップの詳細ついては,以下の記事を見るとわかりやすく解説されていました.
最近のRaspberry Piイメージ(Raspbian)をインストールするメモ – 1ft-seabass.jp.MEMO
piユーザ名の変更
各アカウントにパスワードを設定
LXTerminalを開き,「root」「pi」にそれぞれパスワードを設定する.
特に,rootは権限が非常に強いため,複雑かつ文字数の長いパスワードを設定すること.
自動ログインを解除する
[設定]→[Raspberry Piの設定]を選択して,[システム]タブを開く.そのうち,[自動ログイン]の「現在のユーザとしてログインする」のチェックを外します.
そうすることで,再起動時にpi以外のアカウントを選択できるようになります.
rootでログインする
その他を選択して,ユーザ名に「root」を選択して,自身が設定したパスワードを入力します.
また,rootでのログイン時には,LXTerminalでの命令にsudoを使用する必要はありません.
ユーザ名を変更する
以下のコマンドでpiユーザ名を変更します(例:newPi)
usermod -l newPi pi
homeフォルダ直下にあるpiユーザのディレクトリを自身が付けた名前(ここではnewPi)に移します.
usermod -d /home/newPi -m newPi groupmod -n newPi pi
自動ログインユーザの変更
自動ログイン関連のファイルを,nanoエディタを用いて直接変更します.
編集するのは,/etc/systemd/system/autologin@.serviceというファイルです.
nano /etc/systemd/system/autologin@.service
変更が終わったら,ラズパイを再起動します.
reboot
piユーザ名の変更については,以下の記事が参考になりました.RaspberryPiでpiユーザー名をSSHなしで変更する - Qiita
おわりに
ラズパイ用に毎回ディスプレイを繋いだりするのが面倒だったりするので,メイン機であるWindows PCから操作できるようにしたい...
次回は,その辺りを含めたインストールすべきパッケージについて纏めます.
【Direct2D】メモリ上からBitmapへとコピーする
はじめに
カメラでキャプチャしたイメージに何らかの画像処理を施して,その結果をリアルタイムでウィンドウに描画するプログラムを作りたいと思います.
基本的に扱うのは2D画像のみなので,Direct3Dと相互運用性のある高速かつ高精細な2Dグラフィックスを提供するAPIとしてDirect2Dを使用します.
大まかな流れとしては,
1. ID2D1RenderTarget::CreateBitmap() メソッドでID2D1Bitmapを作成する.
2. ID2D1HwndRenderTarget::BeginDraw() メソッドでレンダーターゲットの描画操作を開始.
3. カメラでキャプチャしたイメージ(もしくは画像処理を施したイメージ)を作成したID2D1Bitmapに反映させる.
4. ID2D1HwndRenderTarget::EndDraw() メソッドでレンダーターゲットの描画操作を終了.
5. 以後,2~4までを繰り返す.
となります.
しかしながら,毎フレーム更新の度にID2D1RenderTarget::CreateBitmapを行い,画像データを流し込むのは(要求するフレームレートや解像度にもよるが)大幅なパフォーマンスの低下を招きます.基本的にリアルタイムグラフィックスの分野においては,フレームごとのリソース再確保は避けるべきとのことらしいです.
そのため,事前に作成しておいたID2D1Bitmapを再利用し,同一の幅と高さを持つ画像データをCopyFromMemory メソッドを用いてメモリ上でやり取りを行いたいと思います.
CopyFromMemoryの使い方
Microsoft社のドキュメントを見てみると,以下のような構文となっています.
ID2D1Bitmap::CopyFromMemory メソッド (Windows)
第2パラメータでコピーするデータを指定,第3パラメータでコピーするデータのストライド(ピッチ)を指定します.
virtual HRESULT CopyFromMemory( [in, optional] const D2D1_RECT_U *dstRect, [in] const void *srcData, UINT32 pitch ) = 0;
dstRectはnullptrを指定,pitchについては”ピクセル幅×ピクセル当たりのバイト数+メモリパディング”という数式を使用して計算できます.
しかし,肝心のsrcDataについてはどのようなデータを用意すればいいのか,ドキュメントの記述では理解できませんでしたが,同じくMicrosoft社のフォーラムに同様の疑問と対処が記載されていました.
How to use ID2D1Bitmap::CopyFromMemory
これによると,事前にID2D1BitmapをID2D1RenderTarget::CreateBitmap() メソッドで作成する際に,指定するパラメータの一つにpixelFormatがあります.
DXGI_FORMAT_B8G8R8A8_UNORMやDXGI_FORMAT_R8G8B8A8_UNORMのように,DXGI_FORMATでピクセル形式を指定します.srcDataの画像データも,この形式に準じるようです.
m_pRenderTarget->CreateBitmap( D2D1::SizeU(width, height), D2D1::BitmapProperties(D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE)), &pBitmap);
サンプルコードのようにDXGI_FORMAT_B8G8R8A8_UNORMで指定した場合,データ配列は32bitの符号なし整数の配列となります.青色成分が最初の8bit,緑色成分が次の8bit,赤色成分がその次の8bit,アルファが最後の8bitです.
OpenCVのcv::Mat型画像データをメモリ上に配置
というわけで,画像処理ライブラリのOpenCVを扱うことが多いので,cv::Mat型からID2D1Bitmapへのコピーを行っていきます.
サンプルコードについては適宜置き換えて下さい.
cv::Mat image; // カメラからキャプチャしたイメージを格納 byte* memory = new byte[image.rows*image.cols*4]; // CopyFromMemory() メソッドの第2パラメータで指定 ・・・・・ for (int row = 0; row < image.rows; row++) { cv::Vec3b *src = image.ptr<cv::Vec3b>(row); for (int col = 0; col < image.cols; col++) { cv::Vec3b bgr = src[col]; int pointBGR = col * 4 + row * image.rows * 4; memory[pointBGR + 0] = bgr[0]; memory[pointBGR + 1] = bgr[1]; memory[pointBGR + 2] = bgr[2]; } } ・・・・・ /* メモリ上のピクセルデータをBitmapにコピー */ pBitmap->CopyFromMemory(nullptr, memory, image.rows*image.cols*4); /* Bitmapの描画 */ m_pRenderTarget->DrawBitmap(pBitmap, //the bitmap to draw [a portion of], D2D1::RectF(0.0f, 0.0f, image.rows, image.cols), //destination rectangle, 1.0f, //alpha blending multiplier, D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR, //interpolation mode, D2D1::RectF(0.0f, 0.0f, image.rows, image.cols)); //source rectangle
【Direct2D】規定値でパラメータを初期化したら垂直同期に合わせられて困った話
はじめに
OpenCVで画像処理をした結果をDirect2Dで描画しようとプログラムを作ってみたら予想以上にフレームレートが落ちていたので,それについて記事にしてみました.
実装と計測
HWNDを対象とするレンダーターゲットであるID2D1HwndRenderTargetインターフェースに関しては,以下の通りに生成しました.
D2D1_SIZE_U PixelSize = { rect.Width(), rect.Height() }; D2D1_RENDER_TARGET_PROPERTIES RenderTargetProperties = D2D1::RenderTargetProperties(); D2D1_HWND_RENDER_TARGET_PROPERTIES HwndRenderTargetProperties = D2D1::HwndRenderTargetProperties(m_hWindow, PixelSize); HRESULT hr= m_pD2d1Factory->CreateHwndRenderTarget( RenderTargetProperties, HwndRenderTargetProperties, &m_pRenderTarget);
また,今回は処理が無事に実行されることを確認するだけだったので,ウィンドウの背景をクリアするのみとなっています.
/* 開始 */ m_pRenderTarget->BeginDraw(); /* 背景のクリア */ m_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::Blue)); /* 終了 */ m_pRenderTarget->EndDraw();
処理自体は非常にシンプルであり,レンダリングの開始・背景のクリア・終了しかしていません.
しかし,このコードで処理を実行した結果,約60fpsしか出ませんでした...
フレームレートが重くなった原因
ID2D1HwndRenderTarget インターフェイスのインスタンスを生成する上で,CreateHwndRenderTarget() 関数を使っていました.
このメソッドの第1・第2パラメータには,それぞれ適切に初期化されたD2D1_RENDER_TARGET_PROPERTIES 構造体,D2D1_HWND_RENDER_TARGET_PROPERTIES 構造体が必要となります.
しかし,先のプログラムでは初期化を簡単にするため,以下の関数を使用していました.
RenderTargetProperties( D2D1_RENDER_TARGET_TYPE type = D2D1_RENDER_TARGET_TYPE_DEFAULT, _In_ CONST D2D1_PIXEL_FORMAT &pixelFormat = D2D1::PixelFormat(), FLOAT dpiX = 0.0, FLOAT dpiY = 0.0, D2D1_RENDER_TARGET_USAGE usage = D2D1_RENDER_TARGET_USAGE_NONE, D2D1_FEATURE_LEVEL minLevel = D2D1_FEATURE_LEVEL_DEFAULT )
HwndRenderTargetProperties( _In_ HWND hwnd, _In_ D2D1_SIZE_U pixelSize = D2D1::Size(static_cast<UINT32>(0), static_cast<UINT32>(0)), _In_ D2D1_PRESENT_OPTIONS presentOptions = D2D1_PRESENT_OPTIONS_NONE )
このうち,HwndRenderTargetProperties() 関数の第3パラメータに指定するD2D1_PRESENT_OPTIONSがフレームレートを下げていた原因でした.このパラメータは規定値だと,レンダリングをディスプレイのリフレッシュレートに合わせる(垂直同期)ようです.
...うん,綺麗に60fpsなんて数字になったのでなんかおかしいとは思ったんですけど,パラメータの指定をさぼった自分のミスでしたね(-_-;)
このパラメータをD2D1_PRESENT_OPTIONS_IMMEDIATELY メンバに設定すれば垂直同期をしなくなるようなので,処理の実行速度なんかを計測したい場合はこのパラメータを設定するといいでしょう.
Unityで始めるOculus GOアプリ開発環境の構築手順(Windows)
はじめに
本ページは,筆者がOculus GOの開発環境を整える際に調べたりしたメモとなっています.
開発環境
- Unity 2018.1.6f1
- Oculus GO 32 bit
- WIndows 10 10.0.17134
Oculus GOのセットアップ
developer登録
まずは,Oculus GOのdeveloper登録を行います.
以下のリンクから新しい団体を任意の名称で登録を行ってください.
Oculus開発者ダッシュボード
Oculus GOを開発者モードにする
既にOculus GOアプリを購入したりで遊んだ方は,自身のモバイル端末にOculus GOアプリが入っていると思います.そのアプリから,以下のフローで開発者モードをONに切り替えます.
設定 > Oculus GO端末情報メニュー > その他の設定 > 開発者モード > ON
これで,Oculus GO側の設定はひとまずは終了です.
Unityのセットアップ
次に,Unity側のセットアップをしていきます.
Unityで3Dプロジェクトを作成
まずは,Unityで3Dのプロジェクトを新規に作成します.プロジェクト名や保存先はなんでもいいです.
File > Build Settingsを開きます.
PlatformでAndroidを選択し,Switch Platformボタンを押して確定させます.
この時,Consoleビューにエラーが出ていないかを確認します.
Oculus GOのOSはAndroid (Version 7.1.2)ベースで動作しているため,Androdアプリ開発と同様にJDK (Java Development Kit)とAndroid SDKのインストールが必要となります.そのため,JDKやSDKのパスが設定されていない,あるいはインストールがされていない場合は,以下のようなエラーが表示されます.
詳しくは,こちらを参照してエラーハンドリングしてください.
Unity - Manual: Android environment setup
Oculus Go用のAndroid開発環境 (JDK/Android SDK)のパス設定
Unity側で,
Edit > Preferences.. > External Tools > Android
にあるSDKとJDKのパスを設定します.とはいえ,インストール終了後にUnityを再起動すると,それらのパスが自動で設定されるようです.
XR Settings
次は,Oculus GO用のVRアプリ開発が行えるように設定をします.
Edit > Project Settings > Player > XR Settings
にあるVirtual Reality Supportedにチェックを入れ,Virtual Reality SDKsよりOculusを選択します.
デフォルトのままBuildをするとおそらく,以下のエラーが出ると思います.
Oculus Requires a Minimum API Level of 19. You have selected 16
API LebelはAndroidのバージョンごとに提供されているAPIを識別するためのものとのことでした.
https://developer.android.com/guide/topics/manifest/uses-sdk-element?hl=ja
先にも述べたように,Oculus GOのOSはAndroid (Version 7.1.2)ベースで動作しています.そのため,エラーによって指示されたAPI Lebelである19~25であれば,問題なくBuildに成功すると思います(因みに,筆者はAPI Lebelを19, 25のどちらにしてもBuildに成功しました).
Bundle Identifierの設定
同じく,"Other Setting"内にあるBundle Identifierにはデフォルトで,
com.Company.ProductName
と記述されていると思います.このままでは,Buildの際にエラーが出てしまうので,任意の独自ドメインに書き換えてください.
(アプリをBuildするだけならば,デフォルト値を変更するだけでエラーを回避することができますが,作成したアプリを公開などをする際には注意が必要です.基本的に,Bundle Identifierは(iOSではiPhoneBundleIdentifier)は独自のものである必要があるためです)
Build and Runの実行
最後に,UnityでBuild and Runを実行して,Oculus GOを装着すると,作成したアプリケーションが無事に動作していると思います.
おわりに
以上で,ひとまずはOculus GOの開発環境を構築することができました.
個人的には,床?の縁のジャギーが結構目立つと感じました.この辺りはVR空間の作り方次第なのでしょうか...?
次回は,Oculus GOのコントローラなどを試してみたいと思います.
参考
本稿を作成するにあたって参考にさせていただいたブログ等
UnityではじめるOculus Go VRアプリ開発 (Mac OS)
UnityでOculus Goの開発環境をセットアップしてみた - Yoshidayo diary