要控制两台步进电机同步进行运转,即同时起步,同时加速,同时到达最大速度,同时减速,最后同时停止。
这是要有一定的算法的:
假如B1电机所走的路程是B2的n倍,在同时起步的前提下,v1=n*v2,a1=n*a2, 才能保证以上的同步结果。
本文程序是在太极创客程序的基础上对其修改后的,接线方式完全保持不变。主要的修改如下:
1, data(电机指令参数)和 stepperNum(控制电机编号) 两个变量改为数组;
2,data(电机指令参数)和 stepperNum(控制电机编号) 两个变量由int改为long int;
3, runUserCmd()例程中if语句逻辑关系的修改。
在输入以下命令后,可以看到两个步进电机的运行始终保持同步:
a100,20
x500,100
m10240,2048
/* Arduino通过AccelStepper库控制28BYJ-48步进电机示例程序-2
by 太极创客(www.taichi-maker.com)
可通过Arduino IDE 串口监视器输入电机指令
本程序旨在演示move/moveTo/runToNewPosition区别 (两个28BYJ-48电机演示)
如需获得本示例程序详细电路信息以及如何使用Arduino控制电机的更多知识,请参考太极创客网站:
http://www.taichi-maker.com/homepage/reference-index/arduino-library-index/accelstepper-library/
* 电机指令列表
* 'o' 利用currentPosition获取当前电机输出轴位置并通过串口监视器输出该信息
* 'v' 利用moveTo函数使电机运行到用户指定坐标位置,moveTo函数不会“block”程序。
* 例:v1024 - 将电机moveTo到1024位置
* 'm' 利用move函数使电机运行相应步数。move函数不会“block”程序。
* 例:m1024 - 使电机运行1024步
* 'r' 利用runToNewPosition函数让电机运行到用户指定坐标位置。runToNewPosition函数功能
* 与moveTo函数功能基本相同。唯一区别是runToNewPosition函数将“block”程序运行。
* 即电机没有到达目标位置前,Arduino将不会继续执行后续程序内容。
* 这一点很像Arduino官方Stepper库中的step函数。
* 例:r1024 - 将电机runToNewPosition到1024位置。Arduino在电机达到1024位置前将停止
* 其它程序任务的执行。
* 's' 利用setCurrentPosition函数设置当前位置为用户指定位置值。
* 例:s0 - 设置当前位置为0
* 'a' 利用setAcceleration函数设置加速度
* 例:a100 - 设置电机运行的加速度为100
* 'x' 利用setMaxSpeed函数设置最大速度
* 例:x500 - 设置电机运行的最大速度为500
* 'd' 用户通过此指令可指定哪一个电机进行工作
* 例:d1 一号电机工作,d2 二号电机工作, d0 两个电机同时工作
*/
#include "AccelStepper.h"
// 电机步进方式定义
#define FULLSTEP 4 //全步进参数
#define HALFSTEP 8 //半步进参数
// 定义步进电机引脚
#define motor1Pin1 8 // 一号28BYJ48连接的ULN2003电机驱动板引脚 in1
#define motor1Pin2 9 // 一号28BYJ48连接的ULN2003电机驱动板引脚 in2
#define motor1Pin3 10 // 一号28BYJ48连接的ULN2003电机驱动板引脚 in3
#define motor1Pin4 11 // 一号28BYJ48连接的ULN2003电机驱动板引脚 in4
#define motor2Pin1 4 // 二号28BYJ48连接的ULN2003电机驱动板引脚 in1
#define motor2Pin2 5 // 二号28BYJ48连接的ULN2003电机驱动板引脚 in2
#define motor2Pin3 6 // 二号28BYJ48连接的ULN2003电机驱动板引脚 in3
#define motor2Pin4 7 // 二号28BYJ48连接的ULN2003电机驱动板引脚 in4
// 定义两个步进电机对象
// 定义中ULN2003驱动板引脚顺序为 in1-in3-in2-in4
// 1号电机设置为全步进运行,2号电机设置为全步进运行
AccelStepper stepper1(FULLSTEP, motor1Pin1, motor1Pin3, motor1Pin2, motor1Pin4);
AccelStepper stepper2(FULLSTEP, motor2Pin1, motor2Pin3, motor2Pin2, motor2Pin4);
char cmd; //电机指令字符
long int data[2]; //电机指令参数
long int stepperNum[2]={1,1}; //控制电机编号
void setup()
{
stepper1.setMaxSpeed(500.0); // 1号电机最大速度500
stepper1.setAcceleration(50.0); // 1号电机加速度50.0
stepper2.setMaxSpeed(500.0); // 2号电机最大速度500
stepper2.setAcceleration(50.0); // 2号电机加速度50.0
Serial.begin(9600);
Serial.println(F("++++++++++++++++++++++++++++++++++"));
Serial.println(F("+ Taichi-Maker AccelStepper Demo +"));
Serial.println(F("+ www.taichi-maker.com +"));
Serial.println(F("++++++++++++++++++++++++++++++++++"));
Serial.println(F(""));
Serial.println(F("Please input motor command:"));
}
void loop(){
if (Serial.available()) { // 检查串口缓存是否有数据等待传输
cmd = Serial.read(); // 获取电机指令中指令信息
Serial.print(F("cmd = "));
Serial.print(cmd);
Serial.print(F(" : "));
data[0] = Serial.parseInt(); // 获取电机指令中参数信息
data[1] = Serial.parseInt(); // 获取电机指令中参数信息
Serial.print(F("data = "));
Serial.print(data[0]);
Serial.print(",");
Serial.print(data[1]);
Serial.println(F(""));
runUsrCmd();
}
stepper1.run();
stepper2.run();
}
void runUsrCmd(){
switch(cmd){
case 'o': //利用currentPosition获取当前电机输出轴位置并通过串口监视器输出该信息
Serial.print(F("stepper1 Position: "));
Serial.println(stepper1.currentPosition());
Serial.print(F("stepper2 Position: "));
Serial.println(stepper2.currentPosition());
Serial.println(F("Current Running Motor: "));
if (stepperNum[0] == 1) {
Serial.println(F("Motor# 0"));
}
if (stepperNum[1] == 1) {
Serial.println(F("Motor# 1"));
}
break;
case 'v': //利用moveTo函数使电机运行到用户指定坐标位置,moveTo函数不会“block”程序。
if (stepperNum[0] == 1){
Serial.print(F("Motor1 'moveTo' ")); Serial.println(data[0]);
stepper1.moveTo(data[0]);
}
if (stepperNum[1] == 1){
Serial.print(F("Motor2 'moveTo' ")); Serial.println(data[1]);
stepper2.moveTo(data[1]);
}
break;
case 'm': // 利用move函数使电机运行相应步数。move函数不会“block”程序。
if (stepperNum[0] == 1){
Serial.print(F("Motor1 'move' ")); Serial.println(data[0]);
stepper1.move(data[0]);
}
if (stepperNum[1] == 1){
Serial.print(F("Motor2 'move' ")); Serial.println(data[1]);
stepper2.move(data[1]);
}
break;
case 'r': //利用runToNewPosition函数让电机运行到用户指定位置值。
if (stepperNum[0] == 1){
Serial.print(F("Motor1 'runToNewPosition' "));
Serial.println(data[0]);
stepper1.runToNewPosition(data[0]);
}
if (stepperNum[1] == 1){
Serial.print(F("Motor2 'runToNewPosition' "));
Serial.println(data[1]);
stepper2.runToNewPosition(data[1]);
}
break;
case 's': //利用setCurrentPosition函数设置当前位置为用户指定位置值。
if (stepperNum[0] == 1){
Serial.print(F("Set stepper1 Current Position to "));
Serial.println(data[0]);
stepper1.setCurrentPosition(data[0]);
}
if (stepperNum[1] == 1){
Serial.print(F("Set stepper2 Current Position to "));
Serial.println(data[1]);
stepper2.setCurrentPosition(data[1]);
}
break;
case 'a': //利用setAcceleration函数设置加速度
if (stepperNum[0] == 1){
Serial.print(F("Motor1 'setAcceleration' "));
Serial.println(data[0]);
stepper1.setAcceleration(data[0]);
}
if (stepperNum[1] == 1){
Serial.print(F("Motor2 'setAcceleration' "));
Serial.println(data[1]);
stepper2.setAcceleration(data[1]);
}
break;
case 'x': //利用setMaxSpeed函数设置最大速度
if (stepperNum[0] == 1){
Serial.print(F("Motor1 'setMaxSpeed' "));
Serial.println(data[0]);
stepper1.setMaxSpeed(data[0]);
}
if (stepperNum[1] == 1){
Serial.print(F("Motor2 'setMaxSpeed' "));
Serial.println(data[1]);
stepper2.setMaxSpeed(data[1]);
}
break;
case 'd': //用户通过此指令可指定哪一个电机进行工作
if ( data[0] + data[1] == 1 ){
stepperNum[0] = data[0];
stepperNum[1] = data[1];
Serial.print(F("Running Motor ")); Serial.println((data[0]==1)?(data[0]):(data[1]));
}
if (data[0] + data[1] == 2){
stepperNum[0] = data[0];
stepperNum[1] = data[1];
Serial.println(F("Running Both Motors "));
} else {
Serial.print(F("Motor Number Wrong."));
}
break;
default: // 未知指令
Serial.println(F("Unknown Command"));
}
}