AnFlex (2024)

An integrated ankle-pump exercise assistance and management system.

Project Overview

Project Summary

This project addresses the critical risk of Deep Vein Thrombosis (DVT) in cancer patients undergoing chemotherapy by designing and building an Ankle-pump Exercise Assistance System. The system transforms a difficult rehabilitation routine into a manageable task by combining mechanical assistance with a digital management console.

The system utilizes servo motors to physically assist the ankle exercise when fatigue sets in. An IMU sensor is integrated into the pedal collects motion data, which is processed by an Arduino board. This data is transmitted via Python SDK to an Appwrite Cloud backend. Consequently, the system provides immediate haptic feedback (via a vibration motor) to deliver useful information for patients (exercise quality, exercise starting and ending, etc.).

To ensure efficient data management and user engagement, a dual-interface software solution was developed: a mobile app for patients to control the device and track compliance, and a web dashboard for medical workers to monitor real-time patient status and exercise history.

My Contributions

I was fully responsible for the end-to-end development of the interaction and information management system, bridging the gap between hardware sensing and software application:

  • Microcontroller & Sensor Integration

  • Cloud Backend & Data Transfer

  • Hardware Prototyping & Assembly (Collaborating with Mechanical Designers)

  • Mobile & Web App Development

Tech Stack

  • Embedded & IoT Hardware: Arduino, Socket/Serial Protocol

  • Backend & Cloud: Appwrite Cloud, Python SDK

  • Frontend: React

Acknowledgements

Thanks to Prof. Ting Han and Prof. Xinyang Tan for guidance, and to Fudan University Shanghai Cancer Center and its medical staff for their support.

Problem Framing

Project Background

The project was initiated based on real-world clinical pain points identified by medical staff at Fudan University Shanghai Cancer Center. Deep vein thrombosis (DVT) is a major concern in hospital settings, as it can progress to fatal pulmonary embolism (PE), which carries a mortality rate of 20–30%. While ankle pump exercises have been proven to be the simplest, most cost-effective, and non-invasive method for preventing DVT by promoting lower-limb blood circulation, many patients—particularly those who are bedridden or recovering from surgery—face difficulties in performing these exercises correctly and consistently.

In response to this gap between proven prevention and actual patient compliance, the medical staff at the Cancer Center called for the design and development of a device that can assist and monitor ankle pump movements, specifically targeting high-risk populations such as patients undergoing cancer treatment.

Occurrence of DVT in 6 months following the surgery (p = 0.032)

References:

Active Ankle Movement May Prevent Deep Vein Thrombosis in Patients Undergoing Lower Limb Surgery - https://www.sciencedirect.com/science/article/pii/S0890509616000285

Field Research & Interview

To gain a deep understanding of the problem context, we conducted on-site research at the hospital. Through close observations of the treatment scenarios of cancer chemotherapy patients (especially the physical constraints and ward environment), and interviews with several healthcare professionals, we understood the functional requirements and system design limitations in this clinical setting.

Environment

Patients

Caregivers

Nurses

Pain Points:

  • Limited space in shared wards (e.g., triple/quadruple rooms)

  • Privacy concerns (given the sensitive location of femoral artery access)

Demands:

  • Compact, easy-to-wear device design

  • No camera-based solutions (compromise privacy)

  • No voice interactions (disturbing for shared wards)

System Architecture

Mechanical Design

The device uses a compact pedal module mounted on the bed’s footboard via a sliding rail, allowing height adjustment for different patients. A soft orthosis secures the limb while leaving the ankle free for movement. Two servo motors are used to provide motion assistance. Each servo is connected to the pedal via an elastic cord, ensuring that the pulling force changes linearly during movement. This linear force variation prevents sudden tension shifts, making the exercise smooth and comfortable for the patient.

Data Flow

The system follows a three-tier IoT architecture:

  • Perception Layer — The hardware prototype integrates an IMU sensor embedded in the pedal to capture real‑time motion data. An Arduino microcontroller handles local data processing, control logic, servo motor control for mechanical assistance, and a vibration motor for haptic feedback. It runs closed‑loop algorithms to assess exercise compliance and movement quality.

  • Network Layer — The microcontroller transmits sensor data to Appwrite Cloud via Python SDK. This layer manages data validation, protocol conversion, and reliable bidirectional communication.

  • Application Layer — The cloud database (Appwrite) synchronizes data with two client applications: (1) a Mobile App for patients (and caregivers) to control the device, view exercise progress, and receive notifications; and (2) a Web Dashboard for medical professionals to monitor multiple patients’ compliance, analyze training history, and generate reports.

User Flow

The patient starts the session via the app. The device then signals the start with a vibration, prompting the patient to begin the ankle-pump exercise. As the device drives the pedal, an IMU sensor validates the movement. If the motion is correct, the server increments the rep count, and the device provides vibration feedback to the patient. This cycle repeats until the target repetitions are reached. Once completed, the device stops and signals the end of the session, the server generates a report, and both the patient and nurse can view the final records.

  • For patients, the automated vibration feedback and app-based control eliminate the need for constant manual tracking, making rehabilitation exercises more engaging and easier to perform independently.

  • For nurses, the real-time dashboard and automated report generation enable efficient remote monitoring of multiple patients’ progress without requiring physical presence during each exercise session.

Hardware Prototyping & Data Transfer

Pedal & Servo Integration

During the construction of the physical prototype, we installed a pair of foot pedals with caster wheels onto a base made of steel bars and slide rails, and connected two 35kg servo motors to the left and right pedals respectively.

Sensor & Data Transfer

At the same time, we tested the IMU sensor on a cardboard model, defined appropriate angle thresholds based on the actual scenario of ankle pump exercises. Then, we developed a step counter according to the thresholds, and uploaded the motion data in real time to the backend of Appwrite Cloud via the Socket io and Python SDK.

Testing Data Collection & Transfer (Arduino -> Python -> Appwrite Cloud) with paper model (and my old laptop)

Python (Data Transfer & Connection with Cloud)
import serial
import time
from datetime import datetime, timezone
from appwrite.client import Client
from appwrite.services.databases import Databases
from appwrite.id import ID
 
# ========== Configuration ==========
SERIAL_PORT = "COM3"
BAUD_RATE = 115200
 
# ========== Appwrite Settings & Initialization ==========
 
APPWRITE_ENDPOINT = "https://cloud.appwrite.io/v1"
APPWRITE_PROJECT_ID = "project_id"
APPWRITE_API_KEY = "api_key"
APPWRITE_DATABASE_ID = "database_id"
APPWRITE_COLLECTION_ID = "collection_name"
 
PATIENT_ID = "patient_001"
 
client = Client()
client.set_endpoint(APPWRITE_ENDPOINT)
client.set_project(APPWRITE_PROJECT_ID)
client.set_key(APPWRITE_API_KEY)
 
databases = Databases(client)
 
# ========== Read steps from serial ==========
def read_step_from_serial(serial_connection):
 
if serial_connection.in_waiting:
line = serial_connection.readline().decode('utf-8', errors='ignore').strip()
if line.startswith("STEP:"):
try:
steps = int(line.split(":")[1])
return steps
except (IndexError, ValueError):
print(f"Data format error: {line}")
return None
return None
 
# ========== Upload data to Appwrite Cloud ==========
def upload_step_count(steps):
try:
record = {
"patient_id": PATIENT_ID,
"steps": steps,
"timestamp": datetime.now(timezone.utc).isoformat()
}
result = databases.create_document(
database_id=APPWRITE_DATABASE_ID,
collection_id=APPWRITE_COLLECTION_ID,
document_id=ID.unique(),
data=record
)
print(f"Uploaded: {steps} steps (Document ID: {result['$id']})")
return True
except Exception as e:
print(f"Upload failed: {e}")
return False
 
# ========== Main program ==========
 
if __name__ == "__main__":
try:
ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1)
print(f"Serial port {SERIAL_PORT} opened, listening...")
except serial.SerialException as e:
print(f"Failed to open serial port {SERIAL_PORT}: {e}")
 
try:
while True:
steps = read_step_from_serial(ser)
if steps is not None:
print(f"Received steps: {steps}")
upload_step_count(steps)
time.sleep(0.1)
except KeyboardInterrupt:
print("\nProgram exited")
finally:
ser.close()
Arduino (Data Collection & Step Counter)
#include <Wire.h>
#include <MPU6050.h>
 
MPU6050 mpu;
 
// Step counter parameters
const unsigned long MIN_STEP_INTERVAL = 300;
const float STEP_THRESHOLD = 0.15;
const float MIN_MAGNITUDE = 1.0;
 
// Data upload parameters
const unsigned long UPLOAD_INTERVAL = 5000;
unsigned long lastUploadTime = 0;
 
// State variables
unsigned long lastStepTime = 0;
int stepCount = 0;
float lastMagnitude = 0;
 
// Sensor data
float ax, ay, az;
float magnitude = 0;
 
// ========== Step detection function ==========
bool detectStep(float currentMagnitude, float previousMagnitude, unsigned long currentTime) {
// Check time interval
if (currentTime - lastStepTime < MIN_STEP_INTERVAL) {
return false;
}
// Calculate change in magnitude
float change = fabs(currentMagnitude - previousMagnitude);
// Apply threshold and magnitude range check
if (change >= STEP_THRESHOLD &&
currentMagnitude >= MIN_MAGNITUDE &&
currentMagnitude <= 3.0) {
return true;
}
return false;
}
 
// ========== Data upload function ==========
void sendStepData() {
// Send in simple text format, e.g. "STEP:25"
Serial.print("STEP:");
Serial.println(stepCount);
}
 
void setup() {
Serial.begin(115200);
Wire.begin();
mpu.initialize();
if (!mpu.testConnection()) {
Serial.println("MPU Connection Failed.");
while (1);
}
lastUploadTime = millis();
}
 
void loop() {
// Read raw data from sensor & Convert data to g
int16_t ax_raw, ay_raw, az_raw;
mpu.getAcceleration(&ax_raw, &ay_raw, &az_raw);
ax = ax_raw / 16384.0;
ay = ay_raw / 16384.0;
az = az_raw / 16384.0;
// Compute resultant magnitude
magnitude = sqrt(ax*ax + ay*ay + az*az);
unsigned long now = millis();
// Step detection
if (detectStep(magnitude, lastMagnitude, now)) {
stepCount++;
lastStepTime = now;
}
lastMagnitude = magnitude;
// Upload step count
if (now - lastUploadTime >= UPLOAD_INTERVAL) {
sendStepData();
lastUploadTime = now;
}
delay(50);
}

Code for prototype (basic step counter & cloud connection)

Assembly

We installed the sensing system into a leg brace (with the fixation at the ankle joint removed to allow movement) and attached it to one side of the pedal, in order to synchronize the servo-assisted motion with the counting of the IMU sensor.

Software Development

Backend (Server): Appwrite Database Implementation

For the prototype, we implemented a simplified database architecture using Appwrite Cloud and focused on core functionality: exercise reps tracking and cloud synchronization.

The system utilizes 2 tables to store training session records and patient information. Both tables are indexed by patient ID, enabling retrieval of individual records.

  • Patients Info Collection: Stores minimal patient information including a unique patient ID, name, ward number, chemotherapy starting & ending time, and a cumulative exercise session counter that automatically increments with each completed session.

  • Training Sessions Collection: Records individual exercise sessions with details such as session ID, repetition count, duration, and timestamps.

Training Session (Python)
# Create the table 'TrainingSessions'
trainingTable = tablesDB.create_table(
database_id=anFlexDB.id,
table_id=ID.unique(),
name='TrainingSessions'
)
 
# Define columns
 
# patientId: string reference to patients.patientId
tablesDB.create_varchar_column(
database_id=trainingDatabase.id,
table_id=trainingTable.id,
key='patientId',
size=255,
required=True
)
 
# sessionId: unique identifier (e.g., '20240120-P001-001')
tablesDB.create_varchar_column(
database_id=trainingDatabase.id,
table_id=trainingTable.id,
key='sessionId',
size=255,
required=True
# Uniqueness constraint is not explicitly provided in the API,
# but can be added separately if supported.
)
 
# exerciseCount: integer (reps completed)
tablesDB.create_integer_column(
database_id=trainingDatabase.id,
table_id=trainingTable.id,
key='exerciseCount',
required=True
)
 
# duration: integer (seconds)
tablesDB.create_integer_column(
database_id=trainingDatabase.id,
table_id=trainingTable.id,
key='duration',
required=True
)
 
# completedAt: datetime
tablesDB.create_datetime_column(
database_id=trainingDatabase.id,
table_id=trainingTable.id,
key='completedAt',
required=True
)
 
# createdAt: datetime
tablesDB.create_datetime_column(
database_id=trainingDatabase.id,
table_id=trainingTable.id,
key='createdAt',
required=True
)
Patient (Python)
# Create the 'Patients' table
patientTable = tablesDB.create_table(
database_id=anFlexDB.id,
table_id=ID.unique(),
name='Patients'
)
 
# Define columns
 
# patientId: unique identifier (e.g., 'P001')
tablesDB.create_varchar_column(
database_id=patientDatabase.id,
table_id=patientTable.id,
key='patientId',
size=255,
required=True
)
 
# patientName: patient's full name
tablesDB.create_varchar_column(
database_id=patientDatabase.id,
table_id=patientTable.id,
key='patientName',
size=255,
required=True
)
 
# wardNumber: ward identifier
tablesDB.create_varchar_column(
database_id=patientDatabase.id,
table_id=patientTable.id,
key='wardNumber',
size=50,
required=True
)
 
# totalExerciseSessionCount: integer with default 0
tablesDB.create_integer_column(
database_id=patientDatabase.id,
table_id=patientTable.id,
key='totalExerciseSessionCount',
required=True,
default=0 # default value as specified
)
 
# therapySessionStart: datetime
tablesDB.create_datetime_column(
database_id=patientDatabase.id,
table_id=patientTable.id,
key='therapySessionStart',
required=True
)
 
# therapySessionEnd: datetime
tablesDB.create_datetime_column(
database_id=patientDatabase.id,
table_id=patientTable.id,
key='therapySessionEnd',
required=True
)

Frontend (Client): Data Visualization

Based on the data retrieved from Appwrite Cloud, the information is clearly visualized via a mobile app (designed for patients and their caregivers) and a web app (designed for medical workers).

The mobile application controls the device and provides intuitive visual feedback to help patients and caregivers monitor their exercise status, suggest training schedule within the prescribed chemotherapy schedule.

The web app provides medical staff with a centralized command center for monitoring patient compliance and managing chemotherapy progress. The main Dashboard is designed to highlight patients pending training (requiring intervention) sorted by their last training time. The Training Reports module offers a detailed tabular view for patient data through a structured list containing Name, Room Number, Hospitalization Time, and Latest Completion Time.

Project Delivery & Critical Reflection

Project Delivery and Demonstration

The prototype was presented to medical staff at Fudan University Shanghai Cancer Center for validation. The system successfully demonstrated the feasibility of automated ankle-pump assistance and remote monitoring.

The presentation at Fudan University Shanghai Cancer Center, and the in-depth discussions with healthcare professionals.

Critical Feedback - Security & Compliance

During the review, medical professionals highlighted a critical gap: Data Security and Regulatory Compliance. While the functional prototype worked, transmitting patient health data via cloud services (Appwrite) raised concerns regarding patient privacy and data encryption standards.

Future Improvement - Architecting for Trust

Acknowledging the critical feedback regarding data sovereignty and privacy, I conducted follow-up research on healthcare information security regulations in China. This led to the design of alternative technical architectures—prioritizing local data storage, access control (enhanced by audit log), and encryption—to ensure the system meets regulatory standards without compromising usability.

Local Storage

Encryption

Access Control

  • Self-hosting: deploy Appwrite with Docker on the hospital’s local server.

  • Data transfer: enable HTTPS across all data transfers.

  • Encrypt sensitive fields using the Chinese commercial cryptography standard SM4.

  • Enhanced tracking: add Python middleware to capture and retain audit logs.

  • Access management: integrate with the hospital information system for identity authentication.