11-05-2024 05:57 AM
I'm currently working on a consolidometer system that communicates with an Arduino via LabVIEW. The system takes measurements of axial pressure, distance, and pore pressure, which are sent over serial to LabVIEW for real-time monitoring and control. However, I'm facing a significant issue with the data acquisition:
I’ve verified that:
Are there recommended techniques for handling serial data in LabVIEW to ensure that only complete, non-zero readings are processed?
Any advice on troubleshooting this issue would be very helpful!
Thank you!
this is my arduino program:
#include <HX711.h>
// Definisikan pin untuk motor stepper
const int stepPin = 5;
const int dirPin = 2;
const int enPin = 8;
// Definisikan pin untuk HX711
const int hx711_data_pin = 4;
const int hx711_clock_pin = 3;
// Inisialisasi HX711
HX711 scale;
float Q_raw = 0;
float Q = 0;
float Q_cal = -44.60; // Gunakan nilai kalibrasi yang diperoleh
float Z_off = 0; // Atur offset nol setelah kalibrasi
float Q_filtered = 0; // Nilai yang sudah difilter
const int numReadings = 10;
float readings[numReadings]; // Array untuk nilai pembacaan
int readIndex = 0;
float total = 0;
float average = 0;
char bt = 0; // BT
bool motorRunning = false; // Status motor
int direction = 1; // 1 untuk maju, -1 untuk mundur
unsigned long speedValue = 1152000;
// Definisikan pin untuk dial indicator
#define DataPin A0
#define ClkPin A1
// Dial Indicator resolution: 100 - 0.01mm, 1000 - 0.001mm
#define Resolution 1000
// UART speed
#define UARTBaudRate 115200
// ADC threshold, ADC values greater than this are interpreted as logical 1, see loop()
#define ADC_Threshold 140
// data format
#define DATA_BITS_LEN 24
#define SIGN_BIT 20
#define START_BIT -1 // -1 - no start bit
// Waktu terakhir data diambil
unsigned long lastMillis = 0;
unsigned long motorLastStepTime = 0; // Waktu terakhir langkah motor dilakukan
// Deklarasi pin untuk Pressure Transmitter
const int analogPin = A3; // Pin analog tempat output konverter dihubungkan
float sensorValue = 0; // Variabel untuk menyimpan nilai pembacaan sensor
float pressure = 0; // Variabel untuk menyimpan nilai tekanan yang dihitung
// Rentang tegangan output konverter (disesuaikan dengan konverter yang digunakan)
const float minVoltage = 0.0; // Tegangan minimum (biasanya 0V)
const float maxVoltage = 3.3; // Tegangan maksimum
// Rentang tekanan dari sensor (disesuaikan dengan spesifikasi sensor)
const float minPressure = 0.0; // Tekanan minimum (0 bar)
const float maxPressure = 10.0; // Tekanan maksimum (10 bar)
// Faktor kalibrasi untuk Pressure Transmitter
float pressureCalibrationFactor = 2.2 / 4; // Kalibrasi sensor untuk menyesuaikan dengan nilai kompresor
// Pengaturan filter median untuk dial indicator
const int filterWindowSize = 5; // Ukuran jendela untuk filter median
long filterWindow[filterWindowSize];
int filterIndex = 0;
// Fungsi untuk mendapatkan bit mentah dari dial indicator
bool getRawBit() {
bool data;
while (analogRead(ClkPin) > ADC_Threshold);
while (analogRead(ClkPin) < ADC_Threshold);
data = analogRead(DataPin) > ADC_Threshold;
return data;
}
// Fungsi untuk mendapatkan data mentah dari dial indicator
long getRawData() {
long out = 0;
for (int i = 0; i < DATA_BITS_LEN; i++) {
out |= getRawBit() ? 1L << DATA_BITS_LEN : 0L;
out >>= 1;
}
return out;
}
// Fungsi untuk mendapatkan nilai dari dial indicator
long getValue() {
long out = getRawData();
bool sign = out & (1L << SIGN_BIT);
out &= (1L << SIGN_BIT) - 1L;
out >>= (START_BIT + 1);
if (sign) out = -out;
return out;
}
// Fungsi untuk filter median
long medianFilter(long newValue) {
filterWindow[filterIndex] = newValue;
filterIndex = (filterIndex + 1) % filterWindowSize;
// Buat salinan jendela filter
long sortedWindow[filterWindowSize];
for (int i = 0; i < filterWindowSize; i++) {
sortedWindow[i] = filterWindow[i];
}
// Urutkan jendela
for (int i = 0; i < filterWindowSize - 1; i++) {
for (int j = i + 1; j < filterWindowSize; j++) {
if (sortedWindow[i] > sortedWindow[j]) {
long temp = sortedWindow[i];
sortedWindow[i] = sortedWindow[j];
sortedWindow[j] = temp;
}
}
}
// Kembalikan nilai median
return sortedWindow[filterWindowSize / 2];
}
// Fungsi untuk mencetak nilai dengan format tertentu
void prettyPrintValue(long value) {
double v = value;
Serial.print(v / 1000, 3);
}
// Fungsi untuk mengatur kecepatan motor
void setMotorSpeed(unsigned long newSpeed) {
speedValue = newSpeed;
Serial.print("Speed set to: ");
Serial.println(speedValue);
}
// Fungsi untuk menjalankan motor
void runMotor() {
digitalWrite(dirPin, direction == 1 ? HIGH : LOW);
digitalWrite(stepPin, HIGH);
delayMicroseconds(speedValue);
digitalWrite(stepPin, LOW);
delayMicroseconds(speedValue);
}
// Fungsi untuk menghentikan motor
void stopMotor() {
motorRunning = false;
Serial.println("Stopping");
}
// Fungsi untuk memetakan nilai float seperti fungsi map() untuk integer
float mapFloat(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 setup() {
// set ADC prescale to 16 (set ADC clock to 1MHz)
// this gives us a sampling rate of ~77kSps
bitSet(ADCSRA, ADPS2);
bitClear(ADCSRA, ADPS1);
bitClear(ADCSRA, ADPS0);
Serial.begin(UARTBaudRate);
// Setup HX711
scale.begin(hx711_data_pin, hx711_clock_pin);
// Kalibrasi awal
Serial.println("Calibrating... Please remove all loads.");
delay(1000); // Kurangi delay kalibrasi menjadi 1 detik
Z_off = scale.read();
Serial.print("Zero Offset: ");
Serial.println(Z_off);
// Inisialisasi array readings dengan nol
for (int thisReading = 0; thisReading < numReadings; thisReading++) {
readings[thisReading] = 0;
}
// Setup motor stepper
pinMode(stepPin, OUTPUT);
pinMode(dirPin, OUTPUT);
pinMode(enPin, OUTPUT);
digitalWrite(enPin, LOW);
}
void loop() {
if (Serial.available() > 0) {
char input = Serial.read();
switch (input) {
case '1':
motorRunning = true;
direction = 1;
Serial.println("Moving forwards");
break;
case '2':
stopMotor();
break;
case '3':
motorRunning = true;
direction = -1;
Serial.println("Moving backwards");
break;
case 'S':
char buffer[10];
Serial.readBytesUntil('\n', buffer, sizeof(buffer));
setMotorSpeed(strtoul(buffer, NULL, 10));
break;
case 'D': // True case, step delay negative
Serial.readBytesUntil('\n', buffer, sizeof(buffer));
setMotorSpeed(strtoul(buffer, NULL, 10));
break;
}
}
// Jalankan motor stepper jika perlu
if (motorRunning) {
unsigned long currentMillis = micros();
if (currentMillis - motorLastStepTime >= speedValue) {
motorLastStepTime = currentMillis;
runMotor();
}
}
// Ambil data setiap detik
if (millis() - lastMillis >= 1000) {
lastMillis = millis();
// Pembacaan nilai dari dial indicator dengan filter median
long rawValue = getValue();
long filteredValue = medianFilter(rawValue);
// Filter Moving Average untuk load cell
Q_raw = scale.read();
// Menghapus nilai tertua dari total
total = total - readings[readIndex];
// Menambahkan nilai baru
readings[readIndex] = Q_raw;
// Menambahkan nilai baru ke total
total = total + readings[readIndex];
// Memperbarui indeks
readIndex = (readIndex + 1) % numReadings;
// Menghitung rata-rata
average = total / numReadings;
Q = (average - Z_off) / Q_cal;
// Jika nilai load cell <= 0, set ke 0
if (Q <= 0) {
Q = 0;
}
// Pembacaan nilai dari Pressure Transmitter
sensorValue = analogRead(analogPin);
float voltage = (sensorValue / 1023.0) * maxVoltage;
pressure = mapFloat(voltage, minVoltage, maxVoltage, minPressure, maxPressure);
// Terapkan faktor kalibrasi pada tekanan
pressure *= pressureCalibrationFactor;
// Kirim data load cell, dial indicator (filtered), dan tekanan melalui serial
Serial.print(Q);
Serial.print(",");
prettyPrintValue(filteredValue);
Serial.print(";");
Serial.println(pressure); //
Serial.flush(); // Pastikan buffer serial telah dikirim
}
// Tambahkan delay di akhir loop
delay(100); // Delay 100 ms untuk stabilisasi komunikasi
}