我编写了以下代码来计算使用正交旋转编码器和Arduino Mega的直流电机的转速:
int N3 = 7; //N3 sur la L298N motor shield
int N4 = 8; //N4 sur la L298N motor shield
int ENB = 9; //ENB sur la L298N motor shield
int potPin = A0; //analog pin 0 sur la carte arduino
int valeurLu = 0; //valeur lu du potentiomètre
int valeur_a_ecrire = 0; //valeur à envoyer au moteur
int pin_A_encodeur = 3;
int etat_courant_encodeur = 0;
int etat_precedant_encodeur = 0;
void setup() {
attachInterrupt(digitalPinToInterrupt(3),updatePosition,CHANGE);
pinMode(N3, OUTPUT);
pinMode(N4, OUTPUT);
pinMode(ENB, OUTPUT);
pinMode(A0, INPUT);
pinMode(pin_A_encodeur, INPUT);
Serial.begin(9600);
}
void loop() {
valeurLu = analogRead(potPin);
valeur_a_ecrire = (255.0/1023.0)*valeurLu;
digitalWrite(N4, HIGH);
digitalWrite(N3, LOW);
analogWrite(ENB, valeur_a_ecrire);
etat_courant_encodeur = digitalRead(pin_A_encodeur);
Serial.print(valeur_a_ecrire);
Serial.print(" ");
Serial.println(etat_courant_encodeur);
}
我能够读取编码器发送的读取信息,但它只是一系列的1和0(11000111 ......等)。如何使用此信息计算电机的转速?我的编码器的分辨率为每转64个计数。在此先感谢有关如何解决此问题的任何帮助。
答案 0 :(得分:0)
由于您只是从编码器读取A引脚,每回合只能获得16次脉冲。
这是一种方法......
//...
#define SAMPLE_DELAY (1000) // this gets 1 reading per second.
// adjust the delay to fit your needs
#edfine PULSES_PER_TURN (32) // 32 state changes per turn on 1 line,
unsigned int pulseCount;
bool lastState;
unsigned int lastTime;
float rpm; // speed in turns/minute, doesn't have to be floating point.
void setup()
{
// ...
pinMode(pin_A_encodeur, INPUT);
lastState = digitalRead(pin_A_encodeur);
}
void loop()
{
bool curState = digitalRead(pin_A_encodeur);
if (curState != lastState)
{
++pulseCount;
lastState = curState;
}
if ((unsigned int)millis() - lastTime >= SAMPLE_DELAY)
{
rpm = (pulseCount * (60000.f / ((unsigned int)millis() - lastTime))) / PULSES_PER_TURN;
pulseCount = 0;
lastTime = (unsigned int)millis();
}
//...
}
铸造milis()的返回值是因为我们不需要millis计数器的所有32位计数到1000,节省了2个字节的内存。
通过玩SAMPLE_DELAY,您会注意到读数的稳定性和采样频率之间存在折衷。 SAMPLE_DELAY的最佳值取决于您的应用以及电机的速度范围。
结果取决于主循环中的其他内容。你的循环不应该有任何延迟(),opr你可能会错过一些脉冲。如果无法避免,则应在ISR中移动脉冲检测代码。
另一种方法:
//...
#define SAMPLE_DELAY (1000) // this gets 1 reading per second.
// adjust the delay to fit your needs
#define PULSES_PER_TURN (32) // 32 state changes per turn on 1 line,
volatile unsigned int pulseCount; // note the volatile keyword here.
unsigned int lastTime;
float rpm; // speed in turns/minute, doesn't have to be floating point.
void setup() {
// ...
pinMode(pin_A_encodeur, INPUT);
lastState = digitalRead(pin_A_encodeur);
attachInterrupt(digitalPinToInterrupt(pin_A_encodeur), onPulse, CHANGE);
}
void loop() {
if ((unsigned int)millis() - lastTime >= SAMPLE_DELAY)
{
unsigned int pulses;
noInterrupts();
pulses = pulseCount; // the atmega is 8 bits, you must disable interruts
pulseCount = 0; // to read/write 16 bit values accessed by ISR
interrupts(); // re-enable interrupts.
// 60000 milliseconds in 1 minute for rpms.
rpm = (pulses * (60000.f / ((unsigned int)millis() - lastTime))) / PULSES_PER_TURN;
lastTime = (unsigned int)millis();
}
//...
}
void onPulse() {
++pulseCount;
}
请注意,数字采样总会导致读数发生一些变化。请记住,如果您决定将RPM存储为整数,则必须使用unsigned long type
,包括每分钟的毫秒数60000ul
,以避免溢出。
另请注意,并非所有引脚都相同。只有一些可以链接到中断的引脚。请参阅arduino doc:https://www.arduino.cc/en/Reference/AttachInterrupt
答案 1 :(得分:0)
感谢更新和澄清,我已经能够在达到稳定状态后获得稳定的电机转速值。考虑到不可能从arduino IDE中将arduino数据写入文件,我决定在MATLAB中对编码器进行编程,将编码器数据写入文件,稍后我将对其进行解码,以确定车轮的RPM。安装在电机上(电机和车轮之间有一个100:1的变速箱)。
命令Arduino板的MATLAB代码:
clear;
clc;
close all;
a = arduino('COM5','Uno')
writeDigitalPin(a, 'D7', 1), writeDigitalPin(a, 'D8', 0)
writePWMDutyCycle(a,'D9',0.7)
%Create a file for storing simulation data
fID = fopen('DemoUnoVmatlab2.txt','w');
startTime = datetime('now');
try
while(1)
t = datetime('now') - startTime;
%Write simulation data to file
fprintf(fID, '%f\t%f\n', second(datenum(t)), double(readDigitalPin(a,'D2')));
end
fclose(fID);
catch
fclose(fID);
end
用于处理采集数据和计算角位置的MATLAB函数
function [] = counterVmatlab(signal_A,time)
count = 0;
previousState = 0;
angularPos = 0;
ppr = 32; % encoder resolution, 32 and NOT 64 because only channel A is used here (see encoder's data sheet)
gearRatio = 100;
results = fopen('resultsVmatlab.txt','w');
for i = 1:length(signal_A)
presentState = signal_A(i);
if presentState ~= previousState
count = count + 1;
previousState = presentState;
fprintf(results,'%f\t%f\t%f\t%f\n', count, i, angularPos, time(i)); % i ==> at what time did a change in state occur
angularPos = angularPos + 360/(ppr*gearRatio);
end
end
fclose(results);
通过绘制角位置和角速度的曲线图,我发现角速度在约5度/秒的稳定值附近变化(参见下面的附加屏幕截图)。考虑到我在12V直流电源上运行一个小电机,我预计角速度大约是360度/秒(这是通过观察电机转动可以观察到的)。所以我想知道我的上述解码算法是否良好?任何帮助将非常感激。
<强> GRAPH 强> Angular position and angular velocity