0

それで、私はロボットに改造しようとしているこの古い電動車椅子を持っています。元のモーター ドライバーを sabertooth 2x12 に交換し、Arduino micro を使用して対話しています。モーターのシャフトがぐるぐる回っているので裏側に磁石とホール効果センサーを付けてロータリーエンコーダーとして機能させました。私の現在の目標は、ロボットに一定量の足を前進させてから停止するように指示できるようにすることです。これを直線的に行うコードを書きましたが、うまくいきませんでした。その後、割り込みについて学びましたが、それはまさに私が必要としているもののように思えました。それで私はそれを試してみましたが、いくつかの異なるレベルで物事がうまくいきませんでした。

レベル 1: モーターを適切に駆動することができたようには見えませんでした。ループ内でモーターをオンにするコマンドを実行したり、if ステートメントを実行したりするたびに、散発的かつ予測不可能な動きをするように思えます。

レベル 2: 割り込みが自分自身を中断しているように感じます。ホイールが前進するのを止めるために設定したものが、ロータリー エンコーダーの 14 クリックを前方に移動するように指示できるため、一方のホイールは 1000 クリックを超えて移動し続け、もう一方のホイールは 1000 クリックを超えて移動し続けます。止まる

レベル 3: コード ウィンドウをアップロードすると Arduino の認識が停止し、リセット ボタンを押して点滅スケッチをアップロードするまでドライバーが壊れてしまい、割り込みを間違って配置したと思います。次に、割り込みの 1 つを削除すると、正常にアップロードされます。

レベル 4: モーターがオンになっていると、ホール効果センサーが正しく機能しないようです。数秒でクリック数が 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;
}
4

1 に答える 1

1
  1. interrupt()and nointerrupt()(またはcli()and ) を使用しないでくださいsei()。タイマーとシリアル割り込みが停止し、多くのものが壊れます。カウント変数を 0 に設定するか、detachInterrupt と attachInterrupt を使用します。

  2. 割り込み内で使用される変数および通常の実行フローは、として宣言する必要がありvolatileます。したがって、それらを次のように宣言しますvolatile int RclickNum=0;

  3. デフォルトでは、割り込み内で他の割り込みは実行されないため、割り込みは高速に実行する必要があります。

  4. 割り込み内でシリアルを使用しないでください。シリアル バッファがいっぱいの場合、Serial.flush() が呼び出され、書き込まれたバイトのシリアル割り込みが待機されますが、割り込みの内部にすでにあるため、コードが永久にハングするデッド ロックが発生します。

  5. 「移動」関数の実行にはかなりの時間がかかるため、複数のコマンドがシリアルに到着した場合、それらは読み取られるまでバッファのノードに残ります。したがって、ターミナルで「asd」と「e」を入力すると、ロボットが左、後方、右に移動し、停止することがわかります (はい、実際には停止機能は役に立たないため、「移動」機能は「つまり、終了するまで返されないため、シリアルのバッファが処理されるまで loop() コード (および "e" の読み取り) は実行されません。

于 2014-03-31T11:41:26.090 に答える