2

シリアル経由でarduinoと通信するためのC++コードをいくつか作成しました。サインとコサインを使用して2つのサーボモーターを発振させようとしますが、データをスキップしています。なぜこれが起こっているのかわかりません。私はシリアルのものにtermios.hを使用しています。C ++からの出力は、「V180H90」のようなものです。つまり、Vertical 180、Horizo​​ntal 90です。以前はfstreamとusleep()を使用してデータを送信していましたが、機能していましたが、任意の数だけ遅延させるよりも優れた方法を使用したいと思います。 。

ヘルプやガイダンスをありがとう。

私のarduinoコード

#include <Servo.h>
typedef enum { NONE, GOT_V, GOT_H } states;
states state = NONE;
Servo pan;
Servo tilt;
int laser = 11;
unsigned int currentValue;

int v_pan = 0;
int v_tilt = 0;

void setup()
{
  pan.attach(10);
  tilt.attach(9);

  Serial.begin(9600);
  state = NONE;
}

void processVertical(const unsigned int value)
{
  Serial.print("Vertical = ");
  Serial.println(value);
  int result = 1300 + (value - 90) * 2;
  //Serial.println(result);
  tilt.writeMicroseconds(result);
}

void processHorizontal(const unsigned int value)
{
  Serial.print("Horizontal = ");
  Serial.println(value);
  int result = 1500 + (value - 180) * 1;
  //Serial.println(result);
  pan.writeMicroseconds(result);
}

void handlePreviousState()
{
  switch(state)
  {
    case GOT_V:
      processVertical(currentValue);
      break;
    case GOT_H:
      processHorizontal(currentValue);
      break;
  }
  currentValue = 0;
}

void processIncomingByte (const byte c)
{
  if (isdigit(c))
  {
    currentValue *=10;
    currentValue += c - '0';
  }
  else
  {
    handlePreviousState();

    switch (c)
    {
      case 'V':
        state = GOT_V;
        break;
      case 'H':
        state = GOT_H;
        break;
      default:
        state = NONE;
        break;
    }
  }
}

void loop()
{
  if(Serial.available() > 0) 
  { 
    processIncomingByte(Serial.read());
  } 
  digitalWrite(laser, HIGH);
}

//check out writeMicroseconds

私のC++コード

// Program for sending data to serial

#include <iostream>
#include <sstream>
#include <string>
#include <termios.h>
#include <fcntl.h>
#include <math.h>

using namespace std;

//open serial port
int openPort(string path)
{
  int fd; //file descriptor for port
  fd = open(path.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
  if (fd == -1)
    cerr << "Cannot open port" << endl;
  else
    fcntl(fd, F_SETFL, 0);
  return (fd);
}

//set options for an open serial port
void setOptions(int fd)
{
  struct termios options;
  tcgetattr(fd, &options);
  cfsetispeed(&options, B9600);
  cfsetospeed(&options, B9600);

  //No parity 8N1
  options.c_cflag &= ~PARENB;
  options.c_cflag &= ~CSTOPB;
  options.c_cflag &= ~CSIZE;
  options.c_cflag |= CS8;

  //No flow control
  options.c_cflag &= ~CRTSCTS;

  //Turn off s/w flow control
  options.c_iflag &= ~(IXON | IXOFF | IXANY);

  //Turn on read and ignore ctrl lines
  options.c_cflag |= (CLOCAL | CREAD); 

  if( tcsetattr(fd, TCSANOW, &options) < 0) { 
    cerr << "Could not set attributes" << endl; 
  }
}

//write to serial port
void writePort(int fd, string data)
{
  int n = write(fd, data.c_str(), 9);
  if (n < 0)
    cerr << "Cannot write to port" << endl;
}

int main() {
  string path = "/dev/tty.usbmodemfd131";
  //string path = "/dev/tty.usbmodemfa141";
  int fd = openPort(path);
  setOptions(fd);

  stringstream ss;
  string output;
  unsigned short vertical = 0;
  unsigned short horizontal = 0; 
  unsigned short freq = 10;

  for(int i = 0; i < 360; i++) {
    vertical = ((cos(i * freq * ((M_PI)/180))) + 1) * 90;
    horizontal = ((sin(i * freq * ((M_PI)/180))) + 1) * 90;
    ss << "V" << vertical << "H" << horizontal << endl; 
    output = ss.str();
    ss.str("");
    writePort(fd, output);
//    cout << output; //DEBUG
  }

  close(fd);
  return 0;
}
4

4 に答える 4

2

新しいモードを受け取った直後に前の状態(handlePreviousState)を処理しているため、デバイス内の「processIncomingByte」ループで速度の問題が発生した可能性があります。

この問題は、値データバイトがPCから継続的に着信しているときに、対応する関数でSerial.printを実行することによって発生する可能性があります。シリアル印刷は、マイクロコントローラーロジックでは比較的遅いプロセスです。

私はArduinoハードウェアに精通していませんが、一部のローエンドのマイクロコントローラーボードはビットバンギング方式を使用してソフトウェアシリアルインターフェイスを実行しているため、送信すると受信は完全に停止します。これを確認するには、Serial.printにコメントを付けて、役立つかどうかを確認します。

とにかく、FIFOバッファがたくさんあるデバイスにハードウェアシリアルインターフェイスがない限り、着信データストリームの途中で長時間の処理を行うことは常に問題があります。

この問題の適切な方法は、最初にバッファ内のメッセージ全体を受信し、次にメッセージ終了マーカーが受信されたときにのみメッセージを処理することです。たとえば、[V180H90]のように[]ペアの中にメッセージを挿入します。「[」でバッファをリセットし、「]」を受け取った後にバッファを処理します。バイトをバッファに収集するときは、バッファオーバーフローもチェックしてください。

于 2013-02-05T14:34:33.053 に答える
1

データをポートのスロートに押し込むだけの場合は、発火しないように最善を尽くしますが、余分なデータは送信されません。結局のところ、ポートは有限の速度で動作し、かなり制限されたダンプデバイスです。

したがって、文字をポートに送信する前に、ポートのステータスをチェックして、送信するデータの別の文字を実際に受け入れる準備ができているかどうかを確認する必要があります。一部のシリアルポートは、無駄なステータスポーリングを回避するために、より多くのデータを取得できる場合でも割り込みを生成できます。

また、2つのデバイスの2つのシリアルポートを追加の非データ信号のペア(RTSおよびCTS)に接続して、受信側がさらにデータを受信する準備ができているかどうかを示すことができる場合もあります。それらを接続していて、デバイスがそれらを使用して準備ができていることを示す場合、プログラムはデバイスの状態CTSも考慮に入れる必要があります。

于 2013-02-05T06:49:59.903 に答える
1

明らかに、デバイスはシリアルポート経由で送信するよりも遅いデータの読み取り/処理を行います。私はここでいくつかの可能な解決策を見ます:

1)フロー制御を実装し、ブロッキングモードでシリアルポートを介してデータを送信します。送信後も待機する必要がありますが、デバイスがデータを読み取って処理するために必要な時間だけです。

2)双方向通信を実装して、デバイスがデータを受け入れる準備ができていることを示す確認メッセージ(つまり、任意の単一のASCII記号)を送信するようにします。

3)コードを2つの並列部分に分割します。つまり、メインループ(またはISR)はシリアルポートからデータを読み取り、リングバッファに格納するだけです。別のループは、リングバッファをポーリングし、そこからデータを取得/処理します。利用可能ないくつかのデータ。これは、2つの別個のスレッド(またはスレッドとISR)が必要であり、リングバッファーを同時アクセスから保護する必要があるため、3つのソリューションの中で最も難しいソリューションですが、最も強力で柔軟性があります。

于 2013-02-05T07:01:56.147 に答える
0

シリアルデバイスへのデータの書き込みが速すぎて、デバイス自体が、デバイスの反対側でデータを読み戻すよりも速くデータを吐き出している。

これに対処する正しい方法は、シリアルデバイスへの書き込み速度を調整して、データで溢れるのを防ぐことです。

于 2013-02-05T06:19:25.443 に答える