我就是不理解,修改的代碼爲什麼電機不執行。我對案例2的代碼按照我的邏輯就行了修改驗證。
試驗證明程序會一直卡在while 循環裏,而且步進電機沒有任何動作。使用while循環是想讓程序更快速的調用stepperX.run(),以此獲得更高的速度,而不是整個程序過一遍調用一次,本身就用的減速電機。速度太慢實際應用是不是很理想,尤其是手動模式,太慢了。
if (muoviX) {
motoreX.setSpeed(speedX);
stepperX.move(300);//相對運動300步,相對較短的時間,不會影響速度變化,只不過損失過渡順滑度
while(stepperX.distanceToGo() != 0){//如果相對運動沒有完成,將始終卡在次循環裏直到運動完成
stepperX.run();//電機運動一步
}
跳不出循環說明stepperX.distanceToGo() != 0始終爲真。
看到有的案例是
stepperX.moveTo(300);//相對運動300步,相對較短的時間,不會影響速度變化,只不過損失過渡順滑度
if (stepperX.distanceToGo() != 0){//如果相對運動沒有完成,將始終卡在次循環裏直到運動完成
stepperX.runToPosition();//電機運動一步
}
這個代碼是可行的。但是是絕對位置,到達位置之後電機不會在動了。
扒出源代碼看看:
從以下代碼可以整理出邏輯順序,
move()->moveTo()->computeNewSpeed()->distanceToGo()計算出相應速度加速度參數;
run()->runSpeed()->step()-step1()->setOutputPins()-電機運動最多一步,調用一次走一步。
runSpeed()函數內對當前位置進行變更;
目前來看,我的代碼邏輯上是通的。
第一步:
void AccelStepper::move(long relative)
{
moveTo(_currentPos + relative);//調用Moveto函數,目標位置爲現在位置+相對值
}
以上代碼計算出相對位置量對應的絕對位置,然後調用moveTo函數執行;
第二步:
void AccelStepper::moveTo(long absolute)
{
if (_targetPos != absolute)
{
_targetPos = absolute;
computeNewSpeed();
// compute new n?
}
}
以上函數,判斷給定的位置是否和現在的位置相等,如果不等就把現在的位置設置成目標位置,並進行速度計算;
速度計算見 第六步;
第三步:
long AccelStepper::distanceToGo()
{
return _targetPos - _currentPos;//返回值爲目標位置減去現在的位置,如果現在位置和目標位置一樣,則爲0;
}
此代碼返回目標位置與現在位置的差值;
第四步:
boolean AccelStepper::run()
{
if (runSpeed())
computeNewSpeed();
return _speed != 0.0 || distanceToGo() != 0;
}
此代碼如果速度沒有達到設定的速度就重新計算速度,返回值爲判斷式(如果速度沒到0並且現在位置沒到目標位置則返回0,否則返回1);
第五步:
boolean AccelStepper::runSpeed()
{
// Dont do anything unless we actually have a step interval
if (!_stepInterval)
return false;
unsigned long time = micros();
if (time - _lastStepTime >= _stepInterval)
{
if (_direction == DIRECTION_CW)
{
// Clockwise
_currentPos += 1;
}
else
{
// Anticlockwise
_currentPos -= 1;
}
step(_currentPos);
_lastStepTime = time; // Caution: does not account for costs in step()
return true;
}
else
{
return false;
}
}
第六步:
void AccelStepper::computeNewSpeed()
{
long distanceTo = distanceToGo(); // +ve is clockwise from curent location
long stepsToStop = (long)((_speed * _speed) / (2.0 * _acceleration)); // Equation 16
if (distanceTo == 0 && stepsToStop <= 1)
{
// We are at the target and its time to stop
_stepInterval = 0;
_speed = 0.0;
_n = 0;
return;
}
if (distanceTo > 0)
{
// We are anticlockwise from the target
// Need to go clockwise from here, maybe decelerate now
if (_n > 0)
{
// Currently accelerating, need to decel now? Or maybe going the wrong way?
if ((stepsToStop >= distanceTo) || _direction == DIRECTION_CCW)
_n = -stepsToStop; // Start deceleration
}
else if (_n < 0)
{
// Currently decelerating, need to accel again?
if ((stepsToStop < distanceTo) && _direction == DIRECTION_CW)
_n = -_n; // Start accceleration
}
}
else if (distanceTo < 0)
{
// We are clockwise from the target
// Need to go anticlockwise from here, maybe decelerate
if (_n > 0)
{
// Currently accelerating, need to decel now? Or maybe going the wrong way?
if ((stepsToStop >= -distanceTo) || _direction == DIRECTION_CW)
_n = -stepsToStop; // Start deceleration
}
else if (_n < 0)
{
// Currently decelerating, need to accel again?
if ((stepsToStop < -distanceTo) && _direction == DIRECTION_CCW)
_n = -_n; // Start accceleration
}
}
// Need to accelerate or decelerate
if (_n == 0)
{
// First step from stopped
_cn = _c0;
_direction = (distanceTo > 0) ? DIRECTION_CW : DIRECTION_CCW;
}
else
{
// Subsequent step. Works for accel (n is +_ve) and decel (n is -ve).
_cn = _cn - ((2.0 * _cn) / ((4.0 * _n) + 1)); // Equation 13
_cn = max(_cn, _cmin);
}
_n++;
_stepInterval = _cn;
_speed = 1000000.0 / _cn;
if (_direction == DIRECTION_CCW)
_speed = -_speed;
#if 0
Serial.println(_speed);
Serial.println(_acceleration);
Serial.println(_cn);
Serial.println(_c0);
Serial.println(_n);
Serial.println(_stepInterval);
Serial.println(distanceTo);
Serial.println(stepsToStop);
Serial.println("-----");
#endif
}
void AccelStepper::step(long step)
{
switch (_interface)
{
case FUNCTION:
step0(step);
break;
case DRIVER:
step1(step);
break;
case FULL2WIRE:
step2(step);
break;
case FULL3WIRE:
step3(step);
break;
case FULL4WIRE:
step4(step);
break;
case HALF3WIRE:
step6(step);
break;
case HALF4WIRE:
step8(step);
break;
}
}
void AccelStepper::setOutputPins(uint8_t mask)
{
uint8_t numpins = 2;
if (_interface == FULL4WIRE || _interface == HALF4WIRE)
numpins = 4;
else if (_interface == FULL3WIRE || _interface == HALF3WIRE)
numpins = 3;
uint8_t i;
for (i = 0; i < numpins; i++)
digitalWrite(_pin[i], (mask & (1 << i)) ? (HIGH ^ _pinInverted[i]) : (LOW ^ _pinInverted[i]));
}
void AccelStepper::step1(long step)
{
(void)(step); // Unused
// _pin[0] is step, _pin[1] is direction
setOutputPins(_direction ? 0b10 : 0b00); // Set direction first else get rogue pulses
setOutputPins(_direction ? 0b11 : 0b01); // step HIGH
// Caution 200ns setup time
// Delay the minimum allowed pulse width
delayMicroseconds(_minPulseWidth);
setOutputPins(_direction ? 0b10 : 0b00); // step LOW
}
/*
* 用Arduino和操縱桿控制馬達,不同的模擬值對應不同的速度值
*/
//Inclusione delle librerie 包含一下庫
#include <AccelStepper.h>
// 引腳定義
const int pinSwEnable = 2; //搖桿按鍵接線引腳
const int pinEnable = 8; //A4988驅動使能引腳定義
const int jX = A0; //搖桿X軸引腳定義
const int stepX = 3; //步進電機X脈衝輸出引腳
const int dirX = 5; //步進電機X方向控制引腳
long speedX, valX, mapX; //電機X相關變量
const int jY = A1; //搖桿Y軸引腳定義
const int stepY = 4; //步進電機Y脈衝輸出引腳
const int dirY = 6; //步進電機Y方向控制引腳
long speedY, valY, mapY; //電機X相關變量
//AccelStepper 庫使用的變量
const int maxSpeed = 1000; //Arduino UNO受晶振限制最大到4000
const int minSpeed = 0; //電機最小速度
const float accelerazione = 50.0; //加速度
const int treshold = 30; //柵域
long tresholdUp, tresholdDown; //變量
boolean abilitato, muoviX, muoviY, enable; //移動變量
//AccelStepper庫電機定義
AccelStepper motoreX(AccelStepper::DRIVER, stepX, dirX);
AccelStepper motoreY(AccelStepper::DRIVER, stepY, dirY);
void setup() {
//變量初始化
speedX = speedY = 0;
enable = false;//電機可工作
//引腳模式定義
pinMode(ledEnable, OUTPUT);
pinMode(pinEnable, OUTPUT);
pinMode(pinSwEnable, INPUT_PULLUP); //按鍵定義輸入,並置高
digitalWrite(ledEnable, enable);
digitalWrite(pinEnable, !enable); //A4988拉高,步進電機不工作
//確定搖桿的位置值
tresholdDown = (maxSpeed / 2) - treshold;//之前treshold賦值30 470
tresholdUp = (maxSpeed / 2) + treshold; //530
//配置步進電機參數
motoreX.setMaxSpeed(maxSpeed);//設置最大速度
motoreX.setSpeed(minSpeed);//設置運行速度
motoreX.setAcceleration(accelerazione);//設置加速度
motoreY.setMaxSpeed(maxSpeed);
motoreY.setSpeed(minSpeed);
motoreY.setAcceleration(accelerazione);
}
void loop() {
checkEnable();
digitalWrite(ledEnable, enable); //控制LED
digitalWrite(pinEnable, !enable); //控制電機驅動使能端
//獲取搖桿兩個方向的模擬變量值
valX = analogRead(jX);
valY = analogRead(jY);
//對從搖桿上獲取的值進行速度變換
mapX = map(valX, 0, 1023, minSpeed, maxSpeed);
mapY = map(valY, 0, 1023, minSpeed, maxSpeed);
pilotaMotori(mapX, mapY);
}
void pilotaMotori(long mapX, long mapY) {
if (mapX <= tresholdDown) {
//變換的X速度小於470
speedX = -map(mapX, tresholdDown, minSpeed, minSpeed, maxSpeed);//小於470爲負方向
muoviX = true;
} else if (mapX >= tresholdUp) {
//變換的X速度大於530
speedX = map(mapX, maxSpeed, tresholdUp, maxSpeed, minSpeed);//大於530爲正方向
muoviX = true;
} else {
//電機不動
speedX = 0;
muoviX = false;
}
if (mapY <= tresholdDown) {
speedY = -map(mapY, tresholdDown, minSpeed, minSpeed, maxSpeed);
muoviY = true;
} else if (mapY >= tresholdUp) {
speedY = map(mapY, maxSpeed, tresholdUp, maxSpeed, minSpeed);
muoviY = true;
} else {
speedY = 0;
muoviY = false;
}
if (muoviX) {
motoreX.setSpeed(speedX);
stepperX.move(300);//相對運動300步,相對較短的時間,不會影響速度變化,只不過損失過渡順滑度
while(stepperX.distanceToGo() != 0){//如果相對運動沒有完成,將始終卡在次循環裏直到運動完成
stepperX.run();//電機運動一步
}
motoreX.run();
} else {
motoreX.stop();
}
if (muoviY) {
motoreY.setSpeed(speedY);
motoreY.run();
} else {
motoreY.stop();
}
}
void checkEnable() {//按鍵檢測
if (digitalRead(pinSwEnable)==0) {
enable = !enable;
}
}
stepperX.move(300);
while(stepperX.distanceToGo() != 0){
stepperX.run();
}
爲什麼電機會不運動。設計了以下代碼進行驗證
#include <AccelStepper.h>
#define SW 2
int n=0;
// Define a stepper and the pins it will use
AccelStepper stepper; // Defaults to AccelStepper::FULL4WIRE (4 pins) on 2, 3, 4, 5
void setup()
{
pinMode(SW,INPUT);
digitalWrite(SW,HIGH);
stepper.setMaxSpeed(3000);
stepper.setAcceleration(50);
Serial.begin(9600);
}
void loop()
{
if(digitalRead(SW) == 0){
stepper.move(300);}
while (stepper.distanceToGo() != 0)
{
// Random change to speed, position and acceleration
// Make sure we dont get 0 speed or accelerations
delay(100);
n=stepper.distanceToGo();
Serial.println("the internal distance remain steps:");
Serial.println(n);
stepper.run();
}
Serial.println("the external distance remain steps:");
Serial.println(n);
}
通過串口檢測證明可以運行,電機不轉的原因可能是因爲脈衝的頻率太高了,設置的加速度與電機的電器特性不符,需要對最大速度和加速度等參數進行調試。
run()函數需要相對距離,如果現在的位置和目標位置一樣是不會運行的。它將通過距離來計算何時該加速何時該減速;