NEMA 17 (ステッピングモーター)の加減速制御ができました
モータードライバーが直ぐに結構熱くなるのが懸念点
ソースコード
長いですが、以下に貼り付けます。
「とりあえず動いた」レベルで堅牢性などは不明です。
また、コーディング標準的に Arduino として適切ではない可能性もあります。
加減速から定速に移行する時に弱い衝撃があるので、滑らかにつなげる処理があった方が良いのかも知れません。(難しそう)
※修正 (2022.6.28、v1.2.1)
一部に間違いがあり、rpm が指定の半分になっていました。
赤字の太字で修正します。(4行)
StepperMotor_v1.2.0.ino
// https://www.norwegiancreations.com/2014/12/arduino-tutorial-stepper-motor-with-easydriver/ ← A3967の配線図とサンプルコード#include "A3967.h"
// ピンアサイン
int m_pinM1 = 2;
int m_pinM2 = 3;
int m_pinDdirection = 4;
int m_pinStep = 5;
// モータードライバークラス
A3967 a3967(A3967::MicloStepTypes::EighthStep, m_pinM1, m_pinM2, m_pinDdirection, m_pinStep);
void setup()
{
// 初期化
a3967.Init();
// シリアルポートの開始
Serial.begin(9600);
// 以下、回転動作
a3967.Step(true, 400, 4);
delay(1000);
a3967.Step(false, 300, 3);
delay(1000);
}
void loop()
{
Test14();
}
void Test14()
{
int maxRpm = 600;
int rotationNumToComplete = 10;
a3967.Accelerate(true, 0, maxRpm, rotationNumToComplete, A3967::MicloStepTypes::EighthStep);
a3967.Accelerate(true, maxRpm, maxRpm + 1, rotationNumToComplete + 5);
//a3967.Step(true, maxRpm, 20);
a3967.Accelerate(true, maxRpm + 1, maxRpm, rotationNumToComplete + 5);
a3967.Accelerate(true, maxRpm, 0, rotationNumToComplete - 2);
delay(1000);
}
A3967.h
#include <Arduino.h>#include "RotateCalcUtil.h"
#ifndef A3967_h
#define A3967_h
class A3967
{
public:
// enum
enum class MicloStepTypes { FullStep, HalfStep, QuarterStep, EighthStep };
// コンストラクタ
A3967(MicloStepTypes micloStep, int pinM1, int pinM2, int directionPin, int stepPin);
// 初期化
void Init();
// 回転動作
void Step(bool isClockwise, int rpm, int rotationNum, A3967::MicloStepTypes micloStepType);
void Step(bool isClockwise, int rpm, int rotationNum);
// 加減速動作
void Accelerate(bool isClockwise, int rpmFrom, int rpmTo, float rotationNumToComplete, A3967::MicloStepTypes micloStepType);
void Accelerate_01(bool isClockwise, int rpmFrom, int rpmTo, float rotationNumToComplete);
void Accelerate(bool isClockwise, int rpmFrom, int rpmTo, float rotationNumToComplete);
private:
// 定数
const int BASE_STEPS_PER_ROTATION = 200;
// 処理クラス
RotateCalcUtil* rotateCalcUtil;
// メンバー変数
A3967::MicloStepTypes m_micloStepType = A3967::MicloStepTypes::EighthStep;
int m_pinM1 = 2;
int m_pinM2 =3;
int m_pinDirection = 4;
int m_pinStep = 5;
// 1周のステップ数の取得
int GetStepsPerRotation(A3967::MicloStepTypes micloStepType);
// マイクロステップモードの書き込み
void WrtiteMicloStepMode(A3967::MicloStepTypes micloStepType);
};
#endif
A3967.cpp
#include "A3967.h"#include <Arduino.h>
#include "RotateCalcUtil.h"
/// コンストラクタ
A3967::A3967(A3967::MicloStepTypes micloStepType, int pinM1, int pinM2, int pinDirection, int pinStep)
{
// 引数の保存
m_micloStepType = micloStepType;
m_pinM1 = pinM1;
m_pinM2 = pinM2;
m_pinDirection = pinDirection;
m_pinStep = pinStep;
// 処理クラスの生成
rotateCalcUtil = new RotateCalcUtil();
}
/// 初期化
void A3967::Init()
{
// ピンモードの設定
pinMode(m_pinM1, OUTPUT);
pinMode(m_pinM2, OUTPUT);
pinMode(m_pinDirection, OUTPUT);
pinMode(m_pinStep, OUTPUT);
// マイクロステップモードの書き込み
A3967::WrtiteMicloStepMode(m_micloStepType);
}
/// 回転動作
void A3967::Step(bool isClockwise, int rpm, int rotationNum, A3967::MicloStepTypes micloStepType)
{
// 引数の保存
m_micloStepType = micloStepType;
// マイクロステップモードの書き込み
A3967::WrtiteMicloStepMode(m_micloStepType);
// 実際の回転動作
A3967::Step(isClockwise, rpm, rotationNum);
}
void A3967::Step(bool isClockwise, int rpm, int rotationNum)
{
// 1周のステップ数の取得
int stepsPerRotation = A3967::GetStepsPerRotation(m_micloStepType);
// 必要なステップ数
int steps = stepsPerRotation * rotationNum;
// 1ステップの時間の計算
int microSecPerStep = rotateCalcUtil->CalcMicroSecPerStep(rpm, stepsPerRotation);
//Serial.print("Step.microSecPerStep : ");
//Serial.println(microSecPerStep);
// 回転方向の指定
if(isClockwise == true) { digitalWrite(m_pinDirection, HIGH); }
else { digitalWrite(m_pinDirection, LOW); }
// 回転動作
int microSecPerStepA;
for(int i = 0; i < steps; i++)
{
//@@@@
int microSecPerStepA = rotateCalcUtil->CalcMicroSecPerStep(rpm, stepsPerRotation);
// 書き込み
digitalWrite(m_pinStep, HIGH);
delayMicroseconds(microSecPerStep / 2);
digitalWrite(m_pinStep, LOW);
delayMicroseconds(microSecPerStep / 2);
}
}
/// 加減速動作
void A3967::Accelerate(bool isClockwise, int rpmFrom, int rpmTo, float rotationNumToComplete, A3967::MicloStepTypes micloStepType)
{
// 引数の保存
m_micloStepType = micloStepType;
// マイクロステップモードの書き込み
A3967::WrtiteMicloStepMode(m_micloStepType);
// 実際の加減速動作
A3967::Accelerate(isClockwise, rpmFrom, rpmTo, rotationNumToComplete);
}
void A3967::Accelerate_01(bool isClockwise, int rpmFrom, int rpmTo, float rotationNumToComplete)
{
// 1周のステップ数の取得
int stepsPerRotation = A3967::GetStepsPerRotation(m_micloStepType);
// 必要なステップ数
int steps = stepsPerRotation * rotationNumToComplete;
// 1ステップの時間の計算(開始時と終了時)
int microSecPerStep_From = rotateCalcUtil->CalcMicroSecPerStep(rpmFrom, stepsPerRotation);
int microSecPerStep_To = rotateCalcUtil->CalcMicroSecPerStep(rpmTo, stepsPerRotation);
// 差分の計算
long microSecPerStep_Delta = 0;
{
int diff = microSecPerStep_To - microSecPerStep_From;
microSecPerStep_Delta = (diff * (long)1000) / (long)steps;
}
// 回転方向の指定
if(isClockwise == true) { digitalWrite(m_pinDirection, HIGH); }
else { digitalWrite(m_pinDirection, LOW); }
// 加減速動作
int microSecPerStep = microSecPerStep_From;
long accumulation = 0;
long temp = 0;
for(int i = 0; i < steps; i++)
{
digitalWrite(m_pinStep, HIGH);
delayMicroseconds(microSecPerStep);
digitalWrite(m_pinStep, LOW);
delayMicroseconds(microSecPerStep);
// 差分の確認と適用
accumulation += microSecPerStep_Delta;
if(accumulation < (long)-1000 || (long)1000 < accumulation)
{
temp = accumulation / (long)1000;
microSecPerStep += temp;
accumulation -= temp * (long)1000;
}
}
}
void A3967::Accelerate(bool isClockwise, int rpmFrom, int rpmTo, float rotationNumToComplete)
{
// 1周のステップ数の取得
int stepsPerRotation = A3967::GetStepsPerRotation(m_micloStepType);
// 必要なステップ数
int steps = stepsPerRotation * rotationNumToComplete;
// 差分の計算
long rp1000000m_Delta = (long)0;
{
int diff = rpmTo - rpmFrom;
rp1000000m_Delta = ((long)diff * (long)1000000) / ((long)steps - (long)1);
}
// 回転方向の指定
if(isClockwise == true) { digitalWrite(m_pinDirection, HIGH); }
else { digitalWrite(m_pinDirection, LOW); }
// 加減速動作
int microSecPerStep;
int rpm = rpmFrom;
long accumulation = 0;
long temp = 0;
for(int i = 0; i < steps; i++)
{
// 差分の確認と適用
if(i != 0)
{
accumulation += rp1000000m_Delta;
if(accumulation < (long)-1000000 || (long)1000000 < accumulation)
{
temp = accumulation / (long)1000000;
rpm += temp;
accumulation -= temp * (long)1000000;
}
}
// 1ステップの時間の計算
microSecPerStep = rotateCalcUtil->CalcMicroSecPerStep(rpm, stepsPerRotation);
//Serial.print("Accelerate.microSecPerStep : ");
//Serial.println(microSecPerStep);
// 書き込み
digitalWrite(m_pinStep, HIGH);
delayMicroseconds(microSecPerStep / 2);
digitalWrite(m_pinStep, LOW);
delayMicroseconds(microSecPerStep / 2);
}
}
//-- 以下、privateメソッド
/// 1周のステップ数の取得
int A3967::GetStepsPerRotation(A3967::MicloStepTypes micloStepType)
{
// 1回転のステップ数(ベース)
int stepsPerRotation = A3967::BASE_STEPS_PER_ROTATION;
// マイクロステップの場合は係数を適用
if (micloStepType == A3967::MicloStepTypes::HalfStep)
{
stepsPerRotation = stepsPerRotation * 2;
}
else if (micloStepType == A3967::MicloStepTypes::QuarterStep)
{
stepsPerRotation = stepsPerRotation * 4;
}
else if (micloStepType == A3967::MicloStepTypes::EighthStep)
{
stepsPerRotation = stepsPerRotation * 8;
}
// 返す
return stepsPerRotation;
}
/// マイクロステップモードの書き込み
void A3967::WrtiteMicloStepMode(A3967::MicloStepTypes micloStepType)
{
if(m_micloStepType == A3967::MicloStepTypes::FullStep)
{
digitalWrite(m_pinM1, LOW);
digitalWrite(m_pinM2, LOW);
}
else if(m_micloStepType == A3967::MicloStepTypes::HalfStep)
{
digitalWrite(m_pinM1, HIGH);
digitalWrite(m_pinM2, LOW);
}
else if(m_micloStepType == A3967::MicloStepTypes::QuarterStep)
{
digitalWrite(m_pinM1, LOW);
digitalWrite(m_pinM2, HIGH);
}
else
{
digitalWrite(m_pinM1, HIGH);
digitalWrite(m_pinM2, HIGH);
}
}
RotateCalcUtil.h
#ifndef RotateCalcUtil_h#define RotateCalcUtil_h
class RotateCalcUtil
{
public:
// コンストラクタ
RotateCalcUtil();
// 1ステップの時間の計算
int CalcMicroSecPerStep(int rpm, int stepsPerRotation);
private:
};
#endif
RotateCalcUtil.cpp
#include "RotateCalcUtil.h"#include <Arduino.h>
/// コンストラクタ
RotateCalcUtil::RotateCalcUtil()
{
// 何もしない
}
/// 1ステップの時間の計算
int RotateCalcUtil::CalcMicroSecPerStep(int rpm, int stepsPerRotation)
{
if(rpm < 10) { rpm = 10; }
long rp1000s = (rpm * (long)1000) / (long)60; // 1000秒あたりの回転数
long stepsPer1000Sec = rp1000s * stepsPerRotation; // 1000秒あたりのステップ数
long microSecPerStep = (long)1000000000 / stepsPer1000Sec; // 1ステップあたりのマイクロ秒
int ret = (int)microSecPerStep; // 型変換
return ret;
}
0 件のコメント:
コメントを投稿