Introduction: Automated Variable Oxygen Chamber

What can this device do?

1. Mix air and nitrogen to produce a gaseous mixture with a specific oxygen percentage between 0% and 21% (hypoxia to normoxia)

• This oxygen controller mixes air and nitrogen in a specific ratio. There is a feedback mechanism built in that utilizes an oxygen sensor to keep the oxygen percentage constant.

2. Automate the changes in oxygen percentage on a schedule

• A graphical user interface (GUI) I built in python allows a user to set intervals of time for a certain oxygen percentages. This means you can type in a program such as 1% oxygen for 4 hours and 13% oxygen for 10 hours that will repeat for a set number of days.

3. Fluctuate the supply of the gaseous mixture fed to cells, which mimics the effects of the cardiovascular and respiratory systems

• Cells in our body do not have a continuous supply of oxygen due to the cardiovascular and respiratory systems (Paper 1). Several publications (Paper 2) have reported higher amplitude oscillations in percent oxygen at the cellular level in tumor cells, and my project attempts to simulate these effects. Specifically, this device turns on or off the output gas mixture of air and nitrogen fed to cells at frequencies between 0-200 mHz (values picked from paper 2).


The goal of this project was to take existing lab equipment and inexpensively modify it to give it additional features that would prove useful in cancer research. I worked in the Laboratory of Integrative Tumor Ecology (L.I.T.E.) at Virginia Tech in Blacksburg, VA under Dr. Scott Verbridge and Ishan Goswami to create this device. It is currently being used in biological studies that will hopefully be published in the upcoming year. As a side note, you do not need to implement all three features I listed above. For some biological studies using this device, the third feature I listed is not being utilized.


If you are going to replicate this project, know that you will have to most likely change a good amount of the hardware and software to get your setup to work how you would like. This was a very customized project because I had to work on a tight budget and schedule with a set amount of laboratory equipment already in the lab.

Step 1: Mixing Air and Nitrogen to Achieve 0% Through 21% Oxygen

To achieve an oxygen percentage that is less than the normal atmospheric oxygen percentage of 21%, I mixed nitrogen gas from a large gas canister with air from an air pump. Depending on what the desired oxygen percentage was, I either added more nitrogen or added more air by opening or closing electronic valves. The gas valves for both nitrogen and air adjusted automatically depending on what the oxygen sensor was reading.

From the graphs above, you can see the results of two experiments I ran on the device to test its capabilities.

The first graph is a three-hour test that fluctuates between 1% oxygen and 21% oxygen. For 21% oxygen, only air is being pumped into the gas mixing chamber. For 1% oxygen, nitrogen is pumped in until the oxygen percentage goes below 1%, at which point a small amount of air will be added to bring the oxygen percentage back up. Then, air and nitrogen will be added automatically to keep the oxygen target at a stable level of 1%.

The second graph shows an experiment with the oxygen percentage switching between 1% and 10%. As you can observe from the graphs, the changes in oxygen percentage were much slower than in the first test. This was due to this second test being run on on the first iteration of the device I built (the large Thermo Scientific incubator), which will be further discussed in the next step.

You could easily add more than just two fluctuating values by entering in a different program to run in the python GUI.

Step 2: Choosing a Gas Mixing Chamber

To begin building this oxygen controller, you will have to choose the kind of setup you would like. The volume of the container where the air and nitrogen mix (what I'm going to call the gas mixing chamber) has a huge impact on the feedback mechanism that controls the air and nitrogen valves. I've experimented with multiple kinds of gas mixing chambers and will walk you through the two versions of this project I've built giving you the pros and cons of each one. I built version 1 first and then created version 2, which had several improvements.

Version 1 - Large Thermo Scientific Incubator

My lab already had a Thermo Scientific Series 8000 WJ incubator. I chose to modify one of the ports on this incubator to input the mixture of air and nitrogen while allowing incubator's contents to output enough so that the internal gas pressure would not get too high. I created a 3D printed part that allowed me to do this (the purple 3 pronged plastic part pictured above). This version's advantages were that the incubator was already temperature and humidity controlled and had a large gas mixing chamber, which I found contributed to a very stable feedback mechanism. The downsides of this design included the fact that large changes in oxygen percent sometimes took 10-45 minutes due to the large volume. Another downside was that I was unable to implement the simulation of the cardiovascular and respiratory systems in this design because air and nitrogen mixed where the cells were located and not in a separate chamber like in version 2.

Version 2 - Small Plexigass Box (Newer and updated with additional features)

I created a secondary version to eliminate the need for an expensive incubator, to make the system portable, to make the system smaller, and to implement the simulation of the cardiovascular and respiratory systems. This version is more complex in terms of both the hardware and software. For hardware, this design requires an extra air pump and three extra gas flow sensors. The second air pump is located inside of the plexiglass to pump the mixture of gas out. For software, there are additional C++ Arduino functions that utilize the extra flow sensors to more precisely control the variable electronic gas valves for air and nitrogen. I would recommend building a system like this only if you are able to modify C++ Arduino code and have the time to change my algorithm to work with your system.

Step 3: The Feedback Loop Oxygen Sensor From PreSens

When I began searching for an oxygen sensor I knew I needed to find one that was:

1) Accurate;

2) Able to communicate with custom software over RS-232, UART, or USB;

3) Reliable in the long-term; and

4) Reusable in other lab experiments outside this project.

After talking with several companies and comparing prices, I found that the OXY-1 ST RS-232 paired with the profiling oxygen microsensor PM-PSt7 from PreSens was a great combination for this project. While I am sure there are other options, this oxygen sensor was able to either communicate with PreSens' Measurement Studio 2 software or custom software, which was important for both my project and future projects that my lab was going to do with this oxygen sensor.

The device from PreSens had an extensive communication protocol manual that I read through so that I could send commands to it and read data from it. I used the RS-232 to USB cable included to plug the device into a Windows 10 PC so that I could talk to the device with the python serial communication module called pyserial. I manually coded the commands that needed to be sent to the OXY-1 ST and also wrote functions to decode the data coming from the oxygen sensor.

The only downside of this oxygen sensor configuration is the price tag for all of the components, which totaled $2514.46

OXY-1 ST RS-232 - $2000

Profiling Oxygen Microsensor PM-PSt7 - $209.45

Evaluation Board for EOM-O2-FDM - $157.77

Pt100 Temperature Probe - $147.24

Step 4: The Electrical Components

The list of electrical components are below. I will go into further detail about them in the next steps.

793 GPH Air Pump - $37 each (used 2) (not pictured in schematic)

Variable gas valves - $29 each (used 3)

L298N Motor Driver Circuits - $7 each (used 2)

Arduino UNOs -$24 each (used 2)

Laser Diodes - $6 for pack of 10 (used 2)

Photoresistors - $6 for pack of 30 (used 2)

Omron Flow Sensor - $216

Omron Flow Sensor Cable - $10

12V Power Supply - $7


Step 5: The Variable Gas Valves

I found some relatively inexpensive 12V valves off of amazon that worked for this project. These valves are different than a lot of the other ones I found because they are variable and not just on/off. These utilize a motor to open and close a ball valve and have built in circuitry to stop the motor when the valve is all the way open or all the way closed.

The downside to these motors was that they have very large diameters, which was unnecessary for the amount of gas flowing through them. If I were to redo this project, I would find different valves that were meant for gas flow. Just opening the valves slightly let in a lot of air or nitrogen and there was no way to determine how much the valve was open. This became a problem when I was mixing the gasses in a small volume in version 2 of the device. Because I was trying to control the oxygen percentage accurately (within 1% oxygen), I needed a way to only add a very small amount of either gas. I will explain in the next step how I used gas flow meters to remedy this problem.

As you can see from the included schematic, applying 12V across the red and yellow wires (ground) would open the valve and applying 12V across the blue and yellow wires would close the valve. While there are many ways to accomplish applying the 12V to the valve, such as relays, I ended up using a L298N based motor driver circuit. The reason I chose the L298N was the integrated circuit (IC) was able to drive enough current, was inexpensive, could be switched with a microcontroller, and could control two valves per IC. The L298N also had a way to decrease the speed at which the valves opened or closed because of a built in pulse width modulation wire that the microcontroller I used could manage.

Step 6: D.I.Y. Gas Flow Sensors (for Version 2 Only)

Because of financial limitations, I had to create my own gas flow sensors instead of purchasing expensive sensors. This step will explain why I had to create my own gas flow sensors using a laser diode and a photoresistor.

As I mentioned in the last step, the version 2 device required gas flow sensors because of the gas valves that I had chosen. When trying to achieve a specific oxygen percent in a small volume, small amounts of air or nitrogen needed to be added. The built in valve circuitry did not have a way to know the position of the valve, meaning I had no idea how much gas was flowing through. To be able to just add a very small amount of gas, I created a gas flow sensor that would output a 5V signal when there was gas flowing and 0V signal when there was no gas flowing.

I created a cheap and simple gas flow sensor because purchasing a high quality, reliable gas flow sensor for the small amount of gas flow we had (0-5 Liters/min) cost around $200. I converted a manual 0-5 L/min adjustable flow meter to one that could put out a signal when any gas was flowing through it. To detect when gas was flowing, I set up a laser diode pointing opposite to a photoresistor on either side of an adjustable flow meter. When gas stopped flowing, the laser's beam would be blocked by the small black ball inside of the adjustable flow meter. The pictures above illustrate how the sensor works.

The sensors that I created do not record how much gas is flowing; they sense only if gas is flowing at all. While this was sufficient for the algorithm to keep the oxygen percentage stable, my lab ended up needing to record the precise amount of gas flowing through the gas valve that simulated the effect of the cardiovasular and respiratory systems. I chose the Omron D6F-10A6 to record this information, which is going to be used for future publications that need graphical information on the gas flow oscillations.

Step 7: The Arduino Software

The software was written in both python 3 and C++. The python GUI that runs on a Windows 10 PC is discussed in the next step.

As I was saying in the "Choosing a Gas Mixing Chamber" step, above, the different gas mixing chambers have very different software. The reason I had two Arduino UNOs was due to the more complex algorithm that was run on version 2 of this device. I also implemented debugging messages to be sent out over I2C to a third Arduino UNO since the UART ports were taken for the Arduino to python communication. For more information on that, please look at the comments in the .ino (Arduino) files.

Below I will discuss the algorithms implemented to maintain an oxygen percentage between 1% - 20%. In both algorithms, 0% oxygen meant the nitrogen valve was opened all the way and 21% oxygen meant the air valve was opened all the way. The variables seen in the second picture are as follows:


gui_value -> the oxygen percentage that the device is trying to reach that is set by the python software

sensor_value -> the sensor's oxygen percentage

duty_cycle -> (only used in version 2) when manual controls are on, this is the python software's set value for the percent of the interval that a valve is open

interval -> (only used in version 2) when manual controls are on, this is the python software's set value for the time period, in seconds

override_checkbox -> (only used in version 2) toggle switch for manual control over the duty cycle and interval used for debugging purposes

ACK -> acknowledgement string

flow_rate -> the value of the Omron D6F-10A6 flow sensor in L/min

oscillation_frequnecy -> the frequency, in millihertz, with which the valve simulating the cardiovascular and respiratory systems would open and close


Version 1 - Large Thermo Scientific Incubator Algorithm

Arduino 1:

This Arduino received both the oxygen sensor percent and the desired software set oxygen percent. From there, it would send back an acknowledgement string "ACK" to tell python the values were received. Then, this Arduino would adjust the air and nitrogen valves accordingly. If there was too little oxygen, the nitrogen valve was closed and the air valve was opened. If there was too much oxygen, the nitrogen valve was opened and the air valve was closed. When the desired oxygen percentage was reached, both gasses would be shut off until the oxygen percentage would inevitably drift. At that point, either air or nitrogen would be added to keep the oxygen percentage stable.

Arduino 2:

Because I was pumping in gas into a closed container, I was worried about over pressurizing the incubator, so as a safety feature, I added a way for gas to flow out. When either air or nitrogen was being pumped in, the second Arduino would open a pressure relief valve. When the desired oxygen percentage was reached, however, I would close the pressure relief valve.

Version 2 - Small Plexigass Box Algorithm

Arduino 1:

This Arduino's algorithm was not as simple as opening or closing the air or nitrogen valve for a period of time and waiting until the desired oxygen percentage was reached. For oxygen percentages less than or equal to 11%, the nitrogen valve was open while the air valve was opened very slightly and then shut at regular intervals. For oxygen percentages greater than 11%, the air valve was open while the nitrogen valve was opened very slightly and then shut at regular intervals.

The flow meters I created were what allowed for the valves to be opened very slightly. They would output a 5V signal so that the Arduino could detect the moment gas started flowing. This signal told the Arduino when to stop opening the valve.

The amount of time the valve that was being repeatedly opened and closed was open was determined by two variables: duty_cycle and interval. The duty cycle was the percentage of the interval that the valve was open. The interval was how often the opening and closing occurred. Depending on the desired oxygen percentage, both the duty cycle and interval variable would change. I implemented a way for python to control these two variables to help with the process of finding the exact duty cycle and interval that corresponded to an oxygen percentage.

Arduino 2:

This Arduino was in charge of simulating the cardiovascular and respiratory systems by opening and closing a valve at certain intervals while also reading the flow rate. It would read in the flow rate as an analog signal from the Omron D6F-10A6 and then transmit the average of the past five flow rate values to python. When python received the averaged flow rate, it would send back this arduino an oscillation frequency in millihertz and an acknowledgement "ACK" separated by a comma. The oscillation frequency was the frequency at which the valve would switch from being open to closed between 0-200mHz.

Step 8: The Python Software

The python software was written in python 3 using the pyserial and tkinter modules. It was responsible for reading the oxygen sensor over a USB cable and sending the desired oxygen percentage to the corresponding arduino. The python software also recorded the date, time, measurement number, GUI value, sensor value, and temperature to a .TXT file each time a new program was run.

There are two python files necessary for running this device: "" and "" I would recommend that you have both files in the same folder and run "" You will also need to edit the COM ports of the Arduino 1, Arduino 2, and the oxygen sensor as those will most likely be different.

To begin running the software, you need to enter both percent oxygen values, the amount of time in minutes for each value, the oscillation frequency (if using version 2), the total run time in minutes. Then, click "begin." The input text boxes at the bottom with the duty cycle, the interval, and override checkbox are for debugging purposes if using version 2, as explained in the previous step.

The python software will begin to look for Arduino 1 and Arduino 2 at the start of the program. Once they are found, the rest of the program will begin.

I've attached all of the software I've written for the project in easy to navigate folders.

Good luck on creating this device and please feel free to message me with any questions!