所以我有一辆旧的电动轮椅,我正试图把它转换成机器人。我用剑齿虎2x12替换了原来的电机驱动器,我正在使用Arduino micro与它交谈。电机轴一直抛出,所以我在背面安装了磁铁和霍尔效应传感器,以充当旋转编码器。我目前的目标是能够告诉机器人向前移动一定数量的脚然后停止。我写了一些代码来线性执行此操作,但这效果不佳。然后我了解了中断,这听起来正是我所需要的。所以我尝试了一下,事情在几个不同的层面上都出了问题。
第一级:我似乎从来没有能够正确驱动电机,似乎任何时候我都会在循环中发出打开它们的命令,或者如果他们决定做他们想做的事并偶尔和不可预测地移动
第二级:我觉得中断正在打断自己和我设置的东西来阻止轮子向前移动,因为我可以告诉它向前移动 14 次旋转编码器点击,一个轮子将继续移动超过 1000 次点击,而另一个停止
第三级:有几次我想我把我的中断放错了,因为当我上传代码窗口时,它会停止识别 Arduino,我的驱动程序会中断,直到我在按下重置按钮后上传闪烁草图,这也重新加载并修复了我的驱动程序。然后,如果我删除了一个中断,它将正常上传。
第四级:当电机打开时,我的霍尔效应传感器似乎无法正常工作。他们倾向于在几秒钟内从 1 次点击跃升到 200 次点击。这反过来又淹没了我的串行端口并使Arduino ide崩溃。
因此,正如您所看到的,系统中的某个地方存在一些缺陷,无论是硬件还是软件,我都不知道。我是否以正确的方式接近这一点,或者是否有一些我不知道的Arduino秘密会让我的生活更轻松?如果我正在接近这个权利,你能看看我下面的代码,看看我做错了什么。
#include <Servo.h>//the motor driver uses this library
Servo LEFT, RIGHT;//left wheel right wheel
int RclickNum=0;//used for the rotory encoder
int LclickNum=0;//these are the number of "clicks" each wheel has moved
int D =115;//Drive
int R =70;//Reverse
int B =90;//Break
int Linterrupt = 1;//these are the interrupt numbers. 0 = pin 3 and 1 = pin 2
int Rinterrupt = 0;
int clickConvert = 7;// how many rotery encoder clicks equal a foot
void setup()
{
Serial.begin(9600); //starting serial communication
LEFT.attach( 9, 1000, 2000);//attaching the motor controller that is acting like a servo
RIGHT.attach(10, 1000, 2000);
attachInterrupt(Linterrupt, LclickCounter, FALLING);//attaching the rotory encoders as interrupts that will
attachInterrupt(Rinterrupt, RclickCounter, FALLING);//trip when the encoder pins go from high to low
}
void loop()
{//This is for controling the robot using the standard wasd format
int input= Serial.read();
if(input == 'a')
left(2);
if(input == 'd')
right(2);
if(input == 'w')
forward(2);
if(input == 's')
backward(2);
if(input == 'e')
STOP();
}
void forward(int feet)//this is called when w is sent threw the serial port and is where i am testing all of my code.
{
interrupts(); //turn on the interrupts
while(RclickNum < feet * clickConvert || LclickNum < feet * clickConvert)// while either the left or right wheel hasnt made it to the desired distance
{
if(RclickNum < feet * clickConvert)//check if the right wheel has gone the distance
RIGHT.write(D); //make the right wheel move
else
RIGHT.write(B);//stop the right wheel
if(LclickNum < feet * clickConvert)
LEFT.write(D);
else
LEFT.write(B);
}
noInterrupts();//stop the interrupts
resetCount();//set the click counters back to zero
}
//once i have the forward function working i will implament it through out the other functions
//----------------------------------------------------------------------
void backward(int feet)
{
RIGHT.write(R);
LEFT.write(R);
}
void left(int feet)
{
RIGHT.write(D);
LEFT.write(R);
}
void right(int feet)
{
RIGHT.write(R);
LEFT.write(D);
}
void STOP()
{
resetCount();
RIGHT.write(B);
LEFT.write(B);
}
void LclickCounter()//this is called by the left encoder interrupt
{
LclickNum++;
Serial.print("L");
Serial.println(LclickNum);
}
void RclickCounter()//this is called by the right encoder interrupt
{
RclickNum++;
M Serial.print("R");
Serial.println(RclickNum);
}
void resetCount()
{
RclickNum=0;
LclickNum=0;
}
-
不要使用
interrupt()
和nointerrupt()
(或cli()
和sei()
),因为它们会停止计时器和串行中断,破坏很多东西。只需将计数变量设置为 0 或使用 detachInterrupt 和 attachInterrupt。 -
中断和正常执行流内部使用的变量应声明为
volatile
,或者它们的值 my 未同步。所以像volatile int RclickNum=0;
一样声明它们
中断 应该快速执行,因为默认情况下,其他中断在中断内不会执行。
切勿使用串行内部中断; 如果串行缓冲区已满,它将调用 Serial.flush(),这将等待写入字节的串行中断,但因为你在 alreadi 内中断永远不会发生......死锁又名你的代码永远挂起!
因为你的"移动"函数需要相当长的时间才能执行,如果多个命令到达串行,Thay将保持ISNODE缓冲区,直到被读取。因此,如果您在终端中编写"asd"然后输入"e",您将看到机器人向左,向后,向右,停止(是的,实际上停止函数没有用,因为它什么都不做,因为您的"移动"函数正在"阻塞",这意味着它们直到它们结束才会返回,因此loop()代码(和"e"的读取)在串行缓冲区被处理之前不会执行。