Close
0%
0%

Clintelli

Clinical Intelligence: modular IoT wearable and AI for clinical data monitoring

Similar projects worth following
Clintelli stands for Clinical Intelligence and is a platform that leverages Artificial Intelligence and wearable IoT technologies to monitor clinical data and improve patient care.

Concept

Clintelli is an open-source hardware and software IoT platform for clinical monitoring of patients. Imagine the Clintelli vest (the wearable/hardware component of the project) as your personal, wearable, affordable and lightweight health monitor. Clintelli’s vest main focus is measuring and analysing Electrocardiogram data, but will also include later sensors for Blood pressure, body temperature and more.

Features:

  • Easy to use wearable IoT technology
  • Easily configurable and customizable based on the requirements of clinical monitoring of the patient (personalized patient care)
  • Easily attachable modules (medical sensors)
  • Support for a variety of medical sensors: ECG, Blood Pressure, Body temperature, IMU
  • Connection with smartphones to configure the wearable and display sensor measurements
  • Connection with the Cloud for data storage, analysis and Machine Learning
  • Can be used for personalized analytics (precision medicine)
  • Cloud software easily deployable to any Cloud provider
  • Powerful hardware enabled by Cortex-M4 Microcontroller
  • End-to-end security both in hardware (cryptographic chip) and in software (digital certificates, encryption) to protect the valuable private medical data
  • Expose data via REST APIs for other third-party HealthTech applications
  • Interface with EMR (Electronic Medical Records) systems using the FHIR standard

Pros:

  • Low cost hardware, affordable healthcare
  • Personalized patient care
  • Ideal for remote clinical monitoring (telemedicine) and elderly care
  • Easy to use
  • Small in size
  • Integrated solution

Cons:

  • Very early stage product
  • Not many cardiac diseases are supported

Methodology

  • Research & Development phases:
    • Research on IoT, Wearables, Medical Devices and ECG
    • Fast prototyping with the development board NodeMCU and Arduino code
    • Setting up the Cloud infrastructure for brokering sensor data
    • Develop Android application for communicating via Bluetooth with the prototype
    • Implement a Deep Neural Network for Atrial Fibrillation Classification using Tensorflow, which will later be used for analysing the measured ECG data (see also https://github.com/nickarad/AF-Classification )
    • Research on Microcontrollers and Medical sensors used in production
    • Design the Clintelli board schematics according to project requirements and datasheets’ specifications. Initial main components are Microcontroller, Cryptographic chip, ECG sensor, WiFi & Bluetooth, voltage regulators etc.
    • Start designing PCB layout and iterate until first version minimum requirements are met and mechanical and electrical constraints are resolved.
    • Send first PCB designs for a small batch-manufacturing (5-10 samples) for testing purposes
    • Manually solder electronic components or order PCB assembly together with the PCB fabrication
    • Test PCB quality, test the design for short-circuits and malfunctions
    • Design plastic cover packaging to house and protect the first version of the Clintelli PCB and the battery.
    • Generate Bills Of Materials (BOMs) from KiCAD and FreeCAD and make first price estimations for the end-product (materials, Integrated Circuits & Electronics supply, PCB manufacturing, plastic cover fabrication etc.)
  • Future steps
    • Test for RoHS compliance (https://www.rohsguide.com/ )
    • Research and prepare for FDA compliance
    • Include more medical sensors in the designs
    • Improve energy consumption and reduce size
    • Reiterate Clintelli-board designs for leveraging Flex PCB technology

Design

Prototype


Platform architecture

Production

Research and Development for Clintelli are very important, but in order for this product to have an actual impact on people's lives and health it must be easily deployable into production, efficiently reproducible and scalable.

The Clintelli vest is considered a medical device, which means that before being made available to market, it must be thoroughly tested (pilot phase) and approved by Medical Device Inspection agencies like FDA (Food & Drug Administration) and EMA (European Medicines Agency) and meet certain quality requirements.

Benchmark

Market

... Read more »

clintelli-board.pdf

Clintelli board schematic

Adobe Portable Document Format - 85.28 kB - 07/22/2019 at 12:26

Preview
Download

  • 1 × NodeMCU - Lua based ESP8266 Arduino based board used for prototyping
  • 1 × AD8232 ECG Sensor used in prototype
  • 1 × Sensor Cable - Electrode Pads (3 connector)
  • 10 × Biomedical Sensor Pads
  • 1 × Cortex M4 (STM32F302) ARM Microcontroller used in the clintelli board

View all 8 components

  • Testing all Prototype systems

    Alex Karadimos08/02/2019 at 11:04 0 comments

    In this experiment we are going to conduct and end-to-end test to see if every system of the Prototype works. We are going to test the following:

    • MQTT broker works properly
    • NodeMCU connects to WiFi and MQTT broker
    • ECG sensor measures data correctly
    • NodeMCU sends ECG data successfully
    • Telegraph subscribes to MQTT broker and sends data for storage at InfluxDB
    • ECG data are are fetched and properly visualized at Chronograph
    • Python subscriber subscribes to MQTT broker successfully and feeds data to Machine Learning mode

  • Store data at InfluxDB: Time Series Database

    Alex Karadimos08/02/2019 at 10:54 0 comments

    A very common practice in IoT solutions is to store data at a Time Series Database. InfluxDB is such a database and it is very suitable for storing the real-time data of Clintelli ECG.

    In the docker-compose file we simply add 4 services, the so called TICK stack.

    T.I.C.K. stands for Telegraf, InfluxDB, Chronograf and Kapacitor and it’s a stack comprised of a time series Database and other tools for data collection, processing and visualization.

    You can learn more on how to get started with InfluxDB, Python and MQTT in my recent article here https://medium.com/@karadalex/getting-started-with-influxdb-with-python-and-mqtt-rabbitmq-e952d67b2963


    Here are the changes in the docker-compose file

    ...
    
      #----------------------------------------------------------------------------------------
      #  TICK Stack
      #----------------------------------------------------------------------------------------
      influxdb:
        image: influxdb:1.7-alpine
        volumes:
          # Mount for influxdb data directory
          - ./influxdb/data:/var/lib/influxdb
          # Mount for influxdb configuration
          - ./influxdb/config/:/etc/influxdb/
        ports:
          # The API for InfluxDB is served on port 8086
          - "8086:8086"
          - "8082:8082"
          # UDP Port
          - "8089:8089/udp"
    
      telegraf:
        image: telegraf:1.11-alpine
        environment:
          HOSTNAME: "telegraf-getting-started"
        # Telegraf requires network access to InfluxDB
        links:
          - influxdb
        volumes:
          # Mount for telegraf configuration
          - ./telegraf.conf:/etc/telegraf/telegraf.conf:ro
          # Mount for Docker API access
          - /var/run/docker.sock:/var/run/docker.sock
        depends_on:
          - rabbitmq
          - influxdb
    
      kapacitor:
        image: kapacitor:1.5-alpine
        volumes:
          # Mount for kapacitor data directory
          - ./kapacitor/data/:/var/lib/kapacitor
          # Mount for kapacitor configuration
          - ./kapacitor/config/:/etc/kapacitor/
        # Kapacitor requires network access to Influxdb
        links:
          - influxdb
        ports:
          # The API for Kapacitor is served on port 9092
          - "9092:9092"
    
      chronograf:
        image: chronograf:1.7-alpine
        environment:
          RESOURCES_PATH: "/usr/share/chronograf/resources"
        volumes:
          # Mount for chronograf database
          - ./chronograf/data/:/var/lib/chronograf/
        links:
          # Chronograf requires network access to InfluxDB and Kapacitor
          - influxdb
          - kapacitor
        ports:
          # The WebUI for Chronograf is served on port 8888
          - "8888:8888"
        depends_on:
          - kapacitor
          - influxdb
          - telegraf

    and here is how the data is visualized in Chronograph, InfluxDB's visualization UI

  • Creating first PCB designs

    Alex Karadimos07/22/2019 at 19:19 3 comments

    First attempt

    Second attempt

    and the 3D rendered view

  • Clintelli board - first schematics

    Alex Karadimos07/22/2019 at 12:26 0 comments

    In order to transform the clintelli IoT wearable prototype into a production ready product, we decided to start designing our own customized, open-source, arduino-based microcontroller board, the Clintelli board.

    The basic components (ICs) are the following:

    • Cortex M4 (STM32F302)
    • ESP32 (ESP-32-WROOM-32)
    • ECG Module (ADS1298)
    • Cryptographic chip (ATECC608A)

    You can see more at the hardware documentation of the clintelli project https://nickarad.github.io/clintelli/#/hardware/custom-hardware

  • Send ECG Data with MQTT

    Alex Karadimos07/21/2019 at 18:50 0 comments

    In the next step of our prototype development, we replaced the simple temperature sensor with the ECG module and made the necessary changes in code to send ECG data with an MQTT publisher via the RabittMQ MQTT broker.


    #include <ESP8266WiFi.h>
    #include <PubSubClient.h>
    #include "secret-config.h"
    
    WiFiClient espClient;
    PubSubClient client(espClient);
    String msg;
    char payload[50];
    unsigned long lastMicros = 0;
    const int analogInPin = 17;  
    
    float getECG(void) {
    	float analog0;
    	// Read from analogic in. 
    	analog0 = analogRead(analogInPin);
    	// binary to voltage conversion
    	return analog0 = (float)analog0 * 3.3 / 1023.0;   
    }
    
    void setup_wifi() {
    	// Connecting to a WiFi network
    	WiFi.begin(ssid, password);
    	while (WiFi.status() != WL_CONNECTED) {
    		delay(500);
    		Serial.print(".");
    	}
    	Serial.println("WiFi connected");
    	Serial.println("IP address: ");
    	Serial.println(WiFi.localIP());
    }
    
    void reconnect() {
    	// Loop until we're reconnected
    	Serial.println("In reconnect...");
    	while (!client.connected()) {
    		Serial.print("Attempting MQTT connection...");
    		// Attempt to connect
    		if (client.connect("Arduino_Gas", mqtt_user, mqtt_pass)) {
    			Serial.println("connected");
    		} 
    		else {
    			Serial.print("failed, rc=");
    			Serial.print(client.state());
    			Serial.println(" try again in 5 seconds");
    			delay(5000);
    		}
    	}
    }
    
    void setup() {
    	Serial.begin(115200);
    	setup_wifi();
    	client.setServer(mqtt_server, 1883);
    }
    
    void loop() {
      
    	char msg[8];
    
    	// Desired sample rate T=7812microseconds
    	if (micros() - lastMicros > 7812) {
    		lastMicros = micros();
    		// float temperatureC = getTemperature() ;
    		float ecg = getECG();
    		sprintf(msg,"%f",ecg);
    		// Serial.print("temperature read");
    		if (!client.connected()) {
    			Serial.print("trying to reconnect...");
    			reconnect();
    		}
    
    		client.publish("mq2_mqtt", msg);
    		//Serial.print("Payload: ");
    		Serial.println(msg);
    	}
    }

  • Testing MQTT communication from Arduino via RabbitMQ

    Alex Karadimos07/15/2019 at 10:39 0 comments

    Next step in setting up the Clintelli platform is installing a MQTT-enabled RabbitMQ server and test communications between the arduino board (publisher) and the various analytics scripts (subscribers).

    At first, we test the MQTT infrastructure by sending some simple measurements from a Temperature sensor connected to the NodeMCU board. Following is the arduino code for publishing the temperature measurements.

    #include <ESP8266WiFi.h>
    #include <PubSubClient.h>
    #include "secret-config.h"
    
    WiFiClient espClient;
    PubSubClient client(espClient);
    unsigned long lastMicros = 0;
    
    void setup_wifi() {
      // Connecting to a WiFi network
      WiFi.begin(ssid, password);
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
      }
      Serial.println("WiFi connected");
      Serial.println("IP address: ");
      Serial.println(WiFi.localIP());
    }
    
    void reconnect() {
      // Loop until we're reconnected
      Serial.println("In reconnect...");
      while (!client.connected()) {
        Serial.print("Attempting MQTT connection...");
        // Attempt to connect
        if (client.connect("Arduino_Gas", mqtt_user, mqtt_pass)) {
          Serial.println("connected");
        } else {
          Serial.print("failed, rc=");
          Serial.print(client.state());
          Serial.println(" try again in 5 seconds");
          delay(5000);
        }
      }
    }
    
    void setup() {
      Serial.begin(115200);
      setup_wifi();
      client.setServer(mqtt_server, 1883);
    }
    
    void loop() {
      char msg[8];
    
      // Desired sample rate T=7812microseconds
      if (micros() - lastMicros > 7812) {
        lastMicros = micros();
        sprintf(msg,"%i",analogRead(17));
        Serial.print("temperature read");
    
        if (!client.connected()) {
          Serial.print("trying to reconnect...");
          reconnect();
        }
    
        client.publish("temp_mqtt", msg);
        Serial.print("Payload: ");
        Serial.println(msg);
      }
    }

     Before uploading that code to the Arduino board, we must setup a MQTT enabled RabbitMQ server. The easiest way is to do that with Docker. Create the following Dockerfile

    # Dockerfile
    FROM rabbitmq:3.7-management
    
    RUN rabbitmq-plugins enable rabbitmq_mqtt
    
    EXPOSE 1883

    and in the same folder create the file docker-compose.yml

    version: '3'
    
    services:
      rabbit:
        build: .
        image: clintelli-rabbitmq
        environment:
          RABBITMQ_ERLANG_COOKIE: "SWQOKODSQALRPCLNMEQG"
          RABBITMQ_DEFAULT_USER: "rabbitmq"
          RABBITMQ_DEFAULT_PASS: "rabbitmq"
          RABBITMQ_DEFAULT_VHOST: "/"
        ports:
          - "15672:15672"
          - "5672:5672"
          - "1883:1883"

     and then run that (you must have Docker and docker-compose installed in your computer)

    docker-compose up 

    Make sure to note the IP adress of the RabbitMQ server, we will need it for the Arduino configuration code below.

    // Update these with values suitable for your network.
    const char* ssid = "your_ssid";
    const char* password = "your_password";
    const char* mqtt_server = "192.168.0.121"; 
    const char* mqtt_user = "rabbitmq";
    const char* mqtt_pass= "rabbitmq";

     You can now upload the arduino code either via the Arduino IDE or the arduino-cli https://github.com/arduino/arduino-cli with the following commands

    arduino-cli compile --fqbn esp8266:esp8266:nodemcu .
    arduino-cli upload -p /dev/ttyUSB0 --fqbn esp8266:esp8266:nodemcu .

     After that you must have Arduino and RabbitMQ running. To see the published messages run the following Python script

    # test_sub.py
    import paho.mqtt.client as mqtt
     
    def on_connect(client, userdata, flags, rc):
        print("Connected to broker")
     
    def on_message(client, userdata, message):
        print("Received message '" + str(message.payload) + "' on topic '"
            + message.topic + "' with QoS " + str(message.qos))
    
    client = mqtt.Client()
    client.username_pw_set("rabbitmq", password='rabbitmq')
    client.connect("192.168.0.129", 1883) 
    
    client.on_connect = on_connect       #attach function to callback
    client.on_message = on_message       #attach function to callback
    
    client.subscribe("") 
    client.loop_forever()                 #start the loop

     to run that you must have the paho client installed

    pip install paho-mqtt

    and then run the python script

    python test_sub.py

    you must see in your terminal...

    Read more »

  • Testing Arduino ECG Module

    Alex Karadimos06/13/2019 at 19:09 0 comments

    You can find the following code, which is shown being executed in the above images, at this github repository

    #include <SPI.h>
    #include <Ethernet.h>
    #include <PubSubClient.h>
    
    #define ORG "*******"
    #define DEVICE_TYPE "*******"
    #define DEVICE_ID "*******"
    #define TOKEN "*******"
    
    // Update this to either the MAC address found on the sticker on your ethernet shield (newer shields)
    // or a different random hexadecimal value (change at least the last four bytes)
    byte mac[]    = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
    // char macstr[] = "xxxxxx";
    // // Note this next value is only used if you intend to test against a local MQTT server
    // byte localserver[] = {192, 168, 1, 98 };
    // Update this value to an appropriate open IP on your local network
    byte ip[]     = {192, 168, 1, 20 };
    
    //=================================================================================================
    
    char server[] = ORG ".messaging.internetofthings.ibmcloud.com";
    char authMethod[] = "use-token-auth";
    char token[] = TOKEN;
    char clientId[] = "d:" ORG ":" DEVICE_TYPE ":" DEVICE_ID;
    
    const char publishTopic[] = "iot-2/evt/status/fmt/json";
    const char responseTopic[] = "iotdm-1/response";
    const char manageTopic[] = "iotdevice-1/mgmt/manage";
    const char updateTopic[] = "iotdm-1/device/update";
    const char rebootTopic[] = "iotdm-1/mgmt/initiate/device/reboot";
    
    // Callback function header
    void callback(char* publishTopic, char* payload, unsigned int payloadLength);
    //=================================================================================================
    
    
    EthernetClient ethClient;
    PubSubClient client(server, 1883, callback, ethClient);
    
    float getECG(void);
    String payload;
    
    
    void setup()
    {
        
      // Start the ethernet client, open up serial port for debugging, and attach the DHT11 sensor
        Ethernet.begin(mac, ip);
        Serial.begin(9600);
    
        if (!client.connected()) {
            Serial.print("Reconnecting client to ");
            Serial.println(server);
            
            // client.subscribe("inTopic");
        while (!client.connect(clientId, authMethod, token)) {
            Serial.print(".");
            //delay(500);
        }
        Serial.println();
        }
    
    }
    
    void loop()
    {
    
          //float ECG = getECG();    
        int ecg=analogRead(0);    
        payload = "{\"d\":";
        payload += ecg;
        payload += "}";
        Serial.print("Sending payload: ");
        Serial.println(payload);
        client.publish(publishTopic, (char *)payload.c_str());
        
         //delay(1);
        client.loop();
    }
    
    
    void callback(char* publishTopic, char* payload, unsigned int length) {
        // In order to republish this payload, a copy must be made
        // as the orignal payload buffer will be overwritten whilst
        // constructing the PUBLISH packet.
    
        // Allocate the correct amount of memory for the payload copy
        byte* p = (byte*)malloc(length);
        // Copy the payload to the new buffer
        memcpy(p,payload,length);
        // client.publish("outTopic", p, length);
        client.publish(publishTopic, (char *)payload);
        // Free the memory
        free(p);
    }

View all 7 project logs

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates