We’ve been prototyping a DIY oxygen concentrator with a target of 15 LPM at 90%+ concentrated oxygen. We are releasing the designs and code here of the progress we’ve made With OxiKit - let’s get this Arduino code and machine optimized folks. It’s FREE for anyone to build.
The goal: attack Covid-19 at its START by creating the least expensive Do it Yourself o2 concentrator that any handyman can build using commonly accessible parts from local hardware stores. And we’ve done it!!!
View the interview in the attached Dropbox link with Chief Medical Director Doctors (John Hopkins - Harvard - Kaisar). The interview details the “Silent Hypoxia” that the Coronavirus triggers. Simply put: Covid-19 suffocates patients without them knowing it’s happening. And they need access to concentrated oxygen FAST. Oxygen starts dropping, cells start dying. Get o2 fast, mitigate the heck out of Covid-19.
OxiKit is part of a large coalition integration project by members of the Pillar Tribe. The Pillar Tribe is made up of over 100 Fortune 100 Executives, Billionaires, Medical Directors, Doctors Engineers and Scientists worming begins the scenes in a confidential format to focus.
We are ready to begin exposing some of the work we are doing publicly.
We have the support of a fortune 100 company to provide the highest grade zeolite needed to fill the sieves.
See the infographic of the full plan, videos of the OxiKit and interviews with the docs regarding this shield mission project by the pillar tribe.
Help us help the world. We will release step by step video instructions for free along with the code for free to the world how to build this 15 LPM Oxygen Concentrator with a target of 90%+ concentrated oxygen.
Hello all, Danger here. I'm the builder on this project and have only very basic Arduino coding skills, but the program we are running is very simple so its been enough. I would like to add some sensors and a display, but our real issue is we are working to improve the air efficiency. We have achieved 90% at 15LPM with our 4th prototype, but its using too much air to be practical. I have a large Ingersol Rand compressor and it can keep up, but none of the consumer grade compressors we have tested will.
So what we really need is someone with the engineering skill to help us figure this out. Lots of smart people here, so...
// Full program for Arduino Uno control of Oxycon Relays and LCD units.
// Edited: 04/29/20
// Author: Robert Danger Byrd
// For Version Olly Oxy
// RELAY PIN ASSIGNMENT
//**************************************************************************
int Sieve_A_Valve = 5; //Defined Pin as Variable
int Sieve_B_Valve = 6; //Defined Pin as Variable
int PreCharge_Valve = 7; //Defined Pin as Variable
int Fan = 8; //Defined Pin as Variable
// VARIABLE CREATION
//**************************************************************************
unsigned long Production_Delay; //delay variable creation
unsigned long Flush_Delay; //delay variable creation
unsigned long PreCharge_Delay; //delay variable creation
unsigned long Relay_Test_Delay; //delay variable creation
//**************************************************************************
void setup()
{
// STARTUP
//**************************************************************************
// Serial Port initialization
Serial.begin(9600);
// SET PIN MODE FOR PINS IN PROGRAM
//**************************************************************************
pinMode(Sieve_A_Valve, OUTPUT);
pinMode(Sieve_B_Valve, OUTPUT);
pinMode(PreCharge_Valve, OUTPUT);
pinMode(Fan, OUTPUT);
// SET DELAY TIMING HERE
//**************************************************************************
Relay_Test_Delay = 1000; //delay variable in milliseconds
Production_Delay = 4600; //delay variable in milliseconds
Flush_Delay = 400; //delay variable in milliseconds
PreCharge_Delay = 400; //delay variable in milliseconds
//**************************************************************************
/* Notes about the Arduino relay module pins from https://randomnerdtutorials.com/guide-for-relay-module-with-arduino/
The LOW-voltage side has two connectors, each with three sockets:
common (COM),
NC (Normally Closed): the normally closed configuration is used when you want the relay to be closed by default, meaning the current is fHIGHing unless you send a signal from the Arduino to the relay module to open the circuit and stop the current.
NO (Normally Open): the normally open configuration works the other way around: the relay is always open, so the circuit is broken unless you send a signal from the Arduino to close the circuit.
*/
// LOW means the relay is OFF because this code is written for the NC (Normally Closed) wiring setup.
// Set all relays to LOW at power up or Arduino reset.
// RELAY TEST SEQUENCE
//**************************************************************************
Serial.println("Relay Test Sequence");
delay(Relay_Test_Delay);
digitalWrite(Sieve_A_Valve, HIGH); //Turn on relay
delay(Relay_Test_Delay);
digitalWrite(Sieve_B_Valve, HIGH); //Turn on relay
delay(Relay_Test_Delay);
digitalWrite(PreCharge_Valve, HIGH); //Turn on relay
delay(Relay_Test_Delay);
digitalWrite(Fan, HIGH); //Turn on relay
delay(Relay_Test_Delay);
Serial.println("Relay Test Sequence Complete");
delay(Relay_Test_Delay);
Serial.println("Program Starting...");
delay(Relay_Test_Delay);
// FAN CONTROL
//**************************************************************************
digitalWrite(Fan, HIGH);
Serial.println("Fan Switched On");
}
void loop()
{
//CYCLE 1
//**************************************************************************
Serial.println("Sieve A Charge / Sieve B Purge");
digitalWrite(Sieve_A_Valve, HIGH);
digitalWrite(Sieve_B_Valve, LOW);
digitalWrite(PreCharge_Valve, LOW);
delay(Production_Delay);
//CYCLE 2
//**************************************************************************
Serial.println("Sieve A Charge / Sieve B Purge / Flush/PreCharge");
digitalWrite(Sieve_A_Valve, HIGH);
digitalWrite(Sieve_B_Valve, LOW);
digitalWrite(PreCharge_Valve, HIGH);
delay(Flush_Delay) ;
//CYCLE 3
//**************************************************************************
Serial.println("Sieve A Charge / Sieve B Charge / Flush/PreCharge");
digitalWrite(Sieve_A_Valve, HIGH);
digitalWrite(Sieve_B_Valve, HIGH);
digitalWrite(PreCharge_Valve, HIGH);
delay(PreCharge_Delay);
//CYCLE 4
//**************************************************************************
Serial.println("Sieve A Purge / Sieve B Charge");
digitalWrite(Sieve_A_Valve, LOW);
digitalWrite(Sieve_B_Valve, HIGH);
digitalWrite(PreCharge_Valve, LOW);
delay(Production_Delay);
//CYCLE 5
//**************************************************************************
Serial.println("Sieve A Purge / Sieve B Charge / Flush/PreCharge");
digitalWrite(Sieve_A_Valve, LOW);
digitalWrite(Sieve_B_Valve, HIGH);
digitalWrite(PreCharge_Valve, HIGH);
delay(Flush_Delay);
//CYCLE 6
//**************************************************************************
Serial.println("Sieve A Charge / Sieve B Charge / Flush/PreCharge");
digitalWrite(Sieve_A_Valve, HIGH);
digitalWrite(Sieve_B_Valve, HIGH);
digitalWrite(PreCharge_Valve, HIGH);
delay(PreCharge_Delay) ;
}
I recommend you to do an Auto Format (Tools > Auto Format in the Arduino IDE or Ctrl + B in the Arduino Web Editor) on your code to make it easier for people to read.
It seems to me that, assuming you don't have any leaks, the only way to increase the air efficiency is to reduce the amount of purging. How do the commercial oxygen concentrators determine the purge timing? Is it just done on a fixed interval like yours, or is it a closed loop system that uses a sensor (back-pressure or O2 concentration?) to determine the timing?
I've been using a collection of 2nd hand medical oxygen concentrators to supply oxygen to my glassblowing torches for the last 20 years, but only have a basic understanding of how the system works.
I'd think getting the air from a standard air compressor clean and dry enough would be a challenge.
Thanks for the feedback on formatting, I'll look into that.
And you are right about reducing purge time, however we must completely cycle the sieves for maximum efficiency. We are making progress though and now are producing 15LPM at 90% w 20PSI input pressure, which is a big step forward.
We have achieved the efficiency we need to make this practical. Now we seek engineering minds to help us refine it further and continue to improve the design.
Here is the latest code, and yes I did run the autoformat tool
// Full program for Arduino Uno control of Oxycon Relays and LCD units.
// Edited: 05/20/20
// Author: Robert Danger Byrd
// For Version Dagney Oxy
// RELAY PIN ASSIGNMENT
//**************************************************************************
int Sieve_A_Valve = 5; //Defined Pin as Variable
int Sieve_B_Valve = 6; //Defined Pin as Variable
int PreCharge_Valve = 7; //Defined Pin as Variable
int Fan = 8; //Defined Pin as Variable
// VARIABLE CREATION
//**************************************************************************
unsigned long Relay_Test_Delay; //delay variable creation
unsigned long Startup_Purge_Delay; //delay variable creation
unsigned long Production_Delay; //delay variable creation
unsigned long Flush_Delay; //delay variable creation
unsigned long PreCharge_Delay; //delay variable creation
// STARTUP
//**************************************************************************
// Serial Port initialization
Serial.begin(9600);
// SET PIN MODE FOR PINS IN PROGRAM
//**************************************************************************
pinMode(Sieve_A_Valve, OUTPUT);
pinMode(Sieve_B_Valve, OUTPUT);
pinMode(PreCharge_Valve, OUTPUT);
pinMode(Fan, OUTPUT);
// VALVE RELAY TEST SEQUENCE
//**************************************************************************
Serial.println("Relay Test Sequence");
digitalWrite(Sieve_A_Valve, HIGH); //Turn on relay
delay(Relay_Test_Delay);
digitalWrite(Sieve_B_Valve, HIGH); //Turn on relay
delay(Relay_Test_Delay);
digitalWrite(PreCharge_Valve, HIGH); //Turn on relay
delay(Relay_Test_Delay);
Serial.println("Valve Relay Test Sequence Complete");
delay(Relay_Test_Delay);
// STARTUP PURGE
//**************************************************************************
Serial.println("Relay Test Sequence");
digitalWrite(Sieve_A_Valve, HIGH); //Turn on relay
digitalWrite(Sieve_B_Valve, HIGH); //Turn on relay
digitalWrite(PreCharge_Valve, HIGH); //Turn on relay
delay(Startup_Purge_Delay);
// FAN CONTROL
//**************************************************************************
Serial.println("Program Starting...");
delay(Relay_Test_Delay);
digitalWrite(Fan, HIGH);
Serial.println("Fan Switched On");
}
void loop()
{
//CYCLE 1
//**************************************************************************
Serial.println("Sieve A Charge / Sieve B Purge");
digitalWrite(Sieve_A_Valve, HIGH);
digitalWrite(Sieve_B_Valve, LOW);
digitalWrite(PreCharge_Valve, LOW);
delay(Production_Delay);
//CYCLE 2
//**************************************************************************
Serial.println("Sieve A Charge / Sieve B Purge / Flush/PreCharge");
digitalWrite(Sieve_A_Valve, HIGH);
digitalWrite(Sieve_B_Valve, LOW);
digitalWrite(PreCharge_Valve, HIGH);
delay(Flush_Delay) ;
//CYCLE 3
//**************************************************************************
Serial.println("Sieve A Charge / Sieve B Charge / Flush/PreCharge");
digitalWrite(Sieve_A_Valve, HIGH);
digitalWrite(Sieve_B_Valve, HIGH);
digitalWrite(PreCharge_Valve, HIGH);
delay(PreCharge_Delay);
//CYCLE 4
//**************************************************************************
Serial.println("Sieve A Purge / Sieve B Charge");
digitalWrite(Sieve_A_Valve, LOW);
digitalWrite(Sieve_B_Valve, HIGH);
digitalWrite(PreCharge_Valve, LOW);
delay(Production_Delay);
//CYCLE 5
//**************************************************************************
Serial.println("Sieve A Purge / Sieve B Charge / Flush/PreCharge");
digitalWrite(Sieve_A_Valve, LOW);
digitalWrite(Sieve_B_Valve, HIGH);
digitalWrite(PreCharge_Valve, HIGH);
delay(Flush_Delay);
//CYCLE 6
//**************************************************************************
Serial.println("Sieve A Charge / Sieve B Charge / Flush/PreCharge");
digitalWrite(Sieve_A_Valve, HIGH);
digitalWrite(Sieve_B_Valve, HIGH);
digitalWrite(PreCharge_Valve, HIGH);
delay(PreCharge_Delay) ;
}
And feel free to share the hell out of this Dropbox link to everyone you know...it has the plan...the videos with the docs...the videos of the machine explained...time to roll out soldiers!
Just out of my .. two things I can think of, you probably already did:
Staged concentrator e.g a quick first stage reaching a 60% O2 level, and second stage, having a lower volume, higher concentration input should reach easier 90%? Not sure if this is right, it's quite possible the zeolite stack already does a continuous "staging" internally
Pre-heating or pre-cooling the air - whichever does help (if any) to achieve a better separation with lower pressure Eventually recover the heat/cool back through a heat exchanger if that's a tremendous amount of energy. I don't know, at 15 lpm O2 how much is the primary input air flow? 60lpm? 100?
Zeolite stack/volume shape has any influence? cross section vs length ratio. Are there better/optimal "grades"? Granule/particle sizes?
Hi,
Can you share more details such as type of zeolite used, solenoid valves,Pressure range of operation, how did you separate CO2 from the output O2, How did you separate moisture from air so that water doesn’t clog the zeolites, and they are many more....
I rewrote the code of TheMemberFormerlyKnownAsAWOL, using a single array of structures for cycles parameters and a single function (setValvesAndDelay) executing a cycle; this way all parameters are in a place for visual inspection, and because the function accept a single structure as parameter can't we made mistakes passing parameters in wrong order
DISCLAIMER: compiled but not tested
// RELAY PIN ASSIGNMENT
//**************************************************************************
const byte Sieve_A_Valve = 5;
const byte Sieve_B_Valve = 6;
const byte PreCharge_Valve = 7;
const byte Fan = 8;
// VARIABLE CREATION
//**************************************************************************
const unsigned long Relay_Test_Delay = 0;
const unsigned long Startup_Purge_Delay = 3000;
const unsigned long Production_Delay = 4300;
const unsigned long Flush_Delay = 450;
const unsigned long PreCharge_Delay = 450;
const byte CHARGE = HIGH;
const byte PURGE = LOW;
//------------------------------
// Defines parameters for cycles
typedef struct tagCycleParameters
{
const char *cycleDescription;
const byte sieveAState;
const byte sieveBState;
const byte preChargeState;
const unsigned long cycleDelay;
} CycleParameters;
// six cycles
const CycleParameters cycleParams[] = {
{ "Sieve A Charge / Sieve B Purge", CHARGE, PURGE, PURGE, Production_Delay }, // cycle 1
{ "Sieve A Charge / Sieve B Purge / Flush/PreCharge", CHARGE, PURGE, CHARGE, Flush_Delay }, // cycle 2
{ "Sieve A Charge / Sieve B Charge / Flush/PreCharge", CHARGE, CHARGE, CHARGE, PreCharge_Delay }, // cycle 3
{ "Sieve A Purge / Sieve B Charge", PURGE, CHARGE, PURGE, Production_Delay }, // cycle 4
{ "Sieve A Purge / Sieve B Charge / Flush/PreCharge", PURGE, CHARGE, CHARGE, Flush_Delay }, // cycle 5
{ "Sieve A Charge / Sieve B Charge / Flush/PreCharge", CHARGE, CHARGE, CHARGE, PreCharge_Delay } // cycle 6
};
const int numCycles = sizeof(cycleParams) / sizeof(CycleParameters);
// parameters for startup purge of valves
const CycleParameters startupPurge =
{ "Relay Test Sequence", CHARGE, CHARGE, CHARGE, Startup_Purge_Delay };
//**************************************************************************
// Setup and loop
//
void setup()
{
// STARTUP
//**************************************************************************
// Serial Port initialization
Serial.begin(9600);
// SET PIN MODE FOR PINS IN PROGRAM
//**************************************************************************
pinMode(Sieve_A_Valve, OUTPUT);
pinMode(Sieve_B_Valve, OUTPUT);
pinMode(PreCharge_Valve, OUTPUT);
pinMode(Fan, OUTPUT);
// VALVE RELAY TEST SEQUENCE
//**************************************************************************
Serial.println(F("Relay Test Sequence"));
testValveOn(Sieve_A_Valve);
testValveOn(Sieve_B_Valve);
testValveOn(PreCharge_Valve);
Serial.println(F("Valve Relay Test Sequence Complete"));
delay(Relay_Test_Delay);
// STARTUP PURGE
//**************************************************************************
setValvesAndDelay(startupPurge); // THIS SEEMS TO BE AT ODDS WITH THE COMMENT
// FAN CONTROL
//**************************************************************************
Serial.println(F("Program Starting..."));
delay(Relay_Test_Delay);
digitalWrite(Fan, HIGH);
Serial.println(F("Fan Switched On"));
}
void loop()
{
for (int i=0; i< numCycles; i++)
setValvesAndDelay(cycleParams[i]);
}
//----------------------------------------------
// Helper functions
//----------------------------------------------
// Check valve On state
void testValveOn(const int valve)
{
digitalWrite(valve, HIGH); //Turn on relay
delay(Relay_Test_Delay);
}
// execute a single cycle
void setValvesAndDelay(const CycleParameters ¶ms)
{
Serial.println(params.cycleDescription);
digitalWrite(Sieve_A_Valve, params.sieveAState);
digitalWrite(Sieve_B_Valve, params.sieveBState);
digitalWrite(PreCharge_Valve, params.preChargeState);
delay(params.cycleDelay);
}