【1】Raspberry pi の、GPIOをTypescriptから操作
別プロジェクトの試験をかねて、以下の条件でラジコンを作りましたので
UZAYAの宣伝を兼ねて、記事にまとめます。
条件
- ラジコン本体は、RasipberryPiで制御
- DualSenseをコントローラーに使用する
- ブラウザにDualSenseを接続し、RasipberryPiに操作信号を送る
- DualSenseのアナログトリガーで速度調整が可能
- ラジコン本体に搭載したカメラの映像を、ブラウザで確認可能
- スマホでカメラ映像を見た場合、VRで見れる
以上の条件を満たす内容で作っていきます。
1度に全部書くと長すぎるので、何回かに分けて続きます。
こんな感じの物を作成する議事録です。
□ 走行デモ
目次
- 【1】Raspberry pi の、GPIOをTypescriptから操作
- 【2】DCモーターをPWMで速度制御
- 【3】サーボモーターを制御
- 【4】DualSenseをブラウザに接続
- 【5】DualSenseの情報をRaspberryPiに飛ばす
- 【6】DualSenseのチャタリング?問題対応
- 【7-1】RaspberryPiから低遅延で映像を飛ばす
- 【7-2】RaspberryPiから低遅延で映像を飛ばす
- 【8】ThreeJSでVRもどきを作成
- 【9-1】iPhoneの加速度から頭の向きをVRに反映
- 【9-2】スマホVRゴーグル向けデザインに変える
- 【10】ラジコン本体の製作
- 【11】パワーアップとバッテリー問題の解決
JavascriptでRaspberryPiのGPIOを操作
RaspberryPiにインストールするOSは
Raspberry Pi OS 32-Bitを使用しています。
nodejsインストール
gpioをTypescriptから操作するにあたり
完全に非推奨事案ですが、nodejs16が必要になります。
自力で今回使用するpigpioのラッパーを書く
という選択肢もありますが
正直面倒なのでとりあえずこのまま行きます。
下記セットアップコマンドで
色々警告が出ますが、とりあえずnodejs16が入ります。
$ curl -s https://deb.nodesource.com/setup_16.x | sudo bash
16系統が入っていることを確認
$ node --version
v16.20.2
npmコマンドも合わせてバージョンが古いです。
$ npm --version
8.19.4
pigpioインストール
gpioを操作する定番ライブラリ、pigioを追加
sudo apt install pigpio
制作時点で下記のバージョンが入りました。
$ pigpiod -v
79
zxインストール
簡単なテストシェル等もTypescriptで作成してしまうので
Google性Javascriptシェルのzxを使用します。
npm install -g zx
制作時点のバージョンは下記になります。
$ zx --version
8.3.2
pigpioを操作するサービス作成
「使い回す処理は別ファイルで記述したい」派に属する人間なので
pigpioを呼び出す部分を単独でサービスとして分けます。
- npmライブラリ、pigpioの呼び出し
- 使用するポート番号の追加
- ポート番号の削除
- 初期化処理
- デジタル書き込み
- PWM書き込み
- Servo書き込み
以上の機能を持つサービスとして作成できれば
何でもいいと思います。
javascriptで書かないと、最終的に動かない問題がありますので
Typescriptで!という予定ですが
原則Javascriptで進めます。
下記は今回使用したコードです。
「gpio.service.js」というファイル名で保存します。
const Gpio = require('pigpio').Gpio;
let GpioPorts = {}
const Ports = [
{ port: 0, mode: "out" }
]
// ポートの追加
const addPort = (port) => {
if (Ports[0].port === 0) {
Ports.pop()
}
if (Ports.find(p => p.port === port.port)) {
console.log(`Port ${port.port} already exi sts`)
} else{
Ports.push(port)
}
}
// ポートの削除
const removePort = (port) => {
const index = Ports.findIndex(p => p.port === port)
if (index !== -1) {
Ports.splice(index, 1)
}
}
// イニシャル処理
const initGpio = () => {
console.log('INITIAL PORTS', Ports)
if (Object.keys(GpioPorts).length > 0) {
GpioPorts = {}
}
try
{
for (const port of Ports) {
console.log('SETUP ',port)
const gpio = new Gpio(port.port, {mode: Gpio.OUTPUT})
GpioPorts[port['port']] = gpio
}
} catch (error) {
console.log('ERROR', error)
}
}
/**
* デジタル出力
* @param port number
* @param value 1 or 0
*/
const write = (
port,
value
) => {
try {
if (GpioPorts[String(port)]) {
GpioPorts[String(port)].digitalWrite(value)
}
// B1.digitalWrite(1)
return {
status: true,
message: `Port ${port} value set to ${value}`
}
} catch (error) {
return {
status: false,
message: error.message
}
}
}
/**
* PWMのソフトウェアエミュレーションを出力
* @param port number
* @param port 1~250
*/
const pwmWrite = (
port,
value
) => {
try {
if (GpioPorts[String(port)]) {
GpioPorts[String(port)].pwmWrite(value)
}
return {
status: true,
message: `Port ${port} value set to ${value}`
}
} catch (error) {
return {
status: false,
message: error.message
}
}
}
/**
* サーボモーター用出力
* @param port number
* @param value 0 ~ 1500
*/
const searvoWrite = (
port,
value
) => {
try {
if (GpioPorts[String(port)]) {
GpioPorts[String(port)].servoWrite(value)
}
return {
status: true,
message: `Port ${port} value set to ${value}`
}
} catch (error) {
return {
status: false,
message: error.message
}
}
}
module.exports = {
addPort,
removePort,
initGpio,
write,
pwmWrite,
searvoWrite
}
zxでLチカ
GPIOを叩くサービスを作ったので
実際に叩きます。
GPIOの16番ポートを使用し
まずは、定番のLチカを行います。
LEDの足の長い方を16番と
短い方をGNDと繋ぐように結線
下記の試験用コードを「gpio_led_test.js」などで保存。
const gpio = require('.gpio.service')
gpio.addPort({port: 16, mode: 'out'})
await gpio.initGpio()
let push = 1
while (true) {
console.log(gpio.write(16, push))
push = (push === 1) ? 0 : 1
await new Promise((resolve) => setTimeout(resolve, 1000))
}
Lチカ試験
ZXで保存したjsファイルを実行
zx ./gpio_led_test.js
1秒毎にLEDが点いたり消えたりするはず、です。
実際の点灯状態の映像です。
これで、JavascriptからGPIOを操作する下準備が出来ましたので
次回はDCモーターを操作し、速度調整まで行います。
UZAYA
Uzayaでは、多分仕事を求めています。
何かの役に立ちそうでしたら、是非お知らせを。