The Rate of the Reaction Project¶
Description¶
The rate of the reaction project is composed of a carbon dioxide sensor that in located on the tight lid of a jar. When chemicals are added to the jar, a chemical reaction takes place, and carbon dioxide forms. The sensor measures the amount of carbon dioxide produced per time.
Learning Objectives¶
- Rate of a chemical reaction
- Design and make an application based on the engineering design process
- Replicate the wiring connection and the Python code used on the Raspberry Pi
- Relate science concepts to real-life applications
Materials Needed¶
- Raspberry Pi with micro SD card with Raspbian
- Breadboard & Jumper wires
- Carbon dioxide sensor
- Glue gun
- Transparent jar with a tight lid
- Baking soda and vinegar
Setup and Functionality¶
When vinegar and acid are added together and the jar is closed, carbon dioxide gas is produced. The amount of the gas produced per time indicates the rate of the reaction.
Circuitry and Electronics¶
The Raspberry Pi doesn’t have an analog input pin. So to read the analog output of the sensor, we need to use an analog to digital converter (ADC), in this case an MCP3008.
- In this case, connect:
- The VCC to 5V
- The GND to a ground pin
- The analogue pin to CH0 (pin 1) of the MCP3008

- For the MCP3008, connect:
- MCP3008 VDD to Raspberry Pi 3.3V
- MCP3008 VREF to Raspberry Pi 3.3V
- MCP3008 AGND to Raspberry Pi GND
- MCP3008 DGND to Raspberry Pi GND
- MCP3008 CLK to Raspberry Pi SCLK (pin 23)
- MCP3008 DOUT to Raspberry Pi MISO (pin 21)
- MCP3008 DIN to Raspberry Pi MOSI (pin 19)
- MCP3008 CS/SHDN to Raspberry Pi CE0 (pin 24)
The wiring of the Raspberry Pi to the breadboard, ADC converter and the sensor are shown in the figure below:

Programming¶
from spidev import SpiDev
import time
import math
import sys
class MCP3008:
def __init__(self, bus = 0, device = 0):
self.bus, self.device = bus, device
self.spi = SpiDev()
self.open()
def open(self):
self.spi.open(self.bus, self.device)
def read(self, channel = 0):
adc = self.spi.xfer2([1, (8 + channel) << 4, 0])
data = ((adc[1] & 3) << 8) + adc[2]
return data
def close(self):
self.spi.close()
class CO2():
############### Hardware Related Macros ###############
CO2_PIN = 0 # define which analog input channel you are going to use (MCP3008)
ADC_FACTOR = 2100 # define the factor which to divide the readings of the MCP3008
############### Software Related Macros ###############
READ_SAMPLE_INTERVAL = 50 # define how many samples you are going to take in measurment operation
READ_SAMPLE_TIMES = 5 # define the time interal(in milisecond) between each samples
############### Application Related Macros ###############
GAS_CO2 = 0
def __init__(self, analogPin=0, adcFactor=ADC_FACTOR):
self.ADC_FACTOR = adcFactor
self.CO2_PIN = analogPin
self.adc = MCP3008()
self.CO2Curve = [2.602,0.324,-0.0422]# two points are taken from the curve. <<CO2>>
# with these two points, a line is formed which is "approximately equivalent"
# to the original curve.
# data format:{ x, y, slope}; point1: (lg400, 0.324), point2: (lg10000, 0.265)
def CO2Percentage(self):
val = {}
read = self.CO2Read(self.CO2_PIN)/self.ADC_FACTOR
val["GAS_CO2"] = self.CO2GetGasPercentage(read, self.GAS_CO2)
return val
############### CO2Read ###############
# Input: CO2_pin - analog channel
# Output: Average value of the sensor
# Remarks: This function reads several samples between intervals defined at the start of the script.
def CO2Read(self, CO2_pin):
v = 0.0
for i in range(self.READ_SAMPLE_TIMES):
v += self.adc.read(CO2_pin)
time.sleep(self.READ_SAMPLE_INTERVAL/1000.0)
v = v/self.READ_SAMPLE_TIMES
return v
############### CO2GetGasPercentage ###############
# Input: value - Voltage measurement from sensor
# gas_id - target gas type
# Output: ppm of the target gas
# Remarks: This function passes different curves to the CO2GetPercentage function which
# calculates the ppm (parts per million) of the target gas.
def CO2GetGasPercentage(self, value, gas_id):
if ( gas_id == self.GAS_CO2 ):
return self.CO2GetPercentage(value, self.CO2Curve)
return 0
############### CO2GetPercentage ###############
# Input: value - Voltage measurement from sensor
# pcurve - pointer to the curve of the target gas
# Output: ppm of the target gas
# Remarks: By using the slope and a point of the line. The x(logarithmic value of ppm)
# of the line could be derived if y(voltage value) is provided. As it is a
# logarithmic coordinate, power of 10 is used to convert the result to non-logarithmic
# value.
def CO2GetPercentage(self, value, pcurve):
return math.pow(10,(value-pcurve[1])/pcurve[2] + pcurve[0])
CO2 = CO2();
while True:
perc = CO2.CO2Percentage()
sys.stdout.write("\r")
sys.stdout.write("\033[K")
sys.stdout.write("CO2: %g ppm" % perc["GAS_CO2"])
sys.stdout.flush()
time.sleep(0.1)
Science Concepts and Skills¶
Students will learn about the rate of the reaction, chemical properties of matter, reactants, products, chemical equation, and balancing chemical equations.
When acetic acid (vinegar) is added to sodium bicarbonate (baking soda), carbon dioxide gas is produced based on the following equation:
NaHCO3 + CH3COOH → CO2+ H2O + NaCH3COO
baking soda (sodium bicarbonate) plus vinegar (acetic acid) yields carbon dioxide gas plus water plus sodium acetate
The equation can also be written as:
NaHCO3 + HC2H3O2 → NaC2H3O2 + H2O + CO2
The amount of carbon dioxide produced at certain time intervals is recorded by the sensor and the data is collected.
Students can use the data collected to learn or practice graphing using various software such as Google sheets or Excel and will learn how to find the rate of the reaction from the graph.
The rate of the reaction is calculated as the slope of the best fit line
Slope=y2-y1/x2-x1
where y2 and y1 are values on the y-axis that indicate amount of carbon dioxide produced (change in amount) and x2 and x1 indicate time (change in time)
Rate of reaction=y2-y1/x2-x1 which is rise over run indicating the amount of gas produced per time.
Flex your brain! Can you build a device that would measure the rate of an endothermic or exothermic chemical reaction if no gas is produced?