前回Arduinoでモーターの制御は出来るようになりました。
そこでArduinoとモータードライバー(Mini L298N)でDCモーターを動作させつつ、テンキーパッドで好きなタイミングでDCモーターへの出力パターンを切り替えるられるようにしたいと思います。
どうせなので出力パターンを三角波、のこぎり波、矩形波、sin波、cos波と用意してテンキーパッドのボタンで随時切り替えられるようにします。
用意するもの
前の記事でモータを制御するために用意した一揃いを用意します。
ArduinoとMini L298Nモータードライバーでモーターを制御する - メモとか
加えてKeyPadも用意します。
スターターキットとかによく入っているやつですね。
4*3 Membrane Switch Keypad
ブレッドボード図
それぞれのパーツをつなげます。
プログラム
キーパッド用のライブラリがあるので使わせてもらいました。
使い方などは下記ページを参考にしました。
今回モーターへの出力をいくつかパターンにして随時テンキーパッドの入力で切り替えたいので、単純にfor
を使って波形を作るわけにはいきません。
forループの間テンキーパッドの監視ができないためです。
Arduinoはシングルスレッドなので、別スレッドを立てて監視するわけにもいきません。
そこで毎loop()
ごとに起動してから現在までの時間を返すmillis()
を使って波形を計算してモーターへの出力を決めるようにします。
// switch-motor-operation-with-arduino-and-keypad.ino #include <Key.h> #include <Keypad.h> #include "Waves.h" const byte in1 = 10; // Mini L298N の'IN1'に出力するピン const byte in2 = 9; // Mini L298N の'IN2'に出力するピン // キーパッドの設定いろいろ const byte ROWS = 4; const byte COLS = 3; char hexaKeys[ROWS][COLS] = { {'1', '2', '3'}, {'4', '5', '6'}, {'7', '8', '9'}, {'*', '0', '#'} }; byte rowPins[ROWS] = {8, 7, 6, 5}; // キーパッドの入力に使うピン byte colPins[COLS] = {4, 3, 2}; // キーパッドの入力に使うピン /** * @brief 繰り返しの波形のなかの横軸xとした場合のx位置 * @param waveLength: 波長(ミリ秒) * @return 繰り返しの波形のなかの横軸xとした場合のx位置 */ long current(long waveLength) { return millis() % waveLength; } /** * モーターへの出力のパターンいろいろ */ long wave0() { return 0; } long wave1() { return triangleWave(0, 255, 3000, current(3000)); } long wave2() { return sawtoothWave(0, 255, 1500, current(1500)); } long wave3() { return negativeSawtoothWave(0, 255, 1500, current(1500)); } long wave4() { return squareWave(0, 255, 2000, current(2000)); } long wave5() { return sineWave(0, 255, 5000, current(5000)); } long wave6() { return cosineWave(0, 255, 5000, current(5000)); } void setup() { pinMode(in1, OUTPUT); pinMode(in2, OUTPUT); } void loop() { static Keypad keypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); static long (* waveFunc[])() = {wave0, wave1, wave2, wave3, wave4, wave5, wave6}; static int wave = 0; // キーパッドへの入力で波形切り替え char key = keypad.getKey(); switch (key) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': wave = key - '0'; break; } // モーターへ出力 analogWrite(in1, (* waveFunc[wave])()); }
出力パターンは長いので分けてみました。
map()
関数があるので、どれも簡単に実装できます。
// Waves.h #ifndef _WAVES_h #define _WAVES_h #include <Arduino.h> #include <math.h> // for M_PI long triangleWave(long, long, long, long); long sawtoothWave(long, long, long, long); long negativeSawtoothWave(long, long, long, long); long squareWave(long, long, long, long); long sineWave(long, long, long, long); long cosineWave(long, long, long, long); #endif
// Waves.cpp #include "Waves.h" /** * @brief 三角波 * @param min_: 最小出力 * @param max_: 最大出力 * @param waveLength: 波長 * @param current: 波長の中の現在位置 * @return 現在位置に対応する出力 * @note 波形は下記の感じになります。 * + + * +++ +++ * +++++ +++++ * +++++++ +++++++ * ++++++++++++++++++ */ long triangleWave(long min_, long max_, long waveLength, long current) { if (current < waveLength / 2) { return map(current, 0, waveLength / 2, min_, max_); } else { return map(current, waveLength / 2, waveLength, max_, min_); } } /** * @brief のこぎり波 * @param min_: 最小出力 * @param max_: 最大出力 * @param waveLength: 波長 * @param current: 波長の中の現在位置 * @return 現在位置に対応する出力 * @note 波形は下記の感じになります。 * + + * ++ ++ * +++ +++ * ++++ ++++ * ++++++++++ */ long sawtoothWave(long min_, long max_, long waveLength, long current) { return map(current, 0, waveLength, min_, max_); } /** * @brief 逆のこぎり波 * @param min_: 最小出力 * @param max_: 最大出力 * @param waveLength: 波長 * @param current: 波長の中の現在位置 * @return 現在位置に対応する出力 * @note 波形は下記の感じになります。 * + + * ++ ++ * +++ +++ * ++++ ++++ * ++++++++++ */ long negativeSawtoothWave(long min_, long max_, long waveLength, long current) { return map(current, 0, waveLength, max_, min_); } /** * @brief 矩形波 * @param min_: 最小出力 * @param max_: 最大出力 * @param waveLength: 波長 * @param current: 波長の中の現在位置 * @return 現在位置に対応する出力 * @note 波形は下記の感じになります。 * +++++ +++++ * +++++ +++++ * +++++ +++++ * +++++ +++++ * ++++++++++++++++++++ */ long squareWave(long min_, long max_, long waveLength, long current) { if (current < waveLength / 2) { return max_; } else { return min_; } } /** * @brief 正弦波 * @param min_: 最小出力 * @param max_: 最大出力 * @param waveLength: 波長 * @param current: 波長の中の現在位置 * @return 現在位置に対応する出力 * @note 波形は下記の感じになります。 * ++++ ++++ * ++++++++++ ++++++++++ * ++++++++++++++ ++++++++++++++ * ++++++++++++++++++ ++++++++++++++++++ * ++++++++++++++++++++++++++++++++++++++++++++++++ */ long sineWave(long min_, long max_, long waveLength, long current) { const long accuracy = max_ - min_; const double wave = sin(2 * M_PI / waveLength * current); return map(wave * accuracy, -accuracy, accuracy, min_, max_); } /** * @brief 余弦波 * @param min_: 最小出力 * @param max_: 最大出力 * @param waveLength: 波長 * @param current: 波長の中の現在位置 * @return 現在位置に対応する出力 * @note 波形は下記の感じになります。 * ++ ++++ ++ * +++++ ++++++++++ +++++ * +++++++ ++++++++++++++ +++++++ * +++++++++ ++++++++++++++++++ +++++++++ * ++++++++++++++++++++++++++++++++++++++++++++++++ */ long cosineWave(long min_, long max_, long waveLength, long current) { const long accuracy = max_ - min_; const double wave = cos(2 * M_PI / waveLength * current); return map(wave * accuracy, -accuracy, accuracy, min_, max_); }
(2021/3/9)バグ修正
GitHubにコードを上げてみました。
https://github.com/singo-i/switch-motor-operation-with-arduino-and-keypad