水耕栽培ではLEDのパルス駆動にメリットがあることは LEDのパルス制御で成長促進と消費電力節約の一石二鳥 でご紹介しました。
パルス制御を実現するために、Raspberry Piで制御を行います。前回PythonでPWM制御をしようとして失敗したので、今回はWiringPiを使います。うまくいきましたよ!
パルス制御
パルスって矩形(くけい)と言う意味です。矩形制御ってなに?という話があるかと思いますが、on/offする時にスイッチonとoffを繰り返すことをパルス制御と言います。下の図のように確かに四角い・矩形がたくさん出てきます。
パルス制御は消費電力が低い、発熱しにくい
Steve Jobs率いる初期のAppleがApple II のパソコンの電源にスイッチング電源を使った話は有名です。無駄な電力を消費しないように必要な時に電気を流すという制御をしています。今の世の中、スイッチング電源でない電源は圧倒的に少ないでしょうから、それだけみなさんの身近にあることになります。
パルス制御の重要な2つのパラメータ
パルス制御する上で重要な2つのパラメータがあります。一つは周期、もう一つはDuty比というものです。
- 周期 : 図のTで矩形の周期ですね。
- Duty比 : a / T (%)
例えばDuty比、50%というと、2a = Tが成り立ちます。
パルス制御の一般的な呼び方
パルス制御のことはPWM(Pulse Width Modulation)というのが一般的です。PWM制御ができるかどうかは接続する素子の応答特性によるものが大きいです。蛍光灯はもちろんできなくて、LEDであれば可能な制御方法です。
蛍光灯はPWMで制御できない
蛍光灯は応答特性が良くないため、PWM制御ができません。LEDを使うメリットはここにもあります。
Raspberry PiとWiringPiの導入
Raspberry Piってなに?
Raspberry Piってご存知でしょうか。小型のパソコンでGPIO(General Purpose I/O ) portがついています。I/O portがあるので電子工作と非常に相性がいいです。またパソコンですのでOSを入れれば簡単にプログラムを動かすことができます。
Raspberry Piで使用するPort
Raspberry PiのGPIOはPWM出力に対応したportがひとつ用意されています。Port 18です。このPortのPWMはハードウェア制御なので誤差が少ないです。ソフトウェアでのPWMではパソコンと同じで動いているソフトの影響を受け、制御が不安定になります。このportで最適なPWM制御を実現しましょう!
PORTの制御はWiringPiを使います。
Wiring Piを使う理由
前回Pythonで失敗しました。Software制御しかできなかったのが大きな原因です。今回はRaspberry PiのハードウェアPWM制御を使いたいと思います。Wiring Piはハードウェア制御をサポートしているので今回は失敗しないはずです。
Wiring Piってなに?
WiringPiはGordon Hendersonさんが開発したRaspberry PiのGPIOを簡単に制御できるライブラリです。ライブラリはC言語で動くように準備されています。今回は触れませんが、他の言語でも動作できるようにラッパーが用意されているようです。
Wiring Piのインストール方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
//今は使用しませんが、I2Cのライブラリのinstallをしましょう。 $sudo apt-get install libi2c-dev //GITにsource codeがあります。GITにアクセスできるように準備しましょう。 $sudo apt-get install git-core //GITからWiringPiのファイルをダウンロードします。 $git clone git://git.drogon.net/wiringPi //wiringPiのフォルダができているはずです。そのフォルダに移動してコンパイルしましょう。 $cd wiringPi $./build //installが完了したかを確認します。version情報がでれば十分です。 $gpio -v |
WiringPiのライブラリの確認
Raspberry PiでLEDを制御するためにはGPIOの制御が必要です。GPIOの制御とPWM制御するために必要な関数について説明します。
wiringPiSetupGpio
Raspberry PiにはBroadcomという会社のSoC(System On Chip)が載っており、GPIOを制御します。この関数を呼ぶとそれぞれのGPIOポートを番号で呼ぶことができるようになります。
pinMode
I/OのInput / Outputの設定をします。OUTPUTの場合はOUTPUTを指定します。PWMの場合はPWM_OUTPUTです。InputはINPUTです。
pwmSetMode
SoCがBalancedとMarked Spaceという二つのPWMをサポートしています。こちらに仕様がかいてあります。Balancedは高速切り替えが必要なモードに使われ、Marked Spaceは高速な切り替えが必要なものに使われるようです。Marked Spaceは周期的なDutyや周波数が変わらないもので仕様するのであれば問題ありません。
pwmSetRange/pwmSetClock
周波数がこれらで決まります。Raspberry Piはベースの周波数が19.2MHzです。これに対しこの関数で設定した値で割った値が周波数になります。
19.2MHz / (pwmSetRange * pwmSetClock)が周波数となります。
pwmWrite
Duty比を決めます。pwmSetRangeが基準となりますので、pwmWrite/pwmSetRangeがDuty比になります。
プログラムの作製
サンプルプログラムを作製してみました。
- CPUへの負荷低減のため、10秒ごとに時間のチェックをするようにしています。
- Dutyの比は引数として受け取ります。
- PWM周波数はこちらできめた200us=5000Hzで固定です。
- 植物の光合成は200usおきに行われるようなので400usの周期で200us on / 200us offにするのがおすすめです。今回のプログラムは200usの周期なのでご注意ください。
- 昼間は赤色が点灯するようにしています。夜は青です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
#include <time.h> #include <wiringPi.h> #include <iostream> #include <string> #include <unistd.h> #include <cstdint> #include <algorithm> constexpr uint8_t PORT_PWM = 18; const char* getCmdOption(char** begin, char** end, const std::string& option, const std::string& retDefault) { char** itr = std::find(begin, end, option); if (itr != end && ++itr != end) { return *itr; } return retDefault.c_str(); } int init(int duty, int32_t port_1, int32_t port_2) { if (wiringPiSetupGpio() == -1) { printf("setup failed\n"); return -1; } //set source output mode pinMode(port_1, OUTPUT); pinMode(port_2, OUTPUT); pinMode(PORT_PWM, PWM_OUTPUT); // pwm setting pwmSetMode(PWM_MODE_MS); pwmSetRange(192); pwmSetClock(20); int dutyToSet = static_cast<int>(1.92 * static_cast<float>(duty)); pwmWrite(PORT_PWM, dutyToSet); return 0; } int main(int argc, char* argv[]) { struct tm* now; time_t t; const int32_t pwmDuty = atoi(getCmdOption (argv, argv + argc, "-pwm", "50")); const int32_t port_1 = atoi(getCmdOption (argv, argv + argc, "-port1", "17")); const int32_t port_2 = atoi(getCmdOption (argv, argv + argc, "-port2", "23")); const std::string mode = std::string(getCmdOption(argv, argv + argc, "-mode", "save")); const int32_t dayStart = atoi(getCmdOption (argv, argv + argc, "-start", "600")); const int32_t dayEnd = atoi(getCmdOption (argv, argv + argc, "-end", "1800")); std::cout << "-mode " << mode << std::endl; std::cout << "-pwm " << pwmDuty << std::endl; std::cout << "-port1 " << port_1 << std::endl; std::cout << "-port2 " << port_2 << std::endl; //initialization if(init(pwmDuty, port_1, port_2) != 0) { printf("initialization fail\n"); return -1; } // rounte for each mode if(mode.compare("save") == 0) { std::cout << "save is selected" << std::endl; std::cout << "LED on time: " << dayStart << " - " << dayEnd << std::endl; while(1) { time_t t = time(NULL); struct tm* now = localtime(&t); uint32_t curTime = now->tm_hour * 100 + now->tm_min; if((curTime > dayStart) && (curTime < dayEnd)) { digitalWrite(port_1, 0); digitalWrite(port_2, 0); } else { digitalWrite(port_1, 1); digitalWrite(port_2, 1); } sleep(10); } } else if (mode.compare("run") == 0) { std::cout << "run is selected" << std::endl; digitalWrite(port_1, 1); digitalWrite(port_2, 1); } else { std::cout << "unknown mode: " << mode << " is set. save or run is a mode" << std::endl; return -1; } return 0; } |
実験結果
うまく動きました。意図した通り、5000kHzになっております。
まとめ
WiringPiを使えば正確に周波数制御ができることが確認できました。Sampleプログラムも紹介しましたので、PWM制御をするのであればWiringPiを使用することをお勧めします!
記事を読んでいただいてありがとうございます。この記事がいいなと思ったら下記のSNSボタンのクリックをお願いします。励みになります😁
Wiring Piのインストール方法で
$git clone git://git.dr[a]gon.net/wiringPi
とありますが、
$git clone git://git.dr[o]gon.net/wiringPi
ではないでしょうか?
もう1か所、
「ラズベリーパイでLEDを制御しよう。WiringPiを使います。」
のページも同様だと思います。
「Raspberry Piに MySQLを導入!」のページ、
非常に興味をそそられました。
自分の作った植物工場?がIoT化されたらすごいですね。
まっくん さん
ご指摘ありがとうございます。修正しました。ご迷惑おかけしました。。(×_×;)
MySQLはいいですよー!PHPと相性がよさそうなので温度・湿度のモニタリングに最適なのかなと思っています。温度・湿度が把握できてもエアコンをつけたくないので動かせる機器がファンくらいしかないのが難点ですが。。。将来的には過去のデータから育てる野菜を時期によって変えようと思っています。
IoTに興味があるのであれればこちらも参考になるかもしれません。照度センサーで暗くなったらLEDを光らせたり、水の循環をスケジューリングしていますよー(*´罒`*)ニヒヒ
サンプルプログラムを動かそうとしてみましたが、44行目と69行目でコンパイルエラーが出ます。
atoi(argv[1]); と sleep(10); のところです。
そこで、
#include
#include
を追加すると、コンパイルエラーは出なくなりますが、
実行時に「Segmentation fault」と表示されます。
どこがいけないのでしょうか。
#include の後ろが送信時に消えてしまいました。
<unistd.h>
<stdlib.h>
の2つです。
まっくん さん
こんにちは!
ライブラリは下記を使っています。
stdio.h / time.h / wiringPi.h
コンパイルはgccを使っています。
$ gcc -o pwm.o pwm.c -lwiringPi
私の環境だと特に問題なくコンパイル出来たので、もう一度確認していただけますでしょうか??
プログラムはそっくりコピーさせてもらったので間違いはないと思います。
コンパイルも
$ gcc -o pwm.o pwm.c -lwiringPi
としていますが、エラーになります。
エラーの内容は、
pi@zero:~ $ gcc -o pwm.o pwm.c -lwiringPi
led_test.c: In function ‘main’:
led_test.c:44:15: warning: implicit declaration of function ‘atoi’ [-Wimplicit-function-declaration]
pwmDuty = atoi(argv[1]);
^~~~
led_test.c:69:5: warning: implicit declaration of function ‘sleep’ [-Wimplicit-function-declaration]
sleep(10);
^~~~~
です。
44/69行目はwarningなので修正すべきかもしれませんが、プログラム上は問題ないです。
引数は設定されていますでしょうか? PWMのDuty比を引数としてinputされることを期待しています。50などを引数として渡してください。
ただ、raspberry pi zeroだと動かないかもしれません。手持ちでraspberry pi zero wを持っているのですがこのプログラムを動かすとラズパイがdownしました。おそらくPWMの設定が他のraspberry piと違うのだと思います。解決策はこれから調査になりますが。。
お察しのとおりraspberry pi zero wを使用していますが、特にダウンしたりとかはありません。(ダウンするのは電源が足りてない?)
他のHPとか見てみるとraspberry pi zeroでgpio18ピンのハードウェアpwmをwiringPiを使って利用しているものがありますので、動作すると思いますが・・・
ここも
$sudo apt-get install git-code
になっています。
いまだに
raspberry pi zero で動かそうと四苦八苦しています。
ふと気づいたのですが、文部科学省のHPを見ると、
「・・・クロロフィルP680の還元時間に200μsかかり、この間は光照射が必要ない・・・」
「・・・周期400μs(パルス幅200μs)の間欠光で・・・」
ということですので、
pwm周波数は5000Hzより2500Hzのほうがいいみたいですね。
まっくん さん
確かにそうですね。2.5kHzの方が正しいようです。数字の読み取りを間違えていました。徐々に記事の内容を修正していきます。ご指摘ありがとうございます。
ちょっと納得できないのが200usだからといって同じ周波数にしてしまうとナイキスト周波数を満たさなくなってしまうところです。そうすると倍の周波数5.0kHzの方がいい気がします。
植物の方からシンクしたりしているのか、未解明のDuty比33%でもOKな部分が影響しているのかもしれません。500us以降で急激に結果が悪くなっているのを見ると少なくともシンクはしているのかもしれません。
還元時間200μsは必ず必要みたいなので、Duty比33%にするにはサイクルを300μsにして点灯時間を100μsにすれば良いということなのですかね?
まっくん さん
文部科学省のサイトには300us周期のデータはないのでご検討の方法が良いのかは分かりません。
400usで明暗の比を1:1の結果が一番良くて、1:2にしても何故か良かったということが書いてあるのだと思います。
raspberry pi zero W で pwm 動作しました!(GUI環境にて)
オシロで確認しましたが、波形 バッチリです。(^^)
次は mysql の導入・・・に挑戦してみたいですが、難しそうですね。
そのまえにスマホからのLEDとポンプ等の制御かな?
まっくん さん
おめでとうございます。ACコンセントの制御は簡単なのに実益があるのでおすすめです!
MySQLに関してはhttp://jitaku-yasai.com/home-made/iot-checktemperature/ に詳細まとめてみましたので参考にしてください(〃’ω’)