For those of you who do not know what a Tricorder is, allow me to explain: In the newer Star Trek series, characters often carry a mobile device used for things like measuring rips in the space-time continuum and declaring “He’s dead, Jim.”
Although I earn my money by dealing in software, I have always had an affinity for hardware: wiring chips and other digital components together. I began with circuits based on standard TTL and CMOS logic chips. One day, I discovered the ATMEL AVR programmable series. My journey continued, and I discovered the coolness of Espressif’s ESP8266. After awhile, I found the ESP32 (WROOM32) for my projects.
I had already done projects involving sensors (i.e. BME280) using the I2C bus. I also had projects that used displays and buttons for visualization and control. What I never had was a good combination of those things, packaged together in a nice case with a battery.
Then Hardkernel popped up with the ODROID-GO--the perfect combination for me. I’ve had an idea for a multisensory device for quite a while. Now was the time to embark on such a project.
The ODROID-GO has an expansion header with 10 Pins. Three of them are power, one is not connected and some are for SPI (which would interfere with the performance of the display). At least two of the pins--GIO15 and GPIO4--were not used by anything else. Just enough for I2C. With the ESP32, I2C can be mapped to almost any IO pin. There is no static mapping. I2C was it!
Now I had to figure out which sensors work with I2C. There are lots of them. After some googling I ended up choosing these:
- BNO055 for orientation (roll, pitch, yaw) and acceleration.
- BME280 for ambient pressure, temperature, and humidity.
- VL53L0X for distance measurement (0-120cm).
- VEML6040 for LIGHT measurement (RGB, LUX).
- VEML6075 for UV measurement (UVA, UVB => UV Index).
- CCS811 to measure CO2 and VOC gas concentrations.
- Mics6417 to measure eight more gases and their concentration.
- MLX90416 to measure the temperature (IR) of objects -70 to 300 degrees Celsius (like those contactless thermometers).
Where to buy the sensors? I decided to look to eBay and its countless Chinese sellers. It takes about a month for the sensors to arrive, but they tend to have the cheapest offers. Of course, I ordered multiples of each type in case I burned one of them. I wouldn’t want to wait another month to get replacements. One usually pays about 3-6€ for a sensor. The exception were the Mics, at about 50€.
After the sensors arrived from China I checked out each of them by attaching them to the ODROID-GO via breadboard, writing little test program to produce serial output and display values on the ODROID’s screen.
I also created some experimental soldered boards to get a better feeling of how it would look in the end.
Schematics (Overall Wiring)
In general, wiring I2C sensors is pretty simple. I2C is a bus type interface. Just connect all SCL and SCK pins together and wire these 2 connections to VCC via resistors (Pullup).
Additionally, provide power (VCC, GND). The standard voltage for sensors is 3.3V. Luckily, the ODROID-GO provides 5V AND 3.3V. Each device in a I2C bus has its own ID. That way the controller (master) can address each sensor (slaves) on the bus. Besides the four pins mentioned, some sensors have additional pins that influence their behavior or let them respond to different I2C addresses.
In my case, it was not that simple to connect all sensors since the VEML sensors use the same I2C address of 0x10. Instead of using tricky logic to get around it, I decided to use an I2C Switch (TCA9543a). The one I chose has three I2C ports. One port communicates with the ESP32 and is the “input” port, while the other two are connected to the sensors. The VEMLs are placed at different ports. The switch can be programmed to hand through the I2C communication to either port 1 or 2.
From a programming perspective, you have to tell the switch to activate port 1 or port 2 and then query the sensors connected to that port. Switch over to the other port and query the rest of the sensors. Not really a big deal.
In the end I came up with this schematic:
I used DesignSparkPCB for all my schematics and then later for transforming the schematics into a PCB design. It is free and I highly recommend it. You will be required to register, but this seems to be mandatory for most things these days and for the value you get out of it, registration is worth it.
One important factor for PCB software is the ability to teach it your own components. I tried to find component libraries for the sensors I used, but couldn’t find any that were freely available. I gave up and just designed them myself, which is possible with this program.
Printed Circuit Board (PCB)
From the schematics you can create a PCB in DesignSparkPCB. Due to an excess of wiring, I don’t think a single layer PCB would be possible. It would seem that a two-sided PCB would be necessary.
Many PCB tools offer automatic wiring. Very often this produces strange wirings, so I opted to route the wires myself. DesignsparkPCB, like all the other tools, helps keep you from forgetting wires.
Red and cyan indicate the wiring on the top and bottom layer. Yellow and blue is for documentation purposes and can be printed on the PCB. That way you easily see which device will be placed and soldered in which position.
Having completed the PCB layout, it now needs to be produced. Some people do this on their own. In the past I also did it on my own, but I never liked the chemistry behind it. Additionally, there are 2 layers involved, which requires a very precise alignment of the layers. I doubt that I would be able to handle this. I decided to have it done by a professional company for about 25€.
To lower the costs for the production I decided against solder resist and documentation printing.
Finally having the PCB in my hand, the mounting of the sensors via soldering was done easily.
Doing my first software tests to see if all sensors could be found by the ESP32, I noticed that I made a mistake in the layout. I intended to have the BME280 on the bottom side of the PCB. Having it soldered on the wrong side, VCC and GND were connected to the wrong pins. The BME quit in smoke. Shit happens, 4€ gone. That is why you order more than one. Luckily, this mistake did not affect the other sensors or the ODROID-GO. The Mics gas sensor costs about 50€ and I only have one of them. Burning this one would hurt way more. The issue was easily resolved. The next BME280 I just soldered on top of the BNO055 orientation sensor.
Software (the UI design)
I am not a designer. Making things pretty is not my thing. I usually work on a functional level. In this project, I wanted to prove myself wrong and do a nice user interface for the Tricorder.
From a functional point of view, it was pretty clear that it is not technically feasible to do a full repaint of a whole screen (320x240 pixel) just to refresh some measurement values, maybe several times a second. The display is just not fast enough for that. Heavy flickering would be the result. Nevertheless, some cool graphic elements would be nice in the UI. This led to the design having some full-size screens with JPG background images and empty graphical areas serving as placeholders inside. In a case where the screen is rendered for the first time, the full background image is drawn and then the sensor values are pasted in. For all subsequent value refreshes, only the placeholder areas for the values have to be redrawn. This improves the responsiveness of the UI.
It was also obvious that there were too many measurement values to put them all into one screen at the same time. I introduced screens that could be rotated using the “A” and “B” button.
The hardest thing was to come up with a particular style for the screen images. I made several attempts and threw them all away. Then an idea popped up. It is a Star Trek Tricorder, so I would do it the Star Trek way. I searched Google Images for Star Trek Tricorder and tons of inspiring pictures appeared. From then on, the design style was clear.
I tried several freely available drawing programs, but ended up with paint.net, which I use for most of my graphical needs.
Software (the control logic)
You can program the ESP32 using Espressif’s SDK (ESP-IDF) directly in C++, but the provided functionality seemed to be on a very basic level. Arduino is a very popular ecosystem to provide some abstraction from the low level while still being C/C++. Another advantage of using Arduino is the fact that a big bunch of libraries exist for all sensors making it very easy to use them.
For Arduino you can use the Arduino IDE, which I started with a few years ago. Then I stumbled about PlatformIO. It comes as plugin for the ATOM or the VS-CODE editor. I used both and found that I liked VS-CODE more.
Getting into detail about how to code for ESP32 in the Arduino world with VS-CODE would bloat this article. ODROID magazine already had articles about coding for the ODROID-GO. It may be more interesting to mention the things you usually do not do in an implementation for the ESP32.
I never had to deal with binary files in my code for the ESP32. The way to do it for the ODROID-GO (and ESP32 in general) is SPIFF. SPIFF is a file system for the ESP32. You can upload binary files into a special area of the ESP32’s flash memory (the SPIFF partition).
For the ODROID-GO there is a collection of libraries you can use to address the hardware of the GO (speaker, buttons, display, even potential sensors). The display library supports the display of JPG files stored in the SPIFF partition.
What you have to do is to upload the JPGs into the ESP using PlatformIO. After doing that, you can program the ESP and access the uploaded files in your code by providing the filenames. That makes it very easy to fill the GO’s screen with a JPG file-- it needs one line of code.
Another thing I had to do was modify some sensor libraries. Those libraries are often written to work with more than one controller, thanks to the Arduino abstraction. This leads to some issues if the ESP32 works differently in some areas. The changes were not too many.
The current state of the software
The following images show the various screens I already designed. As I mentioned before, the screens can be switched back and forth using the A or B button.
The sensors need to be initialized. A good time for a welcome screen. I probably should have cleaned the screen before taking the photo.
The Ambient Screen holds sensor values from the BME, the VEML6040 and VEML6075. This is ambient temperature (in celsius), humidity (in %), pressure (in hPa), light intensity (in LUX) and the UV index (it’s a number indicating how dangerous the current UV level is)
Light Sensor (RGB)
The light view gives detailed information about the distribution of red, green, and blue in the visible light. The exact wavelengths measured by the sensor can be checked in the VEMLs datasheet.
The distribution is presented in a bar graph for red, green, and blue.
The light intensity in LUX was already present in the ambient screen and can be seen here again.
The color temperature indicates if the light is “warm” or “cold”. Higher values indicate cold light (blue), lower ones indicate warm light (red)
The Gases View
The gases view presents measurements from the CCS811 and the Mics sensor. Ten gases in total.
The unit of the measurements is parts per million (ppm). The gases are given by their chemical formulas since the names did not fit into the screen.
- CO - Carbon Monoxide: Can easily cause suffocation. Hard to recover from exposure.
- H2 - Hydrogen: Together with oxygen you have a high chance to blow up your house. Also used for rocket thrusters.
- NO2 - Nitrogen Dioxide: Toxic.
- C2O5OH - Ethanol: Alcohol. I like that stuff in various forms.
- NH3 - Ammoniac: Intense smell. One source can be poop. Not healthy of course.
- CH4 - Methane: Worse than CO2 in terms of greenhouse gas. Inflammable if O2 is present.
- C3H8 - Propane: People use it to fire things.
- C4H10 - Butane: Also inflammable. Camping gas.
- CO2 - Carbon Dioxide: That’s what we exhale and what plants need to live. Causes trouble as a greenhouse gas.
- VOC - Volatile Compound Gases: Substances in gaseous form at room temperature. It is not precisely defined which gases are detected. It is just an indicator. The higher the value the worse it is.
In the screenshot you see that there seems to be Propane and Butane around the Tricorder. This is due to the fact that the Mics gas sensor needs some heat up time before delivering accurate values. I didn’t want to wait 10 minutes to take the picture.
The distance between the Tricorder and an object it is pointed at can range 0 to 120cm. It is displayed in form of a number a bar graph (the white bar).
The temperature of an object is displayed the same way as distance. It is given as a number and a bar graph (red bar). Unit is Celsius.
The orientation was the hardest thing to design a page for. Simple numbers do not provide an intuitive meaning. The current solution is surely not the best. I hope to come up with some better ideas.
To the left, the roll is displayed. If the Tricorder is rolled counterclockwise, then the blue number to the left is displayed at the bottom position (as in the screenshot). If rolled clockwise the number would be displayed in the upper position, as the angle in degrees (0-180).
For the pitch, it is the same. If the Tricorder is directed upwards, the number indicating the rotational angle is displayed in the top position (as in the screenshot). If directed downwards, the number is displayed in the lower position.
The yaw (yellow) is just the angle the Tricorder points to (north, south, east, west), from 0-359.9 degrees. This can be used as compass.
The sensors deliver measurement values. How accurate are those measurements? Without a reference you can’t tell. It is easy to check distance measurement. Temperature becomes harder. The light intensity also requires more effort--for instance, finding a referential measurement device. Almost impossible to verify are the gas concentrations. I intend to see how I can improve here.
Implement things like hold/min/max
If you know multimeters, those devices often have the ability to track minimum, maximum or average values. Freezing the display in order to display a measurement for a longer time is also very common. The Tricorder could need that too. This will make more use of the ODROID’s buttons.
Wireless measurement export?
Measurements are currently only displayed on the ODROID’s display. The ESP32 can work with WiFi and Bluetooth (BLE and classic SPP). The Tricorder could be extended to provide the measurements “over the air”. MQTT and BLE are candidates here. I did both already with the ESP32.
I currently do not see the use case for it in this project. One possible project is a “measurement box”. Its measurements could be displayed using your mobile device. However, for this, the ODROID-GO would not be needed.
I currently only use the BNO055 sensor for roll, pitch, and yaw. It is capable of doing more, such as acceleration measurements (g-forces).
I own a 3D printer. I surely have the plan to create a case for the Tricorder’s electronics that somehow snaps to the ODROID-GO case.