Raspberry Pi で実行され、Pi のシリアル ポートを使用して Arduino と対話するプログラムを開発しています。
私のアーキテクチャは次のとおりです。PiはPanStamp(Arduino +ワイヤレストランシーバー)に接続され、データをワイヤレスで送信するSatellite(いくつかのセンサーを備えたPanStamp)があります。Pi はサテライトをアクティブ化および非アクティブ化できます。衛星は毎秒約 5 回データを送信し、Pi に接続された PanStamp はこのデータを受信し、シリアル ポートを使用して送信します。毎秒、Pi の PanStamp もいくつかのセンサーの読み取り値を送信します。
そのために、Qt フレームワーク、qextserialport (Qt のシグナル/スロットを実装するシリアル ポート ライブラリ) wiriginpi を使用して、GPIO といくつかの TCP および UDP ソケットを制御し、インターネット経由でデータを送信しています。
衛星がデータを送信しているときは、すべてがうまく機能しているようです。
しかし、サテライトをオフにすると、プログラム全体がかなり遅くなります。2秒おきくらいのデータしか出てこない… 通常は1秒おきに受信するはずです(PanStampがタイミングよくデータを送ってくれています、オシロスコープで確認しました)。
データと一緒に送信されたパケット数があり、失われたパケットはありません。つまり、一種のバッファか、データ フローを押さえている何かのように見えます。
最も奇妙なことは、衛星を再びオンにすると (「高速」データ フロー)、すべてがバッファリングされ、ゆっくりと処理されているように、Pi が「データのバースト」を示すことです。バストの大きさも、衛星がオフだった時間に比例しているように見えます。
何が起こっているのか/どうすればテストできるのか、誰かが知っていますか?
いくつかのコード:
シリアル ポートの初期化:
/* Initialize Serial Port to talk with PanStamp */
this->port = new QextSerialPort(portName, QextSerialPort::EventDriven);
port->setBaudRate(BAUD9600);
port->setFlowControl(FLOW_OFF);
port->setParity(PAR_NONE);
port->setDataBits(DATA_8);
port->setStopBits(STOP_1);
if (port->open(QIODevice::ReadWrite) == true)
{
/* Connect the arriving data signal with the incoming data function */
connect(port, SIGNAL(readyRead()), this, SLOT(incoming_data()));
/* Connect state change signal with its function */
connect(port, SIGNAL(dsrChanged(bool)), this, SLOT(onDsrChanged(bool)));
/* Debug */
qDebug() << "listening for data on" << port->portName();
}
else
{
qDebug() << "device failed to open:" << port->errorString();
exit(1);
}
関数 incoming_data() (読み取るデータがあるたびに呼び出されます):
/**
* @brief SerialHandler::incoming_data
*
* It is called every time that a byte is received.
*
* It is responable to syncronize with the wireless link
* and call store_incoming_data with the right data.
*
* To syncronize it waits for two 0xBA, when it happens
* get_data is set to true. The next byte is the data size.
*
* The function waits to all data arrive, read it and pass it
* to store_incoming_data that parses it and sore on memory/disk.
*
*/
void SerialHandler::incoming_data()
{
QByteArray bytes;
unsigned char b;
int i;
/* Wait for sync condition */
if(!get_data)
{
debug_msg(".", port->bytesAvailable());
fflush(stderr);
if(last_byte == 0xBA)
{
bytes = port->read(1);
b = (unsigned char) bytes.at(0);
if(b == 0xBA)
{
get_data = true;
return;
}
else
last_byte = b;
}
else
{
bytes = port->read(1);
b = bytes.at(0);
fflush(stdout);
last_byte = b;
}
}
else
{
debug_msg(",");
/* Read the data size */
if(port->bytesAvailable() && (data_size < 0))
{
bytes = port->read(1);
data_size = (int) bytes.at(0);
debug_msg("Size: %i -> %02X\n", data_size, (unsigned char) data_size);
}
fflush(stderr);
/* Read data and call store_incoming_data */
if(port->bytesAvailable() >= data_size)
{
bytes = port->read(data_size);
if(data_size == 0x34)
store_incoming_stellite_data(bytes);
else
{
if(bytes.at(0) == HUB_DATA)
store_incoming_hub_data(bytes);
else
{
printf("data_size: %i\tDebug panStamp data: ", data_size);
for(i = 0; i < bytes.size(); i++)
printf("[%02X]", (unsigned char) bytes.at(i));
printf("\n");
}
fflush(stdout);
}
get_data = false;
last_byte = 0;
data_size = -1;
fflush(stderr);
}
}
}
他の関数とデータ構造体は次のとおりです。
/* ========================================== Data Types ======================================= */
typedef unsigned char byte;
typedef union _float_byte
{
unsigned char asByte[4];
float asFloat;
} float_byte;
typedef union _int_byte
{
unsigned char asByte[2];
short int asInt;
} int_byte;
typedef union _uint_byte
{
unsigned char asByte[4];
unsigned int asUInt;
} uint_byte;
typedef struct _stellite_data
{
QTime piTime;
float_byte x0, y0, z0;
float_byte x1, y1, z1;
float_byte temp0, temp1;
float_byte pressure0;
float_byte pressure1;
float_byte pressure2;
uint_byte time_stamp;
int_byte packet_count;
QByteArray bytes;
byte sender;
byte status_byte;
} satellite_data;
typedef struct _hub_data
{
QTime piTime;
float_byte altitude;
byte status_byte;
QByteArray bytes;
uint_byte packet_count;
byte power_sat0;
byte power_sat1;
byte hack_hd0;
byte hack_hd1;
byte solenoid0;
byte solenoid1;
byte webcam;
} hub_data;
/* ========================================== END Data Types ======================================= */
/**
* @brief SerialHandler::store_incoming_hub_data
*
* Store Hub's data.
*
* Packet description:
* +---------------------+-----------------+
* | Altitude_Command | Altitude (float)|
* | (1 byte) | (4 byts) |
* +---------------------+-----------------+
*
* @param data Data to be stored
*/
void SerialHandler::store_incoming_hub_data(QByteArray data)
{
hub_data *tmp = new hub_data;
char *datagram;
int datagram_size;
tmp->piTime = QTime::currentTime();
tmp->altitude.asByte[0] = data.at(1);
tmp->altitude.asByte[1] = data.at(2);
tmp->altitude.asByte[2] = data.at(3);
tmp->altitude.asByte[3] = data.at(4);
tmp->packet_count.asByte[0] = data.at(5);
tmp->packet_count.asByte[1] = data.at(6);
tmp->packet_count.asByte[2] = data.at(7);
tmp->packet_count.asByte[3] = data.at(8);
tmp->power_sat0 = GS_link->power_sat0;
tmp->power_sat1 = GS_link->power_sat1;
tmp->hack_hd0 = GS_link->hack_hd0;
tmp->hack_hd1 = GS_link->hack_hd1;
tmp->solenoid0 = GS_link->solenoid0;
tmp->solenoid1 = GS_link->solenoid1;
tmp->webcam = GS_link->webcam;
printf("HUB: %s:%i\t%u\t%.4f\t%i\t%i\t%i\t%i\t%i\t%i\t%i\n",
tmp->piTime.toString().toStdString().c_str(),
tmp->piTime.msec(),
tmp->packet_count.asUInt,
tmp->altitude.asFloat,
tmp->power_sat0,
tmp->power_sat1,
tmp->hack_hd0,
tmp->hack_hd1,
tmp->solenoid0,
tmp->solenoid1,
tmp->webcam);
fflush(stdout);
/* Send to GS */
datagram_size = asprintf(&datagram, "H,ALT,%.4f,S0,%i,S1,%i,HD0,%i,HD1,%i,SOL0,%i,SOL1,%i,W,%i",
tmp->altitude.asFloat,
tmp->power_sat0,
tmp->power_sat1,
tmp->hack_hd0,
tmp->hack_hd1,
tmp->solenoid0,
tmp->solenoid1,
tmp->webcam);
GS_link->send_datagram(datagram_size, datagram);
hub_data_list.append(tmp);
if((hub_data_list.size()%60) == 0)
log_hub_data("iSEDE_Hub.log");
free(datagram);
}
void SerialHandler::log_hub_data(QString file_name)
{
int i;
QFile file(file_name);
file.open(QIODevice::Append);
QTextStream file_out(&file);
printf("Logging Hub's data...\n");
for(i = last_hub_logged; i < hub_data_list.size(); i++)
{
file_out << hub_data_list.at(i)->piTime.toString(Qt::ISODate).toStdString().c_str() << ":";
file_out << hub_data_list.at(i)->piTime.msec() << ';';
file_out << hub_data_list.at(i)->altitude.asFloat << ';';
file_out << hub_data_list.at(i)->power_sat0 << ';';
file_out << hub_data_list.at(i)->power_sat1 << ';';
file_out << hub_data_list.at(i)->hack_hd0 << ';';
file_out << hub_data_list.at(i)->hack_hd1 << ';';
file_out << hub_data_list.at(i)->solenoid0 << ';';
file_out << hub_data_list.at(i)->solenoid1 << ';';
file_out << hub_data_list.at(i)->webcam << '\n';
}
last_hub_logged = i;
file.close();
printf("Done!\n");
}
/**
* @brief SerialHandler::store_incoming_data
* @param data
*
* Parse the data.
*
* Payload description:
* +---------------+------------------+---------------------+---------------+--------------+-------------+------------------+
* | Packet Count | Temperature (x2) | Accelerometers (x2) | Pressure (x3) | Time Stamp | Status byte | Sender's Address |
* | (2 bytes) | (8 bytes) | (24 bytes) | (12 bytes) | (4 bytes) | (1 byte) | (1 byte) |
* +---------------+------------------+---------------------+---------------+--------------+-------------+------------------+
*/
void SerialHandler::store_incoming_stellite_data(QByteArray data)
{
satellite_data *tmp = new satellite_data;
tmp->bytes.append(data);
/* Pi's time */
tmp->piTime = QTime::currentTime();
/* Packet count */
tmp->packet_count.asByte[0] = data.at(0);
tmp->packet_count.asByte[1] = data.at(1);
/* Temperature 0 */
tmp->temp0.asByte[0] = data.at(2);
tmp->temp0.asByte[1] = data.at(3);
tmp->temp0.asByte[2] = data.at(4);
tmp->temp0.asByte[3] = data.at(5);
/* Temperature 1 */
tmp->temp1.asByte[0] = data.at(6);
tmp->temp1.asByte[1] = data.at(7);
tmp->temp1.asByte[2] = data.at(8);
tmp->temp1.asByte[3] = data.at(9);
/* Accelerometer 0 */
tmp->x0.asByte[0] = data.at(10);
tmp->x0.asByte[1] = data.at(11);
tmp->x0.asByte[2] = data.at(12);
tmp->x0.asByte[3] = data.at(13);
tmp->y0.asByte[0] = data.at(14);
tmp->y0.asByte[1] = data.at(15);
tmp->y0.asByte[2] = data.at(16);
tmp->y0.asByte[3] = data.at(17);
tmp->z0.asByte[0] = data.at(18);
tmp->z0.asByte[1] = data.at(19);
tmp->z0.asByte[2] = data.at(20);
tmp->z0.asByte[3] = data.at(21);
/* Accelerometer 1 */
tmp->x1.asByte[0] = data.at(22);
tmp->x1.asByte[1] = data.at(23);
tmp->x1.asByte[2] = data.at(24);
tmp->x1.asByte[3] = data.at(25);
tmp->y1.asByte[0] = data.at(26);
tmp->y1.asByte[1] = data.at(27);
tmp->y1.asByte[2] = data.at(28);
tmp->y1.asByte[3] = data.at(29);
tmp->z1.asByte[0] = data.at(30);
tmp->z1.asByte[1] = data.at(31);
tmp->z1.asByte[2] = data.at(32);
tmp->z1.asByte[3] = data.at(33);
/* Pressure 0 */
tmp->pressure0.asByte[0] = data.at(34);
tmp->pressure0.asByte[1] = data.at(35);
tmp->pressure0.asByte[2] = data.at(36);
tmp->pressure0.asByte[3] = data.at(37);
/* Pressure 1 */
tmp->pressure1.asByte[0] = data.at(38);
tmp->pressure1.asByte[1] = data.at(39);
tmp->pressure1.asByte[2] = data.at(40);
tmp->pressure1.asByte[3] = data.at(41);
/* Pressure 2 */
tmp->pressure2.asByte[0] = data.at(42);
tmp->pressure2.asByte[1] = data.at(43);
tmp->pressure2.asByte[2] = data.at(44);
tmp->pressure2.asByte[3] = data.at(45);
/* Satellite time stamp */
tmp->time_stamp.asByte[0] = data.at(46);
tmp->time_stamp.asByte[1] = data.at(47);
tmp->time_stamp.asByte[2] = data.at(48);
tmp->time_stamp.asByte[3] = data.at(49);
/* Satellite status byte */
tmp->status_byte = data.at(50);
/* Sender's address */
tmp->sender = data.at(51);
printf("%u\t%u\t%u\t%hi\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%s\t%s:%03i\n",
tmp->sender,
tmp->time_stamp.asUInt,
tmp->time_stamp.asUInt/1000,
tmp->packet_count.asInt,
tmp->temp0.asFloat,
tmp->temp1.asFloat,
tmp->x0.asFloat,
tmp->y0.asFloat,
tmp->z0.asFloat,
tmp->x1.asFloat,
tmp->y1.asFloat,
tmp->z1.asFloat,
tmp->pressure0.asFloat,
tmp->pressure1.asFloat,
tmp->pressure2.asFloat,
byte_to_binary(tmp->status_byte),
tmp->piTime.toString(Qt::ISODate).toStdString().c_str(),
tmp->piTime.msec());
fflush(stdout);
/* Create a datagram and send it */
char *datagram = NULL;
int datagram_size;
datagram_size = asprintf(&datagram, "S%u,C,%u,PC,%u,A0,%.4f,%.4f,%.4f,A1,%.4f,%.4f,%.4f,T0,%.4f,T1,%.4f,P0,%.4f,P1,%.4f,P2,%.4f,SB,%u\n",
tmp->sender - 7,
tmp->time_stamp.asUInt,
tmp->packet_count.asInt,
tmp->x0.asFloat,
tmp->y0.asFloat,
tmp->z0.asFloat,
tmp->x1.asFloat,
tmp->y1.asFloat,
tmp->z1.asFloat,
tmp->temp0.asFloat,
tmp->temp1.asFloat,
tmp->pressure0.asFloat,
tmp->pressure1.asFloat,
tmp->pressure2.asFloat,
tmp->status_byte);
GS_link->send_datagram(datagram_size, datagram);
free(datagram);
data_list.append(tmp);
debug_msg("**%i**\n", data_list.size());
if(data_list.size()%100 == 0)
{
log_data("iSEDE.log");
}
/**
* @brief SerialHandler::log_data
* @param file_name
*/
void SerialHandler::log_data(QString file_name)
{
int i;
QFile file(file_name);
file.open(QIODevice::Append);
QTextStream file_out(&file);
printf("Logging data....\n");
for(i = last_logged; i < data_list.size(); i++)
{
file_out << data_list.at(i)->piTime.toString(Qt::ISODate).toStdString().c_str() << ":";
file_out << data_list.at(i)->piTime.msec() << ";";
file_out << data_list.at(i)->sender << ",";
file_out << data_list.at(i)->time_stamp.asUInt << ",";
file_out << data_list.at(i)->packet_count.asInt << ",";
file_out << data_list.at(i)->temp0.asFloat << ",";
file_out << data_list.at(i)->temp1.asFloat << ",";
file_out << data_list.at(i)->x0.asFloat << ",";
file_out << data_list.at(i)->y0.asFloat << ",";
file_out << data_list.at(i)->z0.asFloat << ",";
file_out << data_list.at(i)->x1.asFloat << ",";
file_out << data_list.at(i)->y1.asFloat << ",";
file_out << data_list.at(i)->z1.asFloat << ",";
file_out << data_list.at(i)->pressure0.asFloat << ",";
file_out << byte_to_binary(data_list.at(i)->status_byte);
file_out << "\n";
}
last_logged = i;
file.close();
printf("Done!\n");
}
多くのテストと調査の後、私は最終的に何が起こっているのかを発見しました:readyRead()
新しいデータがあるたびに信号が発行されますが、ドキュメントには「readyRead()は再帰的に発行されない」incoming_data()
と書かれているため、どちらが接続されているように見えますreadyRead()
一部のバイトが到着したときにのみ呼び出され、プログラムがパケットと「非同期」になり、一部のパケットのみを読み取ることができます(他のパケットはバッファに残ります)。
それにもかかわらず、大量のデータが到着する場合、この「非同期状態」は発生しません。
これが私が作成したスレッドです。この特定の問題に対処するために別のスレッドを作成します。
私を助けてくれたみんな、どうもありがとう!