Skip to content

Repository files navigation

🫀 Real-Time Vital Sign Monitor

QNX Neutrino RTOS 8.0 · Raspberry Pi 4B · Arduino Uno R4 WiFi

A deterministic, hard real-time medical monitoring system that streams live ECG + EMG biosignals, triggers priority-scheduled alarms within 100 ms, and logs clinical data — all running on a microkernel RTOS.


📸 Demo

================================================
         VITAL SIGN MONITOR (QNX 8.0)
================================================

ECG |████████████████████░░░░░░░░░░░░░░░░░░░| 487 BPM
EMG |══════════════░░░░░░░░░░░░░░░░░░░░░░░░░| 342 mV

------------------------------------------------
 STATUS: ✅ SYSTEM NOMINAL
------------------------------------------------

🧠 What Makes This Interesting

This isn't a hobbyist Arduino sketch — it's a full RTOS architecture project. The Raspberry Pi runs QNX Neutrino, a hard real-time microkernel OS used in medical devices, cars (BlackBerry QNX), and aerospace. The Arduino is just the ADC front-end.

Key RTOS concepts demonstrated:

  • Preemptive priority scheduling (SCHED_FIFO) with 4 threads at distinct priorities
  • Microkernel fault isolation — a USB driver crash cannot affect the alarm engine
  • procmgr_ability() — non-root process acquiring real-time scheduling rights
  • Deterministic alarm response — worst-case latency bounded to 100 ms by the scheduler
  • Priority inheritance via QNX IPC to prevent priority inversion

🗂 Repository Structure

.
├── arduino/
│   └── vital_signs.ino          # EMG + ECG acquisition firmware (500 Hz)
├── qnx/
│   └── medical_monitor.cpp      # Multi-threaded QNX C++ application
├── scripts/
│   └── setup_arduino.sh         # QNX target: USB driver + serial setup
└── README.md

🔧 Hardware

Component Model Role
SBC Raspberry Pi 4B (8 GB) Runs QNX Neutrino 8.0
MCU Arduino Uno R4 WiFi 14-bit ADC; EMG filter + ECG sampling
EMG sensor Muscle BioAmp Shield Surface electrode + instrumentation amp
ECG sensor BioAmp EXG Pill 3-lead wet electrode (RA, LA, RL)
Link USB Serial (CDC-ACM) 115,200 baud → /dev/serusb1 on QNX

Why Arduino R4? The classic Uno has a 10-bit ADC. The R4 gives 14-bit (16,384 levels), significantly reducing quantisation noise in the EMG signal.


🏗 System Architecture

┌─────────────────────────────────────────────────┐
│              QNX Neutrino RTOS 8.0               │
│  ┌──────────────┐  ┌──────────────┐             │
│  │ devc-serusb  │  │  med_monitor │             │
│  │  (USB driver │  │   process    │             │
│  │  resource    │  │              │             │
│  │  manager)    │  │  Pri 20 ───► Alarm thread  │
│  │  /dev/serusb1│  │  Pri 15 ───► Data thread   │
│  └──────┬───────┘  │  Pri 10 ───► UI thread     │
│         │ read()   │  Pri  5 ───► Log thread    │
│  ┌──────▼──────────────────────────────────┐    │
│  │          QNX Microkernel                │    │
│  │  Scheduling · IPC · Memory · Timers     │    │
│  └─────────────────────────────────────────┘    │
└───────────────────┬─────────────────────────────┘
                    │ USB CDC-ACM 115200 baud
         ┌──────────▼──────────────┐
         │    Arduino Uno R4 WiFi  │
         │  EMG: A0 → filter →     │
         │        envelope → CSV   │
         │  ECG: A2 → raw → CSV    │
         │  Output: "342,487\n"    │
         └─────────────────────────┘

⚡ Thread Priority Model

Thread Priority Policy Responsibility
Alarm engine 20 SCHED_FIFO ECG spike detection → alarm in ≤100 ms
Data acquisition 15 SCHED_FIFO Drain USB buffer; parse CSV into globals
UI / HMI 10 SCHED_RR Terminal dashboard at 20 fps
Logger 5 SCHED_RR Background CSV → /tmp/patient_summary.csv

SCHED_FIFO = no time-slicing; thread runs until it blocks or is preempted by higher priority. Used for the two critical threads so timer jitter never delays them.


🔬 Arduino Firmware

Sampling loop — non-blocking timer accumulator

// Accumulator pattern: carries forward overshoot deficit
// maintains exact 500 Hz long-term even with loop jitter
timer += 1000000 / SAMPLE_RATE;  // reload 2000 µs

EMG signal processing pipeline

analogRead(A0)
    └─► EMGFilter()       4-stage IIR biquad bandpass (20–450 Hz)
            └─► abs()     full-wave rectification
                    └─► getEnvelop()   128-sample running average
                                └─► Serial.print()   CSV output

Bandpass filter — 4 cascaded biquad stages

Stage Type Purpose
1 Lowpass Attenuate noise above ~450 Hz
2 Highpass Remove DC + motion artifact < 20 Hz
3 Highpass Steepen roll-off skirt
4 Bandstop Notch 50/60 Hz power line interference

Each stage is Direct Form II Transposed — most numerically stable IIR form for single-precision float. State vars are static, preserving filter memory between loop() calls.

Serial output format

EMG_ENVELOPE,ECG_RAW\n

342,487     ← nominal
0,512       ← no muscle activity  
891,803     ← ECG > 800 → QNX alarm fires

🖥 QNX Application

Building (on host — Windows/Linux with QNX SDP 8.0)

# Cross-compile for AArch64 QNX target
qcc -Vgcc_ntoaarch64le_cxx -o med_monitor medical_monitor.cpp

Deploying to RPi4

# Copy binary
scp -c aes128-ctr -o MACs=hmac-sha2-256 med_monitor qnxuser@<TARGET_IP>:/tmp/

# SSH to target
ssh -c aes128-ctr -o MACs=hmac-sha2-256 qnxuser@<TARGET_IP>

Running on target

# 1. Run Arduino setup script first
chmod +x setup_arduino.sh && sudo ./setup_arduino.sh

# 2. Launch monitor
sudo ./med_monitor

Alarm acknowledgment

Key Action
A Acknowledge alarm — silences buzzer, keeps visual warning until ECG normalises
Ctrl+C Exit monitor (restores terminal settings)

📡 QNX Driver Setup (manual)

# Find Arduino USB IDs
usb -vv

# Kill any existing driver
sudo slay devc-serusb devc-sercdc

# Start USB serial resource manager
sudo /usr/sbin/devc-serusb -v -d vid=0x2341,did=0x1002 &

# Verify device node
ls -l /dev/ser*          # expect /dev/serusb1

# Configure baud rate
stty baud=115200 < /dev/serusb1

# Run
sudo ./med_monitor

🔬 QNX Concepts Used

Microkernel architecture

QNX's kernel is < 80 KB and handles only scheduling, IPC, timers, and memory. Every driver (including devc-serusb) runs as a user-space resource manager process. If the USB driver crashes, the kernel detects it — the alarm and UI threads keep running unaffected.

procmgr_ability() — capability-based privileges
procmgr_ability(0,
    PROCMGR_ADN_ROOT | PROCMGR_AOP_ALLOW | PROCMGR_AID_PRIORITY,
    PROCMGR_AID_EOL);

Grants this process the ability to set SCHED_FIFO priorities above the default ceiling — without running as root. Principle of least privilege.

Priority inversion prevention

QNX's microkernel IPC automatically applies priority inheritance: when a high-priority thread blocks on MsgSend() to a lower-priority server, the server inherits the caller's priority. This is guaranteed by the kernel — the fix that would have prevented the 1997 Mars Pathfinder reset.

volatile shared globals
volatile int g_ecg = 0;
volatile int g_emg = 0;

volatile prevents the compiler from caching these in registers across loop iterations — without it, an optimising compiler might never see cross-thread updates. Note: volatile is not atomic; production systems should use pthread_mutex_t or QNX's atomic_* functions.

Non-canonical terminal input
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);

Switches terminal to raw mode so 'A' is detected without pressing Enter. check_ack() uses select() with zero timeout — non-blocking poll that doesn't stall the 20 fps render loop.


📊 Alarm State Machine

              ECG > 800
NOMINAL ─────────────────► CRITICAL (red, beeping)
   ▲                              │
   │ ECG ≤ 800                    │ press 'A'
   │ (auto-reset)                 ▼
   └──────────────── ACKNOWLEDGED (yellow, silent)

📁 Output Files

File Content
/tmp/patient_summary.csv timestamp, EMG, ECG, status — logged every 5 s by background thread

🛠 Requirements

Host (development)

  • QNX SDP 8.0 (includes qcc cross-compiler)
  • VS Code + QNX SDP Extension (optional, for profiling)
  • Windows 11 or Linux

Target

  • Raspberry Pi 4B with QNX Neutrino 8.0 Quick Start Image
  • Network access (for SCP/SSH deployment)

Hardware

  • Arduino Uno R4 WiFi
  • Muscle BioAmp Shield (EMG)
  • BioAmp EXG Pill (ECG)
  • Electrodes + leads

📄 License

MIT — see LICENSE

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages