我们正在使用Arduino Pro(328 5V)从多个传感器中读取数据,并从串行和控制3个执行器中发送和读取有效载荷。
正在读取的传感器是5个模拟拉伸传感器和2个BNO55 Adafruit IMU。
我们面临的问题是,尽管获得了大约40Hz的消息频率,但传感器输入与通过串行方式到达的数据之间仍然存在大约200ms的明显延迟。
我在下面包含了Arduino代码:
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BNO055.h>
#include <utility/imumaths.h>
//********* SERIAL Communication ***********
// Constants for receiving data from Serial
bool received = false;
byte startByte = 0x10;
const byte payloadOutSize = 54;
struct PayloadOut
{
float w, x, y, z;
float w2, x2, y2, z2;
float ax, ay, az;
uint16_t thumb, index, middle, ring, pinky;
}payloadOut;
const byte payloadInSize = 9;
struct PayloadIn
{
uint8_t thumbEffect, thumbAmp, thumbFreq;
uint8_t indexEffect, indexAmp, indexFreq;
uint8_t middleEffect, middleAmp, middleFreq;
}payloadIn;
unsigned long counter = 0;
unsigned long timeoutCounter = 0;
int timeoutInterval = 1000;
bool timeout = false;
// Constants for parsing received characters for
const int numberOfFingers = 3; // Number of Fingers used in the sketch
int solenoidPin[numberOfFingers];
const int numberOfVariables = 9; // Number of variables in the received String
int Signal[numberOfVariables];
// Auxillary variables for pulse generation
unsigned long previousMicros[numberOfFingers] = { 0 }; // For frequency
long previousMillis[numberOfFingers] = { 0 }; // For pushing
bool trigger[numberOfFingers] = { false };
int timerVariable = 1;
int lowerBound = 0;
// Auxillary variables for keeping data on fingers in memory
int EffectNumber[numberOfFingers] = { 0 };
int EffectFrequency[numberOfFingers] = { 0 };
int EffectAmplitude[numberOfFingers] = { 0 };
//Debug
int SoftwareSerialRx = 9;
int SoftwareSerialTx = 10;
// Indicator Outputs:
const int ledOutput1 = 7;
const int ledOutput2 = 8;
// Sensors:
const int numberOfSensors = 6;
int inSignal[numberOfSensors];
const int AverageN = 15;
int runningAverage[numberOfSensors][AverageN] = {0};
int sensorValueAvg[numberOfSensors] = { 0 };
// IMU:
bool usingIMU = true; // if we want to have the imu turned on from the very beginning
Adafruit_BNO055 bno1 = Adafruit_BNO055(55);
Adafruit_BNO055 bno2 = Adafruit_BNO055(55, 0x29);
float wOrient, xOrient, yOrient, zOrient;
void setup() {
// Serial comms start
Serial.begin(57600); // 38400 or 57600
Serial.println("Arduino is ready");
pinMode(ledOutput1, OUTPUT);
pinMode(ledOutput2, OUTPUT);
// Pins controlling fingers and initiate them
solenoidPin[0] = 3;
solenoidPin[1] = 5;
solenoidPin[2] = 6;
for (int pin = 0; pin < numberOfFingers; pin++) {
pinMode(solenoidPin[pin], OUTPUT);
digitalWrite(solenoidPin[pin], LOW);
}
// Initiate sensor pins
inSignal[0] = A3; // Thumb
inSignal[1] = A6; // index finger
inSignal[2] = A7; // Middle finger
inSignal[3] = A2; // Ring finger
inSignal[4] = A1; // Little finger
inSignal[5] = A0; // Extra sensor
for (int pin1 = 0; pin1 < numberOfSensors; pin1++) {
pinMode(inSignal[pin1],INPUT);
}
// Initializing BNOs
if (!bno1.begin())
{
// There was a problem detecting the BNO055 ... check your connections
Serial.print("Ooops, no BNO055-1 detected ... Check your wiring or I2C ADDR!");
usingIMU = false; // revert back to no IMU mode.
// while(1);
// break;
}
if (!bno2.begin())
{
// There was a problem detecting the BNO055 ... check your connections
Serial.print("Ooops, no BNO055-2 detected ... Check your wiring or I2C ADDR!");
usingIMU = false; // revert back to no IMU mode.
// while(1);
// break;
}
delay(500);
bno1.setExtCrystalUse(true);
bno2.setExtCrystalUse(true);
}
void loop() {
// Timeout function
if (millis() - timeoutCounter > timeoutInterval) {
timeout = true;
}
else timeout = false;
// Receive payload
received = SerialPayloadReceive();
if (received) {
FingerLoad();
Sensing();
SerialPayloadSend();
counter++;
received = false;
timeoutCounter = millis();
}
// FINGER SHIT
if (timeout) {
trigger[0] = trigger[1] = trigger[2] = true;
Signal[0] = Signal[3] = Signal[6] = 0;
}
for (int i = 0; i < 3; i++)
{
OutputElectricalImpulse(i);
}
}
void FingerLoad() {
trigger[0] = payloadIn.thumbEffect;
trigger[1] = payloadIn.indexEffect;
trigger[2] = payloadIn.middleEffect;
Signal[0] = payloadIn.thumbEffect;
Signal[2] = payloadIn.thumbAmp;
Signal[1] = payloadIn.thumbFreq;
Signal[3] = payloadIn.indexEffect;
Signal[5] = payloadIn.indexAmp;
Signal[4] = payloadIn.indexFreq;
Signal[6] = payloadIn.middleEffect;
Signal[8] = payloadIn.middleAmp;
Signal[7] = payloadIn.middleFreq;
}
// Send signals to all fingers!
void OutputElectricalImpulse(int pin) {
float output;
// Put new data into actuator effect arrays
if (trigger[pin] == true) {
if (EffectNumber[pin] != Signal[pin*3] ||
EffectFrequency[pin] != Signal[pin*3 + 1] ||
EffectAmplitude[pin] != Signal[pin*3 + 2]) {
EffectNumber[pin] = Signal[pin*3];
EffectFrequency[pin] = Signal[pin*3 + 1];
EffectAmplitude[pin] = Signal[pin*3 + 2];
digitalWrite(ledOutput1, HIGH);
}
}
// DO STUFF HERE
}
// Sensing flex-sensors
void Sensing() {
for (int i = 0; i < numberOfSensors - 1; i++){
sensorValueAvg[i] = RunningAverage(i, analogRead(inSignal[i]));
}
}
int RunningAverage(int sensor, int sensorValue){
int i = counter % AverageN;
runningAverage[sensor][i] = sensorValue;
int average = 0;
if ( counter < AverageN ){
for (int j = 0; j < i; j++){
average += runningAverage[sensor][j];
}
return average / counter;
}
else {
for (int j = 0; j < AverageN; j++){
average += runningAverage[sensor][j];
}
return average / AverageN;
}
}
float reMap(float x, float in_min, float in_max, float out_min, float out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
void SerialPayloadSend() {
payloadOut.thumb = (uint16_t)sensorValueAvg[0];
payloadOut.index = (uint16_t)sensorValueAvg[1];
payloadOut.middle = (uint16_t)sensorValueAvg[2];
payloadOut.ring = (uint16_t)sensorValueAvg[3];
payloadOut.pinky = (uint16_t)sensorValueAvg[4];
/* DIRECT SIGNAL
payloadOut.thumb = (uint16_t)analogRead(inSignal[0]);
payloadOut.index = (uint16_t)analogRead(inSignal[1]);
payloadOut.middle = (uint16_t)analogRead(inSignal[2]);
payloadOut.ring = (uint16_t)analogRead(inSignal[3]);
payloadOut.pinky = (uint16_t)analogRead(inSignal[4]);
*/
if (usingIMU) {
imu::Quaternion quat = bno1.getQuat();
payloadOut.w = quat.w();
payloadOut.x = quat.x();
payloadOut.y = quat.y();
payloadOut.z = quat.z();
quat = bno2.getQuat();
payloadOut.w2 = quat.w();
payloadOut.x2 = quat.x();
payloadOut.y2 = quat.y();
payloadOut.z2 = quat.z();
imu::Vector<3> accel = bno1.getVector(Adafruit_BNO055::VECTOR_ACCELEROMETER);
payloadOut.ax = accel.x();
payloadOut.ay = accel.y();
payloadOut.az = accel.z();
}
byte outputBuffer[payloadOutSize];
memcpy(outputBuffer, &payloadOut, payloadOutSize);
Serial.write(startByte);
Serial.write(payloadOutSize);
Serial.write(outputBuffer, payloadOutSize);
}
bool SerialPayloadReceive() {
if (Serial.available()) {
byte inbuf[payloadInSize];
int i = 0;
// Hang whilst waiting for start byte
byte inByte;
while (inByte != startByte) inByte = Serial.read();
// Read serial into buffer
while (i < payloadInSize)
{
if (Serial.available()) {
inbuf[i] = Serial.read();
i++;
}
}
memcpy(&payloadIn, inbuf, payloadInSize);
return true;
}
else return false;
}
致歉!使用多线程和System.IO.Ports库将其读入用.NET C#编写的自定义串行程序中。如果这可能是导致问题的原因,我可以在此处发布串行协议的代码。
如您所见,有许多挂起功能,超时的可能性由PC端处理。