Arduinoでモーターへの出力をいくつかのパターンにしてテンキーパッドで切り替える

前回Arduinoでモーターの制御は出来るようになりました。

web-memo-s.hatenablog.com

そこでArduinoとモータードライバー(Mini L298N)でDCモーターを動作させつつ、テンキーパッドで好きなタイミングでDCモーターへの出力パターンを切り替えるられるようにしたいと思います。

どうせなので出力パターンを三角波、のこぎり波、矩形波、sin波、cos波と用意してテンキーパッドのボタンで随時切り替えられるようにします。

用意するもの

前の記事でモータを制御するために用意した一揃いを用意します。

ArduinoとMini L298Nモータードライバーでモーターを制御する - メモとか

加えてKeyPadも用意します。

スターターキットとかによく入っているやつですね。

4*3 Membrane Switch Keypad

s.click.aliexpress.com

ブレッドボード図

それぞれのパーツをつなげます。

f:id:isinsin:20210223134519p:plain
キーパッドとモーター

プログラム

キーパッド用のライブラリがあるので使わせてもらいました。

使い方などは下記ページを参考にしました。

novicengineering.com

www.circuitbasics.com

今回モーターへの出力をいくつかパターンにして随時テンキーパッドの入力で切り替えたいので、単純に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()関数があるので、どれも簡単に実装できます。

www.arduino.cc

// 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