2018年01月15日

Raspberry PiのGPIO操作(3)NeoPixelを光らせる

rpi-8x8-neopixel.jpg

以前aliexpressで購入した8×8のNeoPixelボードをRaspberry Pi Zero Wにつないでみました。
(おそらくこれと同じものだと思います。価格は1/5くらいでしたが・・・)

ソフトウェアは、こちらのツールを使いました。

jgarff/rpi_ws281x: Userspace Raspberry Pi PWM library for WS281X LEDs

解説がこちらにあります。

Overview | NeoPixels on Raspberry Pi | Adafruit Learning System

NeoPixelは以前も書いたように1ビットの信号線で色信号を送ります。
この信号はかなり高速で、Linuxの上でソフトウェアでGPIOをオン・オフしていては間に合いません。
そのため、上記のソフトウェアではRaspberry Piのハードウェア機能のうち、シリアル通信を高速に行えるSPI、PWM、PCMのいずれかを使用して信号を送るようになっています。

今回はSPI(GPIO10/SPI0_MOSI)に接続してみました。電源は3.3Vに接続します。5Vだと信号がうまく送れないようでした。

まず、
sudo raspi-config
で「5 Interfacing Options」を選択し、SPIをenabledにしておきます。
また、ソフトウェアのビルドにsconsというツールが必要なので、これも
sudo api-get install scons
でインストールしておきます。
sconsは初めて使いましたが、Software Constructerの略でmakeの代わりになるようです。

git clone https://github.com/jgarff/rpi_ws281x
でソフトウェアをダウンロードし、
scons
でビルドできます。
testというコマンドが作成されますので、
sudo ./test -g 10 -c
で起動してみます。
これでLEDが点灯すればOKです。
posted by boochow at 23:56| Comment(0) | Raspberry Pi | このブログの読者になる | 更新情報をチェックする

2018年01月14日

Raspberry PiのGPIO操作(2)サーボモータを動かす

raspbian-sg90.jpg

Arduinoでもおなじみのサーボモータ「SG-90」の制御をRaspberry Piでも試してみました。
SG-90は5V動作ですが、制御信号は3.3Vでもなんとか動作するようです。
ただし、Raspberry Piのピンヘッダの5VはUSBの5Vを分配しているだけなので、USBの電源出力が弱いとモータの動作に影響が出ます。

サーボモータの制御はPWMで行いますが、そのためのパッケージは「WiringPi」がメジャーなようです。
Jessie Liteにはデフォルトではインストールされていませんでしたが、
sudo apt-get install wiringpi
でインストールできます。

このパッケージには「gpio」というコマンドが含まれており、このコマンドでPWMの制御も行えます。

まず、GPIOピンをPWMモードにします。使えるピンは、前回の表を参照するとGPIO12、13、18、19となっています。

しかし、WiringPiのマニュアルによると、PWMが使えるのは18だけで、かつアナログオーディオ出力を使っていないこと、という条件があります。
GPIO12、13、19が使えないのは、初代Raspberry Piではピンヘッダが26本で、その中にはGPIO12、13、19が含まれていなかったからだと思われます。
RaspberryPi Zero/Zero Wではアナログオーディオ出力はありませんが、他のRaspberry Piのアナログ音声の出力はPWMで行っているようです。(音質は低そうですね。)

もう一つ注意しなければならないのは、WiringPiでのピン番号がGPIOのピン番号とは異なる点です。
いつもの以下の図を見てください。

GPIO18の前のカッコ書きで、「GPIO_GEN_1」とあります。この「1」がWiringPiでのピン番号になります。
なお「-g」オプションをつければ、WiringPiではなくGPIOのピン番号を使用することができます。

GPIO18を使う場合のSG90との結線は下図のようになります。
rpi-sg90.png


gpioコマンドを以下のように使うと、サーボを動かすことができます。

この例は「Software | Adafruit's Raspberry Pi Lesson 8. Using a Servo Motor | Adafruit Learning System」から拝借しました。

GPIO12, 13, 19も同様にPWM制御できますが、WiringPiのピン番号は定義されていませんので、-gオプションを使って指定する必要があります。

また、gpio modeコマンドでPWMの設定をピンに割り当てるとPWMの設定がリセットされるようなので、都度
gpio pwmr 2000
gpio pwmc 192
gpio pwm-ms
を行う必要があります。


これらのパラメータの意味は以下の通りです。

まず、PWMにはbalancedモードとMark:Spaceモードがあります。

・balancedモード
指定されたデューティ比を、できるだけ高い周波数で再現する。デューティ比50%のとき、最も高い周波数が得られる。デューティ比が0%や100%に近づくと周波数が下がる。

・Mark:Spaceモード
指定された周波数で、1周期内の1(Mark)と0(Space)の比を指定されたデューティ比で再現する。どのようなデューティ比でも周波数は変わらない。

以下のスライドに、両者の違いが視覚的に表現されています。

デジタルアンプのように、アナログ値でPWM変調した信号をローパスフィルタを通してアナログ値に戻す前提ならば、Balancedモードのほうが波形が歪まないと思われます。
しかし、今回のサーボモータは信号周期が20ms(50Hz)と決まっていますのでMark:Spaceモードを使う必要があります。
sg90.png

PWMの周波数は、以下の式で決まります。
19.2MHz / (pwm range * pwm clock divider)

pwm rangeとpwm clock dividerはそれぞれgpio pwmrおよびgpio pwmcで指定されています。
19,200,000 / (2,000 * 192) = 50 (Hz)

となります。

デューティ比は、0〜pwm rangeの範囲で指定します。0のとき0%、pwm rangeのとき100%です。
今回の設定ではpwm rangeが2000ですので、1000を指定したときデューティ比50%(H, Lの長さがそれぞれ10msec)となります。

SG90の仕様では、0.5ms〜2.4msの範囲で指定するようになっていますので、

-90度:0.5ms/20ms = 0.025; 0.025 * 2000 = 50
0度:1.45ms/20ms = 0.0725; 0.0725 * 2000 = 145
90度:2.4ms/20ms = 0.12; 0.12 * 2000 = 240

と指定すれば良いはずですが、私のSG90は50を指定すると「ジー」と振動音が出てしまいました。
一般的には、サーボでは1.5msのとき0度となる製品が多いようですので、

-90度:60
0度:150
90度:250

としておくのが良さそうです。
90度のとき240なら、1増やせば1度動くという感じになって覚えやすいのですが、実際には240だと90度までは回りきらず、250でちょうど回りきる感じでした。
posted by boochow at 19:41| Comment(0) | Raspberry Pi | このブログの読者になる | 更新情報をチェックする

2018年01月13日

Raspberry PiのGPIO操作(1)Lチカ、OLED表示

せっかく久しぶりにRaspbianをインストールしたので、これまでやっていなかった、Raspbianからのデバイス制御を試してみました。

RaspbianはJessie-Liteをインストールし、raspi-configでシリアルポートを有効化しました。
これでシリアルポートからログインできるようになり、キーボードやディスプレイを接続する必要が無くなります。
Pi Zero Wなら、ネットワークとsshを有効にしておけばネットワーク経由でログインできますので、シリアルケーブルも不要になります。

これでRPi周辺がすっきりしましたので、GPIOでのデバイス接続を試してみました。

まず、Raspberry Pi Zero/Zero WのGPIOですが、BCM2835のマニュアルP102によると、ピンに対して機能が以下の図のように割り当てられています。
このうち、ピンヘッダで信号を取り出せるのはGPIO2〜27となっています。
rpi-gpio.png

ざっと見ると、いわゆるGPIOとしての入出力以外に(ピンヘッダから)使える主な機能は

・I2C ×1 (SDA1/SCL1)
・SPI ×2 (SPI0、SPI1)
・UART ×1 (TXD0/RXD0/CTS0/RTS0、またはTXD1/RXD1/CTS1/RTS1)
・PWM ×2 (PWM0、PWM1)
・PCM ×1 (PCM_CLK/PCM_FS/PCM_DIN/PCM_DOUT)
・JTAG ×1 (ARM_TDI/ARM_TDO/ARM_RTCK/ARM_TMS/ARM_TCK)

であることが解ります。
このほかにGPIO Clock(オーディオデバイスにクロックを供給するために使われるらしい)、BSC Slave(I2C互換のBroadcom独自インタフェースらしいです)、メモリインタフェース(SDx、SAxがそれぞれデータバス/アドレスバス)があるようです。

他のRaspberry Piも含めた、より詳しい一覧表が以下のページにあります。

RPi BCM2835 GPIOs - eLinux.org

一つのピンに複数の機能は割り振れないので、例えばSPI1とRTS0/CTS0/RTS1/CTS1を同時に使用することはできません。
ピン配置は以前も掲載しましたが下図の通りです。



●Lチカ

GPIOを制御するには、Pythonのライブラリが公開されています。
しかしRaspbianはLinuxなので、GPIOのオン・オフくらいファイルシステム経由でできるだろう、と考えて調べてみたら、やはりそういったインタフェースが用意されていました。

Raspberry Pi でLチカする方法がたくさんありすぎる件について - Qiita

The Most Basic Way to Access GPIO on a Raspberry Pi

GPIOをオンオフするには、/sys/class/gpio以下のファイルに設定を書き込みます。
先日試したオンボードのLEDがつながっているGPIO47は、BUSYで制御できませんでしたので、普通にピンヘッダのほうのGPIOを試してみました。

1)echo ピン番号 > /sys/class/gpio/export で該当のGPIOを有効化
2)echo out > /sys/class/gpio/ピン番号/direction で出力ピンに設定
3)echo 0か1 > /sys/class/gpio/ピン番号/value でHまたはLを出力

という形で制御できます。
入力の場合は、echo in > /sys/class/gpio/ピン番号/directionで設定し、cat /sys/class/gpio/ピン番号/value で値を取得します。

以下の例ではGPIO4(ピンヘッダの7番ピン)に出力しています。
LEDのアノードを7番ピン、カソードを9番ピン(GND)に接続すれば、LEDをオン・オフできます。



raspbianにはraspi-gpioというパッケージがあり、
sudo apt-get install raspi-gpio
でインストールできます。
このパッケージを使うと、上記と同等のことをより簡単に行うことができます。
例えばGPIOの状態を取得するには、以下のようになります。



●I2C

まず、sudo raspi-configで「5 Interfacing Options」を選択し、I2CとSPIをenabledにしておきます。
これでデバイスドライバが自動で読み込まれるようになります。
I2Cは/dev/i2c-1、SPIは/dev/spidev0.0と/dev/spidev0.1がデバイスファイルとして作成されます。

I2Cは標準コマンドのみで操作することは難しいようですが、Linuxではプログラムを書かずに操作するための専用のi2c-toolsというパッケージがあります。

Raspberry Pi Tutorial Series: I2C - Waveshare Wiki

これはデフォルトのraspbianではインストールされていないので、
sudo apt-get install i2c-tools
でインストールします。
すると、以下のコマンドがインストールされます。
/usr/sbin/i2cdetect
/usr/sbin/i2cget
/usr/sbin/i2c-stub-from-dump
/usr/sbin/i2cdump
/usr/sbin/i2cset

これらのコマンドで、i2cデバイスを制御することができます。
とはいえ、i2cデバイスごとのドライバが必要にはなりますが。
おなじみのOLED、SSD1306のI2C版を接続してみました。結線は下図の通りです。
rpi-ssd1306.png

デバイスの検索は
i2cdetect -a 1
で行えます。1はI2Cバス番号です。
Raspberry Piでは、ピンヘッダ(ピン3、ピン5)で利用できるのはI2C1ですので、1を指定しています。
SSD1306 OLEDを接続した状態で実行すると、以下のようにアドレス「3C」にデバイスがあることが表示されます。
このアドレスは、製品によって異なる場合があるようです。



このOLEDへコマンドを送るには、i2csetを使います。
ちょっと長いですが、こちらのサンプルを借用して、I2Cバス番号とデバイスアドレスだけ書き換えたシェルスクリプトを作ってみました。



実行すると、こんな感じでOLEDに表示されます。

raspbian-ssd1306.jpg
posted by boochow at 23:45| Comment(0) | Raspberry Pi | このブログの読者になる | 更新情報をチェックする

Raspberry Pi版MicroPythonのベンチマークテスト(2)

先日試したRaspberry Piベアメタル版のMicroPythonのベンチマークテストが非常に悪いスコアだったので、念のためRaspbianをRaspberry Pi zero W用にインストールし、その上でLinux版MicroPythonを動かしてみました。

その結果・・・

(1)Pystone
Pystone(1.2) time for 500 passes = 103 ms
This machine benchmarks at 4854 pystones/second

(2)performanceTest
>>> performanceTest()
Count: 5503852

(3)hsquare.py
Doing 50000 calculations...
calculations done after 1364 ms.
Mean time for each inverse h square calculation = 27.2800000000000 us
Sum of inverse h square = 38023.4625865792796
Mean of inverse h square = 0.7604692517316

という感じで、ベアメタル版の8〜9倍高いスコアを叩き出しました。
やはり、何か大きなボトルネック(または設定不良?)があるようです。

config.txtでの設定はパフォーマンスに関わるようなものは特に無く、実際Raspbianインストール時に作成されたconfig.txtのkernel設定を変えてベアメタル版MicroPythonを起動しても、パフォーマンスは向上しませんでした。

ちなみにRaspbian上でMicroPythonをビルドする手順については、こちらに紹介されています。

Installing MicroPython - How To Guide - Raspberry Pi Forums

ただ、Raspberry Pi Zero Wでこれを行うと、PC-Linuxの上でビルドする場合と比べて10倍くらい時間がかかります。
posted by boochow at 10:01| Comment(0) | Raspberry Pi | このブログの読者になる | 更新情報をチェックする

2018年01月07日

Raspberry Pi版MicroPythonのベンチマークテスト

昨日行った、Raspberry Piベアメタル版MicroPythonでのLチカですが、手動でオン・オフができるだけで、「点滅」はできていませんでした。
点滅を行うには、一定時間停止するdelay機能が必要ですが、MicroPythonではutimeモジュールにdelay_ms()があります。
ESP32やSTM32用の実装を参考に、このモジュールをRaspberry Pi用に移植しました

ESP32やSTM32用のモジュールとの差分は、ほぼ現在時刻を取得する部分のみですが、これは以前のC言語版ベアメタルLチカで使ったシステムタイマの機能をそのまま使います。
ただ、Raspberry Piにはバッテリバックアップ付きの時計機能が無いので、電源ONのたびに2000年1月1日0時0分0秒になってしまいます。

とはいえ、delayは実現できましたので、以下のコードでいわゆる「Lチカ」が行えました。



これで経過時間を計測できるようなりましたので、次に以下で紹介されているベンチマークテストを動かしてみました。

Benchmark comparison of MicroPython boards - MicroPython Forum

モジュール名がtimeになっているところはutimeに適宜変更します。
ベンチマークの内容は、
(1)文字列や配列の演算:値が大きいほど高速
(2)一定時間に「1増やす」を行った回数:値が大きいほど高速
(3)内容はよく分かりませんが、ある浮動小数点演算の所要時間:値が小さいほど高速
となっています。

結果ですが、以下のようになりました。
(1)Pystone
Pystone(1.2) time for 500 passes = 818 ms
This machine benchmarks at 611 pystones/second

(2)performanceTest
>>> performanceTest()
Count: 612921

(3)hsquare.py
Doing 50000 calculations...
calculations done after 11717 ms.
Mean time for each inverse h square calculation = 234.3400001525878 us
Sum of inverse h square = 38023.2257843017578
Mean of inverse h square = 0.7604645729065


上記のスレッドにある他のMCUと比較してみましょう。
PyBoard1.1は168MHzのCortex-M4F、Teensy3.6は180MHzのCortex-M4です。

(1)Pystone
* Pyboard v1.1 with MicroPython v1.8.6 : 1,754;
* ESP8266 with MicroPython v1.8.6-7 : 223 (80 MHz) / 415 (160 MHz);
* Teensy 3.6 with MicroPython v1.8.6 : 2212;
* Raspberry Pi Zero W with MicroPython v1.9.3 : 611.

(2)performanceTest
* Pyboard v1.1 with MicroPython v1.8.6 : 2,783,122;
* ESP8266 with MicroPython v1.8.6-7 : 171,145 (80 MHz) / 341,224 (160 MHz);
* Teensy 3.6 with MicroPython v1.8.6 : 3,451,931;
* Raspberry Pi Zero W with MicroPython v1.9.3 : 612,921.

(3)hsquare.py
* Pyboard v1.1 with MicroPython v1.8.6 : 83;
* ESP8266 with MicroPython v1.8.6-7 : 460 (80 MHz) / 239 (160 MHz);
* Teensy 3.6 with MicroPython v1.8.6 : 73;
* Raspberry Pi Zero W with MicroPython v1.9.3 : 234.34.

Raspberry Pi Zero Wのクロックは1GHzのはずなのですが、全然速くないですね。
どこかにボトルネックがあるのかもしれません。
ラベル:MicroPython
posted by boochow at 18:38| Comment(0) | Raspberry Pi | このブログの読者になる | 更新情報をチェックする
人気記事