与Arduino的串行通信,频率为40Hz但延迟高

时间:2018-07-24 12:18:25

标签: arduino serial-port latency

我们正在使用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端处理。

0 个答案:

没有答案
相关问题