I’ve been testing the Inno-maker IMX462 camera for several experiments over a period of multiple years. It’s a sensor targeted for low light conditions, offered at a low price, and given those features I found that it’s a valuable alternative to the stock Raspberry Pi cams. I also found the image quality sometimes is lacking especially when using it in the low-light conditions where it should actually excel. I’ve dived into some of the details on how we can improve the image quality and found some nice tricks along the way. Recently I decided to ask the manufacturer if they were aware and if they would revision their product in the future. You never know right… But as it turned out, Inno-maker was already aware of some of the issues that I found and actually they already did have a new revision out there. To quote their words:
Thank you very much for the detailed explanation provided in your blog. We truly appreciate the effort you put into documenting your findings. May I know roughly when you purchased our IMX462 camera module? We already solved this issue around the middle of last year by replacing the LDO. The older versions indeed had this problem.
My camera board is bought in 2023 so unfortunately I’m using on of those affected boards. Inno-maker was kind enough to send the newer revision board in order to compare it to the older one. So here I am again, testing the image quality of the Inno-maker IMX462, but this time using the latest revision with LDO fixes.
Left: Inno-maker IMX462 old rev (modified), right: new revLeft: Inno-maker IMX462 new rev, right: old rev (modified)
The tests are as following. I started comparing with the stock lens which contains an IR filter, and then took several pictures with different kind of exposure times (10ms, 100ms, 1s, 10s) and different kind of gain settings (0, 49, 98). I can added an IR light source (3 IR LEDs) and repeated the same process. Afterwards I swapped the stock lens with one where I’ve removed the IR filter from, and redid all once again.
All pictures were taken in Low Conversion Gain mode, which is the default in the linux kernel. Next I’ll share the pictures as I’ve obtained them, no image editing has been done (not even rotation).
stock lens with IR filter, no IR leds
shutter 10ms – gain 0shutter 10ms – gain 49shutter 10ms – gain 98shutter 100ms – gain 0shutter 100ms – gain 49shutter 100ms – gain 98shutter 1s – gain 0shutter 1s – gain 49shutter 1s – gain 98shutter 10s – gain 0shutter 10s – gain 49shutter 10s – gain 98
stock lens with IR filter + IR leds
shutter 10ms – gain 0shutter 10ms – gain 49shutter 10ms – gain 98shutter 100ms – gain 0shutter 100ms – gain 49shutter 100ms – gain 98shutter 1s – gain 0shutter 1s – gain 49shutter 1s – gain 98shutter 10s – gain 0shu tter10s – gain 49shutter 10s – gain 98
modified lens without IR filter, no IR leds
shutter 10ms – gain 0shutter 10ms – gain 49shutter 10ms – gain 98shutter 100ms – gain 0shutter 100ms – gain 49shutter 100ms – gain 98shutter 1s – gain 0shutter 1s – gain 49shutter 1s – gain 98shutter 10s – gain 0shutter 10s – gain 49shutter 10s – gain 98
modified lens without IR filter + IR leds
shutter 10ms – gain 0shutter 10ms – gain 49shutter 10ms – gain 98shutter 100ms – gain 0shutter 100ms – gain 49shutter 100ms – gain 98shutter 1s – gain 0shutter 1s – gain 49shutter 1s – gain 98shutter 10s – gain 0shutter 10s – gain 49shutter 10s – gain 98
analyses
First things first, simple physics do apply here:
increasing the exposure time helps in capturing details in low light conditions
increasing gain helps in low light condition when you want to restrict the exposure time, but brings lower quality images as a result due to noise
That being said, as you notice the pictures turn out a bit red-ish. This is due to the PI its power LED being roughly the only source of light directly pointed to the target background in a completely dark room. This assumption gets confirmed as soon as I switch on the IR LEDs. The latter easily outshines the power LED. The IR light appears a bit white-ish compared to the reds from the power source. We see this confirmed for the 10s exposure shots with the stock lens (with IR filter), when you compare the pictures with or without IR led. The images are still unedited, except for rotation.
left: IR LEDs + power LED active, right: only power LED (10s shutter – gain 49)
But the impact is huge when we repeat that shot without IR filter.
left: IR LEDs + power LED active, right: only power LED (10s shutter – gain 49)
The change in overall brightness is so huge that the image even gets over-exposured! So if you’re looking into nightly security applications I highly recommend removing the IR filter plus adding a IR light source as it will allow to capture dramatically more details! It even allows us to set the shutter to 100ms and still see details in the room’s background, which when repeated for the other LED/filter combination is simply not possible.
But the most important question here is: how is the quality when we start increasing the gain. Let’s widen the image up for some detail:
shutter 10s – gain 98 – stock lens – no IR light source (only power LED) – LCG mode
At those high gain settings it’s perfectly natural that we get noise added to our image. But what I find important here is that we see no banding at all. Okay, you may say there the most left side of the picture is a lot less bright than the right side, but that’s due to the power LED being blocked by that clamp that holds everything in place. It’s just shadow casted over the background, but it does indeed looks it bit weird this way. Now remember one of the picture I took in the past, with IMX462 from the first batch…
IMX462 v1 – shutter 100ms – gain 98 – modified lens – IR light source (only power LED) – LCG mode
And compare that with the same image lens, IR source, exposure and gain settings on the PI 2 that I’m currently using for the current tests:
IMX462 v2 – shutter 100ms – gain 98 – modified lens – IR light source (only power LED) – LCG mode
Although the lightning setup may differ over the tests back than and now, what’s important here is that we don’t see any of those banding issues here anymore!
Is Wifi impacting the analog picture quality? Let’s test:
shutter 10s – gain 98 – stock lens – no IR light source (only power LED) – LCG mode
Again the lighting may have been slightly different to previous tests, like the standby LED of a new device in that room, but in general we again see that there is no banding at all, even with the gain at its maximum level.
Conclusive thoughts
Left: Inno-maker IMX462 new rev, right: old rev (modified)
As it turns out, the Inno-maker IMX462 has become an even better alternative for lowres Raspberry Pi cameras, specially outperforming the Pi cams in low light conditions. It offers good value for superior night sight, and now with the new revision some of the pains of the first revision has been tackled. So if you’re still looking for a good bang-for-back security sensor, the Inno-maker IMX462 may be your board of choice.
The Sony IMX462 image sensor is a first generation Sony sensor with Starvis technology. It’s a sensor made for low light condition and is quite affordable. Hence why it has been favored in some of my own experiments. Today I had a quick look at what an IR filter can do for this sensor. This can be particularly interesting as the sensor has higher sensitivity in the IR spectrum compared to other off-the-shelve cameras. Here is the sensor’s light sensitivity chart:
The range of the human eye is somewhere along 4000 to 7000 Angstroms. However for IMX462 there is definitely a big peak in sensitivity beyond what we can see with the human eye. Light sources in the range of 8000 to 8500 Angstroms are picked up very well by the sensor too, while for the human eye it’s as if nothing is there. This range is exactly what we call the Infra-red range, or IR range. Therefore the IMX462 is a good candidate to fit a security camera where it can be accompanied by an IR light source. But is that really so? Since I had a box of Arducam lenses laying around I thought I could easily make the experiment as those lenses by default come with an IR filter applied.
So here we go… I started by adding IR LEDs to my Raspberry Pi setup:
Raspberry Pi, with 3V3analog LDO mod for IMX462, and 3 IR LEDs
I took my Rasberry Pi to a nearly perfect dark room with no light sources around. In effect there is about only the IR light source active. I mounted a 55° wide Arducam lens but leave it unmodified (aka with IR filter). For our tests the following command is used for taking pictures:
Now the Arducam lenses have their IR filters very well attached to the lens body. Compared to other branded lenses the filter doesn’t come of that easily. For example I found that on some lenses the filter would almost fall of by itself. Not with Arducam. I has to break the IR filter in order to get it removed. Warranty removed, without doubt.
Now let’s repeat the test:
IMX462 shutter=100ms gain=98 without IR filter
Wow! Dramatic change! Well, it was to be expected though if you’ve had (like me) previous experience with light filters. The filter really blocks the IR sources well resulting in a near pitch dark picture. Without the filter the image is even overexposed, as if it was taking in broad daylight! So for security cams I can definitely understand the need to remove the IR filter after the sun has set. During the day however it is better to keep the IR filter mounted as it will assure good representation of the colors in your videos and images.
For purposes of astro-photography, if you’re intending to picture the moon the IR filter can probable stay in place as the moon has no IR sources. For some planets such as Jupiter and Saturn it may be interesting to see what you get with and without IR filter. For deep sky objects and nebula it’s probable better to go without IR filter, but is also depends on what you want to achieve.
This is a quick reference article where I test the Inno-maker IMX462 sensor on a Raspberry Pi 3. The scene is mostly dark, imagine a room with closed door and all windows covered up. The RPI3 is accompanied with 3 IR LEDs just to have at least some light once we start experimenting.
It’s important that we disable Automatic Exposure/Gain Control (AEC/AGC) and Auto White Balance (AWB) algorithms. We can do that with libcamera by using the exposure time (--shutter), the gain (--gain) and the white balance gains (--awbgains) settings. We need this for reproducability, but also for speed as some of these algorithm requires taking extra shots. Typically our command look as following:
With the shutter speed setting we control how long the image sensor gets to collect light. It’s often referenced as the exposure time. The longer the shutter speed, the more light is going to fall into the sensor, the more details we will get in our dark scene. Libcamera sets the shutter time in microseconds.
In dark conditions, a 1s shutter reveals some initial details. However, it is still too little to recognize anything. At 3s shutterspeed more details become visible and we can finally recognize objects. Bumping the shutter even higher means bringing even more details into the picture. Additionally we don’t notice a lot of noise in the picture. The only thing we do notice is that the picture becomes a bit white /pale.
Gain
The gain settings controls the combined analog and digital gain. But what is the difference the two? The analog gain comes into play inside the image sensor, where light is converted into an electrical signal (voltage), and then further on using an Analog-to-Digital Converter (ADC) into digital 1’s and 0’s. The analog gain amplifies the voltage signal before it goes into the ADC. In the resulting picture the amplification (referred to as ‘gain’) makes low light scenes appear brighter than without the extra gain.
There is however also a downside to this gain. The photo-detector is sensitive to dark noise, however from perspective of the amplifier this noise is indistinguishable from normal light that was collected in the photo-detector. Therefore the amplifier will also amplify the noise, and as such reduce the dynamic range. Normally the noise of the ADC will dominate over the noise introduced by the gain amplifier. However, as the gain is increased it will take the overhand at some point.
Digital gain is applied after the ADC stage, when the final image has been composed. The multiplication is performed on the digital values and as a result reduces the resolution. This process can be performed by some extra part in the image sensor, or an ISP, but it can also be achieved by post processing. Therefore it’s better not to apply any digital gain in your capturing pipeline as it actually discards some of the information that was captured in the analog stage. Without the digital gain you’re left with the option to apply the multiplication during your post processing stage.
The choice of analog vs digital gain is however not entirely ours to make. Using libcamera the --gain setting controls both. It’s up to the driver to actually decide what gain it will apply. But given the downside of using digital gain it will always prefer using analog gain over digital gain. Looking further in detail we actually see that image sensors have those analog and digital gain amplifiers embedded in hardware. They’re bound to a minimum and maximum value of amplification, which can than be controlled via the CCI (I2C) bus.
When we read the datasheet of the IMX462 we find that gain can be controlled within following rates:
0 dB to 29.4 dB: Analog Gain 29.4 dB (step pitch 0.3 dB)
29.7 dB to 71.4 dB: Analog Gain 29.4 dB + Digital Gain 0.3 to 42 dB (step pitch 0.3 dB)
In our tests we will avoid using digital gain. Lucky for use the linux driver for the IMX462 already ensures to have only control over the range of analog gain. Looking at the driver we notice that the range goes from 0 to 100, which maps to the ~30dB max and 0.3dB steps (30db/0.3dB = 100).
For our gain tests we fix the exposure time to 100ms.
It takes us up to a gain of 20 before we see any objects appearing in the background. And as we bump up the gain, more and more details will become visible. In some extend it’s similar to what we saw happening when we experimented with the exposure time. We could say that under the same conditions, using a 5s shutter with gain 1, roughly results in the same picture as when we use a 100ms shutter with gain 70.
The mayor difference though is that bumping up the gain also introduces a lot of noise in our pictures. At those higher gain values we can easily spot many horizontal bands and the picture quality is a lot worse than using the longer exposure shots. So if the shutter speed is allowed to go high than it will result in better picture quality in conditions where not a lot of light is available. In case you can’t allow the shutter to go high there is still the option to increase the gain but know that you will have to deliver in on image quality as noise gets amplified to. But in the end gain is also a way of bringing low light signals (like faint stars) into the picture. Keep in mind that from the results we’re mostly talking about the RAW data quality. No de-noising algorithms have been performed, though it could (and would) help to compensate some of the image quality loss of using the higher gain.
LCG vs HCG
The exposure and gain settings are 2 very common settings that you can find in most camera software, including libcamera, and as you can see it gives us quite accurate control over the camera sensor. There is however more to discover. The IMX462 has an extra trick up its sleeve: dual conversion gain. The IMX462 can choice between 2 conversion modes: Low Conversion Gain (LCG) and High Conversion Gain (HCG).
Do not confuse HCG/LCG with the normal gain setting that we saw previously. Those are 2 different things! The gain setting is about amplification, HCG/LCG is about photodiode to voltage conversion. So let’s say in LCG mode a bung of electrons convert to 0.01V, the same amount of electrons may convert in HCG mode to 0.05V. So with the same mount of light, a higher voltage is generated, hence why it’s called “high conversion gain”. In the end it will help in low light conditions.
Low conversion gain (LCG)
the normal mode
white is at 90% of pixel saturation
good for bright parts in the image
High conversion gain (HCG)
increases sensitivity and reduces readout noise level
has advantage in signal-to-noise (SNR) at low illuminance levels
good for dark parts in the image
So each gain mode has its own advantages, and they can even be combined by an ISP to achieve a higher dynamic range. There is very interesting topic at cloudynights about HCG. In the consumer market the IMX462 is used for example in the ZWO ASI462 camera. The reason I mention this is that they also advertise the HCG mode. In astro-photography this can play an important role. While HCG is implemented in the IMX462 in a different register than the normal gain setting, ZWO controls it automatically for you once the normal gain is increased to level 80. ZWO has their own gain levels compared to those of libcamera, so here 80 * 0.1dB = 8dB, where for libcamera 8dB gives a gain level of about 8dB * 0.3dB = 0.24dB. Always look at dB when comparing across vendors. Looking back at our previous gain experiments it would mean that if we also implemented auto LCG/HCG switching at the same levels, the switchover to HCG would already happen before noise is becoming dominant. It would also mean that on that moment we would see a big bump in brightness.
For the raspberry pi and libcamera things are currently a bit more complicated. As of November 2024 there is no out-of-the-box support for toggling HCG mode in video4linux, nor in libcamera. However, that doesn’t mean it’s impossible. HCG has already been discussed in a few topics on the raspberry pi forums and meanwhile a pull request (PR) has been opened for quite a bit of time that should allow control of HCG via a kernel module parameter. It means it doesn’t involve video4linux nor libcamera at all, but still if you’d ever need it you can enable it via the sysfs entries for the kernel module. A side effect of having the github PR is that the build server creates a build artifact that can directly be installed on your system. The PR is targetting linux 6.6 which is also the kernel that I’m currently on, so everything should go fairly straightforward. Note: you may not be able to install the build artifact by the time you read this article as the build server only retains the artifacts for few weeks/months.
Before you proceed in patching your kernel there is still one thing we need to take care off: patching libcamera itself. As you may have noticed from the kernel patches is that IMX462, due to small differences with IMX290, is from now on a individual camera device in the linux kernel. You can target the IMX462 specifically in your device tree while in the past you had to set it up as a IMX290/IMX327. So for the best user experience we should make sure to have the device tree overlay for IMX462 activated in the config.txt:
Now, about the licamera patches themselves I also need to shed some lights on what has been done. The patches are mandatory to make libcamera work with the “new” IMX462 camera driver. Libcamera wasn’t yet aware of this camera device since it never existed in earlier kernels. Libcamera would therefore exit with and error when you tried to take a snapshot. So I patched libcamera to support the new IMX462 cam and I created this PR on raspberry pi fork of libcamera so that the support will make it to the next Raspbian OS release. However it was concluded that the patches should better be upstreamed to the origin libcamera, and so that’s what I did. You can find them here:
The patches are merged upstream as we speak, so Raspbian will get the support for IMX462 out of the box anywhere soon, but due to merging strategies and the kernel dependency it’s rather hard to tell when exactly that will happen. Long story short, unless your OS already has the HCG kernel mode parameter in the sysfs (check if you have /sys/module/imx290/parameters/hcg_mode file) you’re on your own for patching your kernel and libcamera software.
If the rpi build artifacts are still available, at least you can already use the kernel as is. To install the patched kernel:
$ sudo rpi-update pulls/5859
This will take a few minutes to install. In my case the PR artifacts slightly upgrades to linux 6.6.57. If needed you can always switch back to a normal RPI kernel by updating to the latest version:
$ sudo rpi-update
Afterwards reboot the machine.
$ uname -a
Linux pycam3 6.6.57-v7+ #1 SMP Sat Oct 19 12:29:20 UTC 2024 armv7l GNU/Linux
The new kernel module entry can be found in the sysfs:
$ cat /sys/module/imx290/parameters/hcg_mode
N
By default it’s off, but you can enable/disable it by writing 0 or 1 to this file:
$ echo 1 | sudo tee /sys/module/imx290/parameters/hcg_mode
NOTE: the pics taken for the HCG experiments are performed with a slightly modified camera board. Do not directly compare them to those I took earlier. More details about the mods are upcoming, but essentially what I did is improving the quality of the power supply to the camera which on its turn reduces removes the horizontal banding that we can clearly see at high gain levels.
OK, now about the HCG mode, it’s pretty much clear that it makes the camera again more sensitive to light. At looks as if another level of analog gain is added, and actually it is said that HCG mode sort of brings an additional 5.8x gain. It also make noise stand out a bit more, so it’s not just something that magically fixes things for us. But if you look at it from another angle it just one more option in your toolbox as it allows us to see things in the dark as if we were using long exposure times, while actually the exposure time is set to only 100ms. Also compare the picture with HCG=on,gain=20 to the one with HCG=off,gain=50. Both pictures are pretty much the same in brightness, even though the gain levels are considerably different. Let’s zoom in a bit:
HCG off gain 50 vs HCG on gain 20, exposure 100ms
I’m not entirely convinced here but there seems to be a very small, subtle difference between both in that the one with HCG seems to be a tiny bit less noisy. Maybe it’s just the overall brightness that is a tiny bit off, or just some variation that we’re seeing. Anyway, I think it certainly deserves further exploring once I get back to trying astrophotography.
Conclusive thoughts
To conclude, we can state the IMX462 can be used in dark scenes. As a photographer, you have a few tools in your belt to get to the best possible result. There is a considerable range of exposure settings. Analog gain is available up to about 30dB. Finally, the High Conversion Gain can be enabled or disabled using the patches described in this article. I hope you found something interesting. At least for me, it was worth diving into this HCG thingy. It was also valuable to get some sort of reference picture quality on which I can compare my camera modifications. Regarding the latter, stay tuned for another article. It will go more into details on what you should do to get rid of the horizontal banding issues with the Inno-maker IMX462. See you soon.
I kind of stumbled into setting up a DIY astro cam through several earlier articles, and learning some ins and outs of the telescopes and cameras along the way. By the end of those articles I wasn’t entirely pleased with the results I got so I felt the urge to dig deeper. I started my adventures by writing a simple bash script and using tools such as libcamera-still to capture the RAW files and ssh to copy over the pictures, but this was not performing good at all so this felt like an interesting thing to improve. So I started to explore some options here.
Pre-setup
Make sure that you have a Raspberry Pi with Raspbian OS setup. In my case it’s a RPI2 with Raspbian 12 (bookworm). Also make sure to have SSH access and the disc space expanded to the entire sd-card space. You should also hookup the camera to the RPI:
And install the correct device tree overlay for your camera. In my case I had to edit the boot config and set:
#Camera dtoverlay=imx462,clock-frequency=74250000
The libcamera library and userspace demo applications like libcamera-still, libcamera-vid and so on should already come pre-installed.
libcamera, libcamera-apps, rpicam-apps, pycamera2
Until now I’ve been testing with the utilities that come with Raspbian OS, being libcamera-still and friends. But what er all of these software packages exactly?
libcamera: a modern C++ library that abstracts the usage of cameras and ISPs away to make application development easier and with less gory camera specifics. Libcamera is developed as an independent open-source project for linux and Android.
libcamera-apps: a bunch of userspace applications that are build upon libcamera. It allows users to easily snap pictures, RAWs and videos using image sensors and ISPs that are supported through libcamera. It’s developed by the Raspberry Pi Foundation, therfor the libcamera library and libcamera-apps are developed by 2 different entities. More recently the apps/tools have been renamed to rpicam-apps to elaborate that the userspace apps and libcamera are 2 different things being supported by different teams.
rpicam-apps: previously named libcamera-apps, as you could read in the above
pycamera2: python library to make applications using libcamera as backend. It replaces the pycamera library that was created on top of the legacy Raspbian camera stack. As a python library it’s for many people a more convenient way to start hacking vision apps compared to directly using libcamera in a C++ project. Picamera2 also comes with a nice manual to get you going.
I started experimenting with pycamera2 myself a bit, but since I wanted a network solution I also started to think what other stuff I would need to develop. A REST based API? Maybe something with websocket for fast response? And how does that work in bad network conditions? Or could I maybe sail on the work of others? Well… meet INDI.
INDI
To quote their own words:
INDI Library is an open source software to control astronomical equipment. It is based on the Instrument Neutral Distributed Interface (INDI) protocol and acts as a bridge between software clients and hardware devices. Since it is network transparent, it enables you to communicate with your equipment transparently over any network without requiring any 3rd party software. It is simple enough to control a single backyard telescope, and powerful enough to control state of the art observatories across multiple locations.
Image courtesy of indilib.org
INDI serves offers the networked approach that I’ve been achieving so by calling my libcamera commands over SSH, and it also has libcamera support so it fits my goal perfectly! But INDI is also a broad collection of many other software pieces coming together, not only for our Raspberry Pi based cameras but for many other cameras, controllers, motorized mounts and so forth. But let’s try to focus on some of the components that are of most interest for us.
indi-3rdparty: a collection of all sorts of specific driver implementations for INDI.
indi-libcamera: this is just the specific 3rd party INDI driver for devices that are supported by libcamera. It’s basically just one of the many drivers in indi-3rdparty.
indi-pylibcamera: developed as an alternative driver implementation for indi-libcamera. However in contrary to the latter indi-pylibcamera is not part of the indi-3rdparty repository and probable will never be
I started by going through many pages of developer ramblings at the indib forum. From that Indi-pylibcamera seems to have matured best over the years and the author is very willing to help out with any issues that you have. But given it’s a alternative to the more official 3rd-party drivers repository I’m hesitating if it’s the best choice in the long run. The other way around the indi-libcamera driver doesn’t seem to be well maintained but I was willing to give a helping hand in case it was required. So let’s get started.
Compiling from INDI from source on Raspbian 12 (bookworm)
You can off course try to apt install all key components, but in my case I would end up with slightly outdated software and with libcamera support you mostly want the latest and greatest. Furthermore if I would be willing to help out with the development or debugging I’ll need to compile from source anyway. So let’s get our hands dirty…
To get the latest working software I’ll be building both indi and indi-libcamera from source, but also libXISF which is a dependency for indi that provides XISF support. But let us first install some build dependencies:
cd ~/Projects git clone https://gitea.nouspiro.space/nou/libXISF.git cd libXISF cmake -B build -S . cmake --build build --parallel sudo cmake --install build
Next is indi:
cd ~/Projects
git clone https://github.com/indilib/indi.git
cd indi
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug ~/Projects/indi
make -j2
sudo make install
Grab a coffee or somethings, this one is going to take a while if you’re like me building it on your RPI. Once done we can check if our indiserver is available with the latest version:
$ indiserver -h 2024-02-01T20:40:10: startup: indiserver -h Usage: indiserver [options] driver [driver ...] Purpose: server for local and remote INDI drivers INDI Library: 2.0.6 Code v2.0.6. Protocol 1.7.
Now let’s continue with indi-libcamera:
cd ~/Projects
git clone https://github.com/indilib/indi-3rdparty
cd indi-3rdparty
mkdir -p build/indi-libcamera
cd build/indi-libcamera
cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug ~/Projects/indi-3rdparty/indi-libcamera
make -j2
sudo make install
With all of that set and done we’re on to the next step: using our new tools:
Starting the indi server
To be able to connect our host pc to the Raspberry Pi we need to run a indi server on the Pi. We can do so as following:
$ indiserver -v indi_libcamera_ccd
In the output you’ll notice the libcamera driver at work:
2024-02-01T20:54:29: startup: indiserver -v indi_libcamera_ccd 2024-02-01T20:54:29: Driver indi_libcamera_ccd: pid=5997 rfd=6 wfd=6 efd=7 2024-02-01T20:54:29: listening to port 7624 on fd 5 2024-02-01T20:54:29: Local server: listening on local domain at: @/tmp/indiserver 2024-02-01T20:54:30: Driver indi_libcamera_ccd: [3:09:59.402123462] [5997] INFO Camera camera_manager.cpp:284 libcamera v0.1.0+118-563cd78e 2024-02-01T20:54:30: Driver indi_libcamera_ccd: [3:09:59.593527216] [6003] WARN RPiSdn sdn.cpp:39 Using legacy SDN tuning - please consider moving SDN inside rpi.denoise 2024-02-01T20:54:30: Driver indi_libcamera_ccd: [3:09:59.604231695] [6003] INFO RPI vc4.cpp:444 Registered camera /base/soc/i2c0mux/i2c@1/imx290@1a to Unicam device /dev/media1 and ISP device /dev/media0 2024-02-01T20:54:30: Driver indi_libcamera_ccd: [3:09:59.604426747] [6003] INFO RPI pipeline_base.cpp:1142 Using configuration file '/usr/share/libcamera/pipeline/rpi/vc4/rpi_apps.yaml' 2024-02-01T20:54:30: Driver indi_libcamera_ccd: snooping on Telescope Simulator.EQUATORIAL_EOD_COORD 2024-02-01T20:54:30: Driver indi_libcamera_ccd: snooping on Telescope Simulator.EQUATORIAL_COORD 2024-02-01T20:54:30: Driver indi_libcamera_ccd: snooping on Telescope Simulator.TELESCOPE_INFO 2024-02-01T20:54:30: Driver indi_libcamera_ccd: snooping on Telescope Simulator.GEOGRAPHIC_COORD 2024-02-01T20:54:30: Driver indi_libcamera_ccd: snooping on Telescope Simulator.TELESCOPE_PIER_SIDE 2024-02-01T20:54:30: Driver indi_libcamera_ccd: snooping on Rotator Simulator.ABS_ROTATOR_ANGLE 2024-02-01T20:54:30: Driver indi_libcamera_ccd: snooping on Focuser Simulator.ABS_FOCUS_POSITION 2024-02-01T20:54:30: Driver indi_libcamera_ccd: snooping on Focuser Simulator.FOCUS_TEMPERATURE 2024-02-01T20:54:30: Driver indi_libcamera_ccd: snooping on CCD Simulator.FILTER_SLOT 2024-02-01T20:54:30: Driver indi_libcamera_ccd: snooping on CCD Simulator.FILTER_NAME 2024-02-01T20:54:30: Driver indi_libcamera_ccd: snooping on SQM.SKY_QUALITY
Kstars / Ekos client
On your desktop PC you have various indi clients available. I gave Ekos a try. Ekos is a cross-platform client. Open the KStars application:
You can start the Ekos utility by pressing Ctrl + k, or by navigating through the menu via Tools > Ekos. Next a wizard will be started to help you setup your observatory:
Select Next, and on the next step select the remote device option:
In the next window choose Other:
Now enter the IP address of our Raspberry Pi and click Next. PS: I also deselected the Web Manager option here, but more on that later.
And finally enter a profile name and click “Create Profile & Select Devices”:
You’ll be ending up in the Profile Editor window. Make sure to open the dropdown box and select RPI Camera to link the libcamera CCD driver that we loaded to a CCD in Ekos. Press Save.
Ekos is now being started:
At first nothing is shown in Ekos because we haven’t connected to our gear yet. Press the green play button. If you still have your ssh connection open to your Pi from those earlier steps where you started the indi server you’ll now notice a new incoming client connection:
2024-02-01T21:26:21: Client 9: new arrival from 192.168.0.221:42300 - welcome!
A new window will pop-up:
In the new window you can toggle the General Info tab to get some insights in the indi driver being at work. In my case it an IMX462 camera, but advertised as IMX290 since that’s how libcamera picks it up.
After pressing the Connect button you get a whole lot of camera settings that you can easily adjust through the GUI:
You may Close this window or minimize it, and once back in Ekos go to the CCD tab. Here you can start your first capture by pressing the camera icon below the sequence box, hovering the icon will tell you “Capture a preview”:
On the Raspberry Pi you’ll now see libcamera being set to work and capture that shot:
2024-02-01T21:51:00: Driver indi_libcamera_ccd: [4:06:30.151699548] [6070] INFO Camera camera_manager.cpp:284 libcamera v0.1.0+118-563cd78e 2024-02-01T21:51:01: Driver indi_libcamera_ccd: [4:06:30.302132539] [6075] WARN RPiSdn sdn.cpp:39 Using legacy SDN tuning - please consider moving SDN inside rpi.denoise 2024-02-01T21:51:01: Driver indi_libcamera_ccd: [4:06:30.307911048] [6075] INFO RPI vc4.cpp:444 Registered camera /base/soc/i2c0mux/i2c@1/imx290@1a to Unicam device /dev/media1 and ISP device /dev/media0 2024-02-01T21:51:01: Driver indi_libcamera_ccd: [4:06:30.308089276] [6075] INFO RPI pipeline_base.cpp:1142 Using configuration file '/usr/share/libcamera/pipeline/rpi/vc4/rpi_apps.yaml' 2024-02-01T21:51:01: Driver indi_libcamera_ccd: Mode selection for 1944:1097:12:P 2024-02-01T21:51:01: Driver indi_libcamera_ccd: SRGGB10_CSI2P,1280x720/0 - Score: 3084.13 2024-02-01T21:51:01: Driver indi_libcamera_ccd: SRGGB10_CSI2P,1920x1080/0 - Score: 1084.13 2024-02-01T21:51:01: Driver indi_libcamera_ccd: SRGGB12_CSI2P,1280x720/0 - Score: 2084.13 2024-02-01T21:51:01: Driver indi_libcamera_ccd: SRGGB12_CSI2P,1920x1080/0 - Score: 84.127 2024-02-01T21:51:01: Driver indi_libcamera_ccd: Stream configuration adjusted 2024-02-01T21:51:01: Driver indi_libcamera_ccd: [4:06:30.313121278] [6070] INFO Camera camera.cpp:1183 configuring streams: (0) 1944x1097-YUV420 (1) 1920x1080-SRGGB12_CSI2P 2024-02-01T21:51:01: Driver indi_libcamera_ccd: [4:06:30.314471895] [6075] INFO RPI vc4.cpp:608 Sensor: /base/soc/i2c0mux/i2c@1/imx290@1a - Selected sensor format: 1920x1080-SRGGB12_1X12 - Selected unicam format: 1920x1080-pRCC 2024-02-01T21:51:08: Driver indi_libcamera_ccd: Bayer format is RGGB-12
And a preview window will pop-up showing you your first capture!
You can save the preview to FITS, JPEG or PNG on your host pc by pressing the green ‘download’ icon in the upper left corner. Now what’s left for you is to enjoy that first picture that you just have token. At least I hope you have something more interesting than me to capture…
Autostarting indi-server
Until now I’ve been running the indi-server from the shell over an SSH session. Not really the most user friendly approach once you’re in the field, right. But there is indi Web Manager to the rescue. Indi webmanager is python based web application that can start and stop the indi-server for you by means of a REST api call. In lay mens terms it means that you can have the indi-server started by visiting a http web page, sort of. So what’s the difference with starting it over SSH? Well, the indi web manager is supported by Ekos in that it can make the required web calls to setup the indi-server through the INDI web manager. It also allows you to control what drivers need to be loaded. So in other means its also a manager to configure the indi-server plugins. But I found some difficulties installing it, furthermore since my setup is not changing a lot I figured that I didn’t need a daemon controlling our indi-server daemon but could as well create a small systemd service file and be done with it. So let’s go for that option and start creating our own systemd service.
First create a service file:
sudo nano /etc/systemd/system/indiserver.service
And enter following content:
[Unit] Description=INDI server After=multi-user.target
Now you must reload the daemon lists so that systemd picks up the new service. Only then will you be able to ‘enable’ the service for starting with the OS:
sudo systemctl enable indiserver.service
The system will tell you that a symlink has been created.
sudo reboot
Reboot the system and the indi-server should come up after the reboot. If you’re still experiencing issues you can manually start the service using:
sudo systemctl start indiserver.service
Next check the status of the service:
sudo systemctl status indiserver.service
It should tell you that the service is active and running:
Press ‘q’ to quit. You can also inspect the service logs using journalctl:
journalctl -u indiserver.service
Example output:
Feb 02 22:29:34 rpi2 systemd[1]: Started indiserver.service - INDI server. Feb 02 22:29:34 rpi2 indiserver[8617]: 2024-02-02T21:29:34: startup: indiserver -v indi_libcamera_ccd Feb 02 22:29:34 rpi2 indiserver[8617]: 2024-02-02T21:29:34: Driver indi_libcamera_ccd: pid=8618 rfd=6 wfd=6 efd=7 Feb 02 22:29:34 rpi2 indiserver[8617]: 2024-02-02T21:29:34: listening to port 7624 on fd 5 Feb 02 22:29:34 rpi2 indiserver[8617]: 2024-02-02T21:29:34: Local server: listening on local domain at: @/tmp/indiserver Feb 02 22:29:34 rpi2 indiserver[8617]: 2024-02-02T21:29:34: Driver indi_libcamera_ccd: [27:45:03.883924469] [8618] INFO Camera camera_manager.cpp:284 libcamera v0.1.0+118-563cd78e Feb 02 22:29:34 rpi2 indiserver[8617]: 2024-02-02T21:29:34: Driver indi_libcamera_ccd: [27:45:04.001222194] [8623] WARN RPiSdn sdn.cpp:39 Using legacy SDN tuning - please consider movi> Feb 02 22:29:34 rpi2 indiserver[8617]: 2024-02-02T21:29:34: Driver indi_libcamera_ccd: [27:45:04.006897368] [8623] INFO RPI vc4.cpp:444 Registered camera /base/soc/i2c0mux/i2c@1/imx290> Feb 02 22:29:34 rpi2 indiserver[8617]: 2024-02-02T21:29:34: Driver indi_libcamera_ccd: [27:45:04.007352574] [8623] INFO RPI pipeline_base.cpp:1142 Using configuration file '/usr/share/> Feb 02 22:29:34 rpi2 indiserver[8617]: 2024-02-02T21:29:34: Driver indi_libcamera_ccd: snooping on Telescope Simulator.EQUATORIAL_EOD_COORD Feb 02 22:29:34 rpi2 indiserver[8617]: 2024-02-02T21:29:34: Driver indi_libcamera_ccd: snooping on Telescope Simulator.EQUATORIAL_COORD Feb 02 22:29:34 rpi2 indiserver[8617]: 2024-02-02T21:29:34: Driver indi_libcamera_ccd: snooping on Telescope Simulator.TELESCOPE_INFO Feb 02 22:29:34 rpi2 indiserver[8617]: 2024-02-02T21:29:34: Driver indi_libcamera_ccd: snooping on Telescope Simulator.GEOGRAPHIC_COORD Feb 02 22:29:34 rpi2 indiserver[8617]: 2024-02-02T21:29:34: Driver indi_libcamera_ccd: snooping on Telescope Simulator.TELESCOPE_PIER_SIDE Feb 02 22:29:34 rpi2 indiserver[8617]: 2024-02-02T21:29:34: Driver indi_libcamera_ccd: snooping on Rotator Simulator.ABS_ROTATOR_ANGLE Feb 02 22:29:34 rpi2 indiserver[8617]: 2024-02-02T21:29:34: Driver indi_libcamera_ccd: snooping on Focuser Simulator.ABS_FOCUS_POSITION Feb 02 22:29:34 rpi2 indiserver[8617]: 2024-02-02T21:29:34: Driver indi_libcamera_ccd: snooping on Focuser Simulator.FOCUS_TEMPERATURE Feb 02 22:29:34 rpi2 indiserver[8617]: 2024-02-02T21:29:34: Driver indi_libcamera_ccd: snooping on CCD Simulator.FILTER_SLOT Feb 02 22:29:34 rpi2 indiserver[8617]: 2024-02-02T21:29:34: Driver indi_libcamera_ccd: snooping on CCD Simulator.FILTER_NAME Feb 02 22:29:34 rpi2 indiserver[8617]: 2024-02-02T21:29:34: Driver indi_libcamera_ccd: snooping on SQM.SKY_QUALITY
Again press ‘q’ to quit.
Other options within Ekos
Ekos and Kstars in general offers lot’s of possibilities, much more than I could ever come up with let alone implement them within any reasonable time. You can adjust exposure, set filters, adjust the format, and so on here:
You can also choose were to store the captured file: remote vs local:
And even create sequences with various exposures:
The the button next to the loop icon (which may have it’s icon missing due to a bug) is the one to start a video stream. You can even start recording the video from there:
Stability
I’ve been having some issue with DMA buffers no longer being able to allocate and so on. It always works the first time, but for a second picture or video I end up in trouble and need to reboot the gateway or manually restart the indi-server. So maybe it’s time to bump the libcamera version as well. Currently the Raspbian 12 (bookworm) OS comes with a slightly outdated libcamera v0.0.5 released back in the summer of 2023:
$ sudo apt show libcamera0 Package: libcamera0 Version: 0~git20230720+bde9b04f-1
We can update that to version 1.0.0 nowadays if we start from the official Raspberry Pi repo and compile from source. Before we get building we first need to install some more build dependencies:
Unfortunately that didn’t improve anything so I’ll be spending some time to see if we can debug things, but that’s for later.
Processing speed
This was one of the issues I had with my custom SSH script implementation that I wanted to speedup enormously. I was a bit hoping that having everything updated and moving over to a Raspberry Pi 2 would make drastic changes, like maybe 2 or 3 seconds at max for a 1 second exposure shot. I ended up finishing the 1s capture in 8 seconds. But for the 10s shutter I would again end up in over a minute easily. So it’s still far away from what I really wanted! So maybe not needing to open and close the application each time shoves off some time and also moving from a Raspberry Pi 1 to a RPI2 helps a tiny bit here and there, but unfortunately not what I had hoped. So I’m going to have to dive deeper into this matter and get why it’s so slow, do we really have that many parallel things going on here? More and that maybe in a follow up article if I find the time.
The verdict
I’m pleased with the result as all together I didn’t had that much difficulties to set things up. Except maybe for solving one missing build dependency, but that was pretty much it. I’ve had a lot worse build-from-source experiences in the past with other repositories! To my surprise the libcamera implementation is working OK, but the entire libcamera + INDI stack is not yet entirely bug-free. It’s also not yet as fast as I would have hoped for. That’s certainly something I’ll need to further dig into and check with the indi-3rd party team what could be wrong here.
The nice thing about all of this is that now I’m no longer on my own putting things together from scratch. I must say that it’s always fun to just hack yourself something together with a few lines of scripting, but at one point you’re going to have to make the trade-off of doing everything yourselves and spending a lot of time on it versus leveraging on other mens work and making a few mayor leaps forward. With INDI there is now the entire eco-system that’s readily at my hands and I can start exploring maybe adding a motorized mount, or maybe lookout for other desktop clients or maybe even mobile clients so that I don’t have to drag the laptop outside each time. Plenty of options and opportunities now fall within reach thanks to INDI and the open-source community! So I hope to have gotten you inspired to try things for yourself, and leave a line about how you’re experiencing the INDI, libcamera and RPI combination for your astro stuff. Good luck building!
From past experiences with the Freescale Community BSP I was recently wondering if the same tooling was already setup for one of the largest community targetted board around: the Raspberry PI. And it seems it is not!
I went ahead and put it together. You can now easily initialize, synchronize and get your builds running by using Google’s Repo tool in conjuction with Yocto.
The repo can be found below together with instructions:
At the end of the commands you have every metadata you need to start work with. The source code is checked out at rpi-community-bsp/sources. You can use any directory to host your build. As a personal favor I’m using rpi-community-bsp/build as build folder.
I noticed on the first yocto image that I've made there were some issue's regarding the wireless connection. I was not sure exactly what went wrong, but it seemed to be a kernel/driver issue. The rtl8192cu wifi interface had connection problems whenever I disconnected the eth0 interface. I din't find a lot of clue's except from some folks complaining about the 8192cu kernel module not really working out to well. Through lsmod I found out that I was using this module. When using the adapter on my Ubuntu machine I noticed other drivers and modules got loaded - not the pesky 8192cu module - and the wireless interface was indeed working out well.
First idea would be to swap kernel modules by reconfiguring the kernel config in Yocto. However, since I'm recompiling I might as well pull in the latest sources for my working branch and just recompile the entire image. As a result I'd upgrade from Linux 4.4 to 4.9.
I also wrapped some of my work into script so that updating another time later on would make life much easier. Here is what I did:
Updating yocto to latest sources
The script below will pull in all latest meta-layers from the morty branch. Although newer branches are available like pyro and rocko, I'm not yet thinking about pulling these in since this will have a bigger impact on the package versions. Here is the script:
Again, save it to the same directoy, make it executable and run it (overnight).
Deploy the image to SD card
Jumpnowtek already provided some tools to automate some of the task that need to be done to get all your binaries on a SD card. The following script just wraps some of these tools for convenience:
#!/bin/bash
echo "##############################################"
echo "# Choose your SD card #"
echo "##############################################"
lsblk -dn -o NAME,SIZE
while true; do
echo "# Device to format: "
read SDCARD
echo "selected: $SDCARD"
if lsblk -dn -o NAME | grep "$SDCARD"; then
break;
else
echo "Device not supported... retry"
fi
done
echo "##############################################"
echo "# using card [$SDCARD]"
echo "##############################################"
echo ""
echo "##############################################"
echo "# making preparations #"
echo "##############################################"
MOUNTDIR="/media/card"
if [ ! -d "$MOUNTDIR" ]; then
echo "Creating directory $MOUNTDIR"
sudo mkdir "$MOUNTDIR"
else
echo "Using $MOUNTDIR"
umount "/media/card"
fi
echo "exporting variables"
export OETMP=/media/geoffrey/Data/yocto-pi/rpi/build/tmp
export MACHINE=raspberrypi2
echo "unmounting stuff"
PART1="/dev/$SDCARD""p1"
PART2="/dev/$SDCARD""p2"
umount $PART1
umount $PART2
echo "##############################################"
echo "# copy boot partition #"
echo "##############################################"
./rpi/meta-rpi/scripts/copy_boot.sh $SDCARD
echo "##############################################"
echo "# copy boot partition #"
echo "##############################################"
IMAGENAME="qt5"
HOSTNME="thermopi2"
./rpi/meta-rpi/scripts/copy_rootfs.sh $SDCARD $IMAGENAME $HOSTNME
Once again, save the script and run it.
Boot the new system
With the system back up you first may want to check if you get the wlan0 interface working this time. But let's check the kernel version and driver modules first:
We notice the newer 4.9 kernel is in use, and furthermore we also see the rtl8192cu and some other related modules loaded just as I saw on my Ubuntu machine. I went ahead and configured wlan again as mentioned earlier, é voila problem solved!
Deploying custom software
I'm not yet about to open source the entire codebase for my thermostat, I think there's already lots of stuff here to get you going. I also haven't yet made a decicated recipe in Yocto included my own made binaries. For now I will deploy my thermostat software by hand and create a little init script so that it gets loaded automatically at system boot.
For starters create the init script with following content:
We turned our software into a service that can be started through the init daemon by executing the start and stop commands. One last step is need to be made for the service to automatically start at boot: we must link it to runlevel 5 so that the init service picks it up when going through all services connected to the runlevel.
root@thermopi2:/etc/rc5.d# ls -al
total 8
drwxr-xr-x 2 root root 4096 Nov 5 23:41 .
drwxr-xr-x 35 root root 4096 Nov 7 21:12 ..
lrwxrwxrwx 1 root root 20 Nov 5 23:41 S01networking -> ../init.d/networking
lrwxrwxrwx 1 root root 16 Nov 5 23:40 S02dbus-1 -> ../init.d/dbus-1
lrwxrwxrwx 1 root root 14 Nov 5 23:41 S09sshd -> ../init.d/sshd
lrwxrwxrwx 1 root root 21 Nov 5 19:46 S15mountnfs.sh -> ../init.d/mountnfs.sh
lrwxrwxrwx 1 root root 28 Nov 5 23:41 S15pi-blaster.boot.sh -> ../init.d/pi-blaster.boot.sh
lrwxrwxrwx 1 root root 14 Nov 5 23:41 S20ntpd -> ../init.d/ntpd
lrwxrwxrwx 1 root root 18 Nov 5 23:41 S20samba.sh -> ../init.d/samba.sh
lrwxrwxrwx 1 root root 16 Nov 5 23:40 S20syslog -> ../init.d/syslog
lrwxrwxrwx 1 root root 22 Nov 5 19:46 S99rmnologin.sh -> ../init.d/rmnologin.sh
lrwxrwxrwx 1 root root 23 Nov 5 20:56 S99stop-bootlogd -> ../init.d/stop-bootlogd
root@thermopi2:/etc/rc5.d# ln -s ../init.d/quicktemp.sh S95quicktemp
root@thermopi2:/etc/rc5.d# ls -al
total 8
drwxr-xr-x 2 root root 4096 Nov 7 23:29 .
drwxr-xr-x 35 root root 4096 Nov 7 21:12 ..
lrwxrwxrwx 1 root root 20 Nov 5 23:41 S01networking -> ../init.d/networking
lrwxrwxrwx 1 root root 16 Nov 5 23:40 S02dbus-1 -> ../init.d/dbus-1
lrwxrwxrwx 1 root root 14 Nov 5 23:41 S09sshd -> ../init.d/sshd
lrwxrwxrwx 1 root root 21 Nov 5 19:46 S15mountnfs.sh -> ../init.d/mountnfs.sh
lrwxrwxrwx 1 root root 28 Nov 5 23:41 S15pi-blaster.boot.sh -> ../init.d/pi-blaster.boot.sh
lrwxrwxrwx 1 root root 14 Nov 5 23:41 S20ntpd -> ../init.d/ntpd
lrwxrwxrwx 1 root root 18 Nov 5 23:41 S20samba.sh -> ../init.d/samba.sh
lrwxrwxrwx 1 root root 16 Nov 5 23:40 S20syslog -> ../init.d/syslog
lrwxrwxrwx 1 root root 22 Nov 7 23:29 S95quicktemp -> ../init.d/quicktemp.sh
lrwxrwxrwx 1 root root 22 Nov 5 19:46 S99rmnologin.sh -> ../init.d/rmnologin.sh
lrwxrwxrwx 1 root root 23 Nov 5 20:56 S99stop-bootlogd -> ../init.d/stop-bootlogd
Reboot the pi, you'll now see that your software is auto loaded at boot!
Extending the SD card lifetime
As I've mentioned in other blog post having your logs written to a tempfs volatile file system (in RAM) extends the SD card life time a lot. I wont go into detail again here, just have a look here. Note that in our Yocto image there is already the tmpfs created for you so actually we don't have to do anything extra here.
Edit
Although the RTL8192CU driver brought some improvements, it didn't offer a permanent solution. To fix it I've blacklisted the driver again:
The Supervisor daemon is an easy to use utility which makes sure your services are running and never stop. It has its own logging infrastructure which you can check when things go wrong, aside of your own logging infrastructure. However, logging can degrade the SD card on embedded Raspberry Pi systems. Tmpfs to the resque!
Tmpfs allows us to make a filesystem in RAM so that no write cycli is made on the SD card. It can easily be made be editing /etc/fstab:
When you reboot your system the content of /var/log, where all log messages are usually found, is now stored on the RAM based filesystem, hence improving SD card lifetime.
Enter Supervisor. To install supervisor:
sudo apt-get install supervisor
Configure your service by editing /etc/supervisor/conf.d/, for example I have a service running in Mono so I edit /etc/supervisor/conf.d/shutterservice.conf. Inside you’ll find following content:
When you reboot your system again you’ll find that your service might not be available. You can verify this be starting and stopping the service by hand using supervisorctl. This tool will generate some obscure errors at this stage.
The problem here is that the supervisor daemon was not able to create its /var/log/supervisor logging directory when the system boots. You may create the directory yourself and restart supervisor manually using:
sudo mkdir /var/log/supervisor
sudo service supervisor restart
This time supervisor should be able to start, double check the logging files to make sure. However when you reboot your Pi again the tmpfs system will be cleared again, and once again supervisor will not be able to start automatically because of the missing log folder. We can fix this by using a config file for systemd which automatically creates temporary files.
Go ahead and create this config file:
sudo vim /etc/tmpfiles.d/supervisor.conf
Enter following content:
d /var/log/supervisor 0777 root root
When you reboot your system everything should be working as expected, plus you have just extended your SD card’s lifetime!
Previously we made ourselves a Linux distribution ourselves for our target embedded system. We included basic Qt5 support which allows us to create a fast and responsive C++ frontend. This time we will further develop our embedded system and prepare it for usage.
Adding QtQuick – QML support
In the previous article we succeeded in created a QtWidget based application. However, with QtQuick there is a new UI framework available which has its own set of benefits. You may already have noticed that QtCreator comes with lots of examples and you may have even tried some of them. However, if you (like me) created your Yocto based OS using the bitbake qt5-basic-image command you will find that some programs may not work when yo run them on your embedded device:
root@raspberryyocto:~# ./clocks
./clocks: error while loading shared libraries: libQt5Quick.so.5: cannot open shared object file: No such file or directory
root@raspberryyocto:~#
Basically we didn’t include support for QtQuick when we compiled our OS. So if you’re into using QtQuick go back through your Yocto working folder and bitbake the qt5-image:
Notice how fast compiling the image goes this time compared to when we build the qt5-basic-image. The reason for this faster build time is because the qt5-image inherits the qt5-basic-image and Yocto just needed to recompile some of the components that were not yet compiled. Also note that you don’t need a new SDK and you shouldn’t need to re-configure QtCreator.
With your SD card already formatted you only need to copy the compiled files to your SD card:
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/build$ cd ../meta-rpi/scripts/
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$ sudo umount /dev/mmcblk0p1
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$ sudo umount /dev/mmcblk0p2
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$ export MACHINE=raspberrypi
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$ export OETMP=/media/geoffrey/Data/yocto-pi/rpi/build/tmp
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$ ./copy_rootfs.sh mmcblk0 qt5 raspberryyocto
OETMP: /media/geoffrey/Data/yocto-pi/rpi/build/tmp
IMAGE: qt5
HOSTNAME: raspberryyocto
File found: /media/geoffrey/Data/yocto-pi/rpi/build/tmp/deploy/images/raspberrypi/qt5-image-raspberrypi.tar.xz
Block device not found: /dev/mmcblk02, trying p2
Formatting /dev/mmcblk0p2 as ext4
[sudo] wachtwoord voor geoffrey:
/dev/mmcblk0p2 bevat een ext4-bestandssysteem met label 'ROOT'
laatst aangekoppeld op / op Sun Feb 19 22:07:51 2017
Toch doorgaan? (j,n) j
Mounting /dev/mmcblk0p2
Extracting qt5-image-raspberrypi.tar.xz to /media/card
Writing raspberryyocto to /etc/hostname
Unmounting /dev/mmcblk0p2
Done
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$
With that done we need to have a QtQuick test application. If you haven’t yet tried on of the QtCreator’s QtQuick examples do so now. Get back to your embedded device, insert the SD card and boot. Once booted, retrieve the device’s IP address and copy over any QtQuick test application. I’ve used the clocks application. Once you have the application compiled and copied over to the raspberry pi, ssh into your pi and start the application (or launch it from within QtCreator if you’ve had it still openened). You should see more or less something like this:
If you happen to run into “out of memory” errors:
root@raspberryyocto:~# ./clocks
QML debugging is enabled. Only use this in a safe environment.
Unable to query physical screen size, defaulting to 100 dpi.
To override, set QT_QPA_EGLFS_PHYSICAL_WIDTH and QT_QPA_EGLFS_PHYSICAL_HEIGHT (in millimeters).
JIT is disabled for QML. Property bindings and animations will be very slow. Visit https://wiki.qt.io/V4 to learn about possible solutions for your platform.
glGetError 0x505
QSGTextureAtlas: texture atlas allocation failed, out of memory
… then you should tweak the CPU/GPU memory allocation settings. This settings is loaded at boot and it is also saved in a config file on your boot partition. To adjust the config file we first need to mount the boot partition, and next we can edit the file using the vi editor:
root@raspberryyocto:~# mkdir /mnt/fat
root@raspberryyocto:~# mount /dev/mmcblk0p1 /mnt/fat
root@raspberryyocto:~# vi /mnt/fat/config.txt
Add gpu_mem=256 to this file and reboot your pi. Try again running the clocks application, things should go now as intended:
root@raspberryyocto:~# ./clocks
QML debugging is enabled. Only use this in a safe environment.
Unable to query physical screen size, defaulting to 100 dpi.
To override, set QT_QPA_EGLFS_PHYSICAL_WIDTH and QT_QPA_EGLFS_PHYSICAL_HEIGHT (in millimeters).
JIT is disabled for QML. Property bindings and animations will be very slow. Visit https://wiki.qt.io/V4 to learn about possible solutions for your platform.
Setting the timezone
To show the current time we will rely on NTP. RaspberryPi does not come with a RTC see I don’t see any other option. NTP is already added via Yocto, we only have to set the correct timezone:
root@yoctopi:~# ls -l /etc/localtime
lrwxrwxrwx 1 root root 27 Apr 10 18:36 /etc/localtime -> /usr/share/zoneinfo/EST5EDT
root@yoctopi:~# rm /etc/localtime
root@yoctopi:~# ln -s /usr/share/zoneinfo/Europe/Paris /etc/localtime
root@yoctopi:~# date
Sun Apr 16 12:30:40 CEST 2017
Adding a touch screen
The RaspberryPi community has a very decent 7″ touch screen. There is not much to say about, I got one, followed the instructions to hook it op and basically started testing some my applications straight away!
Side note: I used the same housing as show above. This one has the display upside down, the rotate the display through software we must again edit the config file on the boot partition:
root@raspberryyocto:~# mkdir /mnt/fat
root@raspberryyocto:~# mount /dev/mmcblk0p1 /mnt/fat
root@raspberryyocto:~# vi /mnt/fat/config.txt
and add:
display_rotate=2
Restart to apply your changes.
Adding a HTU21D I²C temperature sensor
The HTU21D is a decent temperature and humidity sensor which perfectly suits our needs. To hook it up to our Raspberry Pi 2:
Before we can use the I2C bus we must again edit the Pi’s config file:
root@raspberryyocto:~# mkdir /mnt/fat
root@raspberryyocto:~# mount /dev/mmcblk0p1 /mnt/fat
root@raspberryyocto:~# vi /mnt/fat/config.txt
and add:
dtparam=i2c_arm=on
Restart to apply your changes.
After the system has booted into Linux again we will first check if the i2c_bcm2708 module has been loaded:
This write-up will focus on how to create your own Linux distribution, using Yocto. Yocto is a popular tools these days for creating an embedded operating system from scratch. I’m not going to talk you into how Yocto works, where it came from and so on. If you have no idea at all then go visit the Yocto Project website.
Because this is going to be a single unit creation you might think that it is a bit silly to go through the entire phase of creating you own Linux distribution. Well, off course that’s true, using a full blown distribution like Debian, Fedora or Ubuntu might have the benefits of having the distribution already created for you, with every tool available that you’ll ever need. Creating a Yocto based distribution also has some benefits of its own. For example you can add or remove system components and use only those you really need. This may for example reduce boot time. Furthermore, you have more control over your system, you can toss in/out the components that you require and so the OS isn’t bloated either with programs and tools that you’d never use. This may gratefully reduce the OS’s footprint. And actually it’s a good training to get to know the Yocto Project because it is often used nowadays in embedded systems. At least if that’s where you’re interested in.
The embedded device I’m about to use is the Raspberry Pi 2. The reason I’m choosing this device is simple: it has all the components that I need, it has support for many add-ons, it has a large community which may help you out whenever you get into trouble, it’s relatively cheap to buy and easy to find in stores, and I have already sitting one on my desk waiting for an application to be used in.
(Bit)baking your own Linux distribution
I could go through all the steps of how to create a Yocto based distribution for your Raspberry Pi. Fact is that someone already did write a very good tutorial which I’ve couldn’t done better, so first head over to the Jumpnowtek website and follow the tutorial. Furthermore this guy already did a lot of work for you so his using his layer for raspberry pi will add support for many devices. You can find his Git repo here. For those who’re not fund on compiling their own Yocto distribution but instead just want to go ahead and use it, you can also find downloadable content on the Jumpnowtek download sector.
For my Yocto project I’ve used my Dell XPS 15 laptop with a second HDD of 512Gb installed, 8Gb of RAM and the Ubuntu 16.04 LTS operating system. Because I had this drive already available I’m using this one, but if you’re about to buy a new build setup look for something which is fast, which has a CPU with many cores, which contains a lot of DRAM, and something that uses a SDD. Using faster build systems might dramatically reduce build times because building your own distribution on a system of few years old might easily take 6 to 8 hours!
I creating a dedicated directory (/media/geoffrey/Data/yocto-pi) on my second hard drive and I’ll use this directory to make all of my yocto builds. First pull-in all required repos as instructed on the Jumpnowtek website and initialize your build directory. Because I’m going to be using the Qt5 framework (a C++ UI framework) I’ll be building a QT5 Yocto image and so I need to include several QT5 layers. Here is my bblayers.conf file:
I’ve build the Yocto image using following command:
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi$ source poky-morty/oe-init-build-env /media/geoffrey/Data/yocto-pi/rpi/build
## Shell environment set up for builds. ###
You can now run 'bitbake '
Common targets are:
core-image-minimal
core-image-sato
meta-toolchain
meta-toolchain-sdk
adt-installer
meta-ide-support
You can also run generated qemu images with a command like 'runqemu qemux86'
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/build$
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/build$ bitbake qt5-basic-image
Wait for the build to complete and next copy your files to the SD card using the Jumpnowtek site’s instructions. Make sure you copy it to the correct disk!
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 465,8G 0 disk
├─sda1 8:1 0 244,8G 0 part /
├─sda2 8:2 0 220,6G 0 part
└─sda3 8:3 0 450M 0 part
sdc 8:32 1 3,7G 0 disk
├─sdc1 8:33 1 64M 0 part
└─sdc2 8:34 1 3,6G 0 part
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$ sudo mkdir /media/card
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$ sudo ./mk2parts.sh sdc
[sudo] wachtwoord voor geoffrey:
Working on /dev/sdc
umount: /dev/sdc: not mounted
DISK SIZE – 3963617280 bytes
Okay, here we go ...
=== Zeroing the MBR ===
1024+0 records gelezen
1024+0 records geschreven
1048576 bytes (1,0 MB, 1,0 MiB) copied, 0,53551 s, 2,0 MB/s
=== Creating 2 partitions ===
Checking that no-one is using this disk right now ... OK
Disk /dev/sdc: 3,7 GiB, 3963617280 bytes, 7741440 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
>>> Created a new DOS disklabel with disk identifier 0x6efbfa0c.
Created a new partition 1 of type 'W95 FAT32 (LBA)' and of size 64 MiB.
/dev/sdc2: Created a new partition 2 of type 'Linux' and of size 3,6 GiB.
/dev/sdc3:
New situation:
Apparaat Op. Start Einde Sectoren Size Id Type
/dev/sdc1 * 8192 139263 131072 64M c W95 FAT32 (LBA)
/dev/sdc2 139264 7741439 7602176 3,6G 83 Linux
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
=== Done! ===
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 465,8G 0 disk
├─sda1 8:1 0 244,8G 0 part /
├─sda2 8:2 0 220,6G 0 part
└─sda3 8:3 0 450M 0 part
sdc 8:32 1 3,7G 0 disk
├─sdc1 8:33 1 64M 0 part
└─sdc2 8:34 1 3,6G 0 part
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$ export OETMP=/media/geoffrey/Data/yocto-pi/rpi/build/tmp
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$ export MACHINE=raspberrypi
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$ ./copy_boot.sh sdc
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$ ./copy_rootfs.sh sdc qt5 raspberryyocto
OETMP: /media/geoffrey/Data/yocto-pi/rpi/build/tmp
IMAGE: qt5
HOSTNAME: raspberryyocto
Formatting /dev/sdc2 as ext4
[sudo] wachtwoord voor geoffrey:
/dev/sdc2 bevat een ext4-bestandssysteem met label 'ROOT'
laatst aangekoppeld op /media/card op Wed Mar 29 11:33:06 2017
Toch doorgaan? (j,n) j
Mounting /dev/sdc2
Extracting qt5-image-raspberrypi.tar.xz to /media/card
Writing raspberryyocto /etc/hostname
Unmounting /dev/sdc2
Done
Creating a cross-platform toolchain for application development
Even though our embedded device might contain all the tools needed to compile native applications, most of the time you’ll be wanting to use the processing power of your development machine to speed up development. For this reason we need to install the cross-compilation toolchain. But first we need to create the toolchain using bitbake. Navigate to your working directory and use following command to build the toolchain:
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi$ source poky-morty/oe-init-build-env /media/geoffrey/Data/yocto-pi/rpi/build
### Shell environment set up for builds. ###
You can now run 'bitbake '
Common targets are:
core-image-minimal
core-image-sato
meta-toolchain
meta-ide-support
You can also run generated qemu images with a command like 'runqemu qemux86'
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/build$ clear; bitbake meta-toolchain-qt5
Loading cache: 100% |##################################################################| Time: 0:00:00
Loaded 2660 entries from dependency cache.
Parsing recipes: 100% |################################################################| Time: 0:00:01
Parsing of 1972 .bb files complete (1964 cached, 8 parsed). 2668 targets, 353 skipped, 0 masked, 0 errors.
NOTE: Resolving any missing task queue dependencies
Build Configuration:
BB_VERSION = "1.32.0"
BUILD_SYS = "x86_64-linux"
NATIVELSBSTRING = "universal"
TARGET_SYS = "arm-poky-linux-gnueabi"
MACHINE = "raspberrypi"
DISTRO = "poky"
DISTRO_VERSION = "2.2.1"
TUNE_FEATURES = "arm armv6 vfp arm1176jzfs callconvention-hard"
TARGET_FPU = "hard"
meta
meta-poky = "morty:a3fa5ce87619e81d7acfa43340dd18d8f2b2d7dc"
meta-oe
meta-multimedia
meta-networking
meta-python = "morty:1efa5d623bc64659b57389e50be2568b1355d5f7"
meta-qt5 = "morty:9aa870eecf6dc7a87678393bd55b97e21033ab48"
meta-raspberrypi = "master:e1f69daa805cb02ddd123ae2d4d48035cb5b41d0"
meta-rpi = "morty:03841471ccaed549a2a14a896c13f71af76cf482"
Initialising tasks: 100% |#############################################################| Time: 0:00:05
NOTE: Executing SetScene Tasks
NOTE: Executing RunQueue Tasks
NOTE: Tasks Summary: Attempted 3170 tasks of which 1605 didn't need to be rerun and all succeeded.
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/build$
Again, this will take a lot of time, depending on how fast your dev-pc is. When the build completes you’ll get as a result the script that install the SDK on your development pc. On my pc it was found in the /media/geoffrey/Data/yocto-pi/rpi/build/tmp/deploy/sdk folder. The script is named poky-glibc-x86_64-meta-toolchain-qt5-arm1176jzfshf-vfp-toolchain-2.2.1.sh.
Run the script, and when asked for the install folder I’ve chosen the default option. If you plan to create more than one SDK I’d highly recommend to install each in their own directory. There is no need to run this script as root user. Note that running this script takes roughly 2 minutes to complete, enough time to grab a dieet coke!
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/build/tmp/deploy/sdk$ ./poky-glibc-x86_64-meta-toolchain-qt5-arm1176jzfshf-vfp-toolchain-2.2.
1.sh
Poky (Yocto Project Reference Distro) SDK installer version 2.2.1
=================================================================
Enter target directory for SDK (default: /opt/poky/2.2.1):
You are about to install the SDK to "/opt/poky/2.2.1". Proceed[Y/n]? Y
[sudo] password for geoffrey:
Extracting SDK............................................................................................................................done
Setting it up...done
SDK has been successfully set up and is ready to be used.
Each time you wish to use the SDK in a new shell session, you need to source the environment setup script e.g.
$ . /opt/poky/2.2.1/environment-setup-arm1176jzfshf-vfp-poky-linux-gnueabi
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/build/tmp/deploy/sdk$
Compiling your first program
We came as far as creating a self-made Yocto based distribution with Qt5.7 pre-installed, plus having all the tools installed on our development pc to create a nice embedded application. If you don’t use an IDE then go ahead and use the instructions on the Jumpnowtek website to go ahead and compile your application using qmake.
qmake: could not exec '/usr/lib/x86_64-linux-gnu/qt4/bin/qmake': No such file or directory
… you probable forget to use the source command! Note that the source command is bound to the shell where you used it. If you used it inside a shell script than it will only take effect to the commands inside the shell script!
After compiling has completed you get several files as output. One of the files is the binary executable that represent our program. We can also verify if is has been compiled for ARM:
geoffrey@geoffrey-Dell-XPS-L502X:~/Qt5.5.1/Projects/HelloQtWidgets$ ls -l HelloQtWidgets
-rwxrwxr-x 1 geoffrey geoffrey 1181132 feb 18 17:33 HelloQtWidgets
geoffrey@geoffrey-Dell-XPS-L502X:~/Qt5.5.1/Projects/HelloQtWidgets$ ^C
geoffrey@geoffrey-Dell-XPS-L502X:~/Qt5.5.1/Projects/HelloQtWidgets$ file HelloQtWidgets
HelloQtWidgets: ELF 32-bit LSB executable, ARM, EABI5 version 1 (GNU/Linux), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, BuildID[sha1]=56d390438db87a396f5f28e7adbbdd69cdd0ee68, not stripped
We can now copy the file over to our embedded system:
Next, login to the embedded system using ssh and execute the binary file. You’ll need to have a display attached to your pi in order to view the UI:
geoffrey@geoffrey-Dell-XPS-L502X:~$ ssh root@192.168.0.205
root@raspberryyocto:~# ls
HelloQtWidgets
root@raspberryyocto:~# ./HelloQtWidgets
Unable to query physical screen size, defaulting to 100 dpi.
To override, set QT_QPA_EGLFS_PHYSICAL_WIDTH and QT_QPA_EGLFS_PHYSICAL_HEIGHT (in millimeters).
Setting up QtCreator
Whenever you’re about to create a more advanced program with an UI you’ll find yourselve in the need of a IDE. QtCreator is quit good in providing all the tools you need to create graphical applications so I highly recommend using QtCreator to develop your applications. We’ll now configure QtCreator to use the SDK we’ve used above.
First you need to install QtCreator. Go to the Qt website, fill in the licence form and download Qt5.7. You may also look for the open source version of Qt here. Next make the downloaded file executable and run it. You may install Qt in the default folder. Next we’ll configure QtCreator to use the compiler, debugger, etc. Note that for compiling native applications for our embedded system we need to source the SDK folder each time we run QtCreator. For convenience I created a script that does this for me:
geoffrey@geoffrey-Dell-XPS-L502X:~$ vim qtcreator4pi.sh
You should now see the default welcome page for QtCreator. Next from the main menu bar at the top of the application click the Tools menu item and open the Options window. Now do following steps (note that some steps might look a bit different as the screenshots I’ve made are made on a Qt5.5 setup):
Create your device
Navigate to Devices, click Add, select Generic Linux Device and start the Wizard. Enter following content:
Name: [pick your own name, for example Pi One]
Hostname: [the IP address of your raspberry pi]
Username: root
Authentication type: Password
Password: [leave empty]
Click next, QtCreator will now test your connection and if all goes well you’d get following output:
Connecting to host...
Checking kernel version...
Linux 4.4.43 armv6l
Checking if specified ports are available...
All specified ports are available.
Device test finished successfully.
Make sure to Apply your configuration at this point.
Configure the Qt Version
Navigate to Build &Run > Qt Versions, click Add. If not already selected, navigate and select the /opt/poky/2.2.1/sysroots/x86_64-pokysdk-linux/usr/bin/qt5/qmake executable. Adjust the path to your needs.
Configure the compiler
Navigate to Build & Run > Compilers, click Add, select GCC and use following settings:
Name: [choose your own name, for example Pi One GCC]
Compiler Path: /opt/poky/2.2.1/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi-g++
Configure the debugger
Navigate to Build & Run > Debuggers, click Add and use following settings:
Name: [choose your own name, for example Pi One GDB]
Path: /opt/poky/2.2.1/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi-gdb
Configure the kit (aka hook everything up together)
Navigate to Build & Run > Kits, click Add, and enter following content.
Name: [choose your own name, for example Pi One]
Device Type: Generic Linux Device
Device: [choose the device we created earlier]
Sysroot: /opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi
Compiler: [choose the compiler we configured earlier]
Debugger: [choose the debugger we configured earlier]
Qt Version: [choose the Qt version we configured earlier]
Qt mkspec: linux-oe-g++
We’ve now correctly configured QtCreator for cross-platform development. We need to perform this configuration only once per SDK. Note that whenever you’re going to compile, deploy or debug your application on your embedded device that you launch QtCreator using the script we created earlier (the one that contains the source command). If however your target machine is your own pc you don’t need to source in any SDK and so you can launch QtCreator directly from command line or or using any desktop shortcut.
Building & running applications
With QtCreator configured to use our embedded device’s SDK we can now open a demo application. Note, because I’ve chosen the qt5-basic-image we must take note that not all Qt5 libraries will be available on our target machine. So while QtCreator does provide quite some Qt demo apps, some may work for you.
For this purpose I’ll use a self made demo app. Make sure you’ve launched QtCreator with using our launch script, and open the demo application project. The project might not yet contain build settings that allows us to choose the Pi One kit as build target. We can add this by selecting the Projects button on the left menu bar, click Add kit and select the one we’ve configured earlier. In my case I’d select Pi One:
Now, from the left menu bar select your target kit:
Use the hammer icon the build your application. As a result you’ll find a new directory inside your QtCreator working directory, and inside you’ll find the executable binary file we just created.
By now we have our own Linux based OS with all the tools installed to develop our thermostat UI an backend software. Stay tuned for more.
Currently I’m controlling my house’s heating system with a Theben RAM 325:
My first goal was to get a some understanding of how the current thermostat was doing its job. I don’t own the manual anymore so I was more or less on my own to figure out how to use this thermostat. Well, it’s not overly complicated, and in the end I found at that the Theben RAM725 works as a replacement for the RAM325 so I could go use the 725’s manual as reference.
The left side if the thermostat houses a 12h clock. In the upper left corner we find an indicator which tells us tells us weather it’s in “normal” (day) or “energy saving” (night) mode. The picture above is taken with the energy mode in “normal”. On the bottom right side we can find the temperature setting which allows us to set the energy saving mode temperature. A more advanced version also has a second temperature settings used to set the temperature during normal operation. At the top right we find the program selection switch which has 3 pre-defined programs: automatic program (clock icon), forced energy saving program (moon icon), and the comfort program (the one that is currently selected) where the thermostatic taps decide the temperature.
What you don’t see in this picture is that behind the clock we can set “on” and “off” jumpers which are used in automatic mode. There is also a LED located at the front which indicates when the heating system is heating.
The back side tells us its 230V powered (connectors 4 and 5). Connectors 1, 2, and 3 are used to control the heater (gas burner, valve, …). Here are some wiring examples:
There is also a small adjustment screw on the upper left side which allows tweaking the temperature trigger point.
Although this thermostat does a good job in what it needs to do, it’s pretty cheap and reliable, but it’s not really the most sexy thing to have in house and for an embedded engineer that I am a perfect goal to tackle on my own!
The newcomer
The embedded device I’m about to use is the Raspberry Pi 2. The reason I’m choosing this device is simple: it has all the components that I need, it has support for many add-ons, it has a large community which may help you out whenever you get into trouble, it’s relatively cheap to buy and easy to find in stores, and I have already sitting one on my desk waiting for an application to be used in. Furthermore it has a pretty decent touch screen and all sorts housing available so that I don’t have to tech the entire system by myself.
With that given this will be the first article in series of 3 to 4 articles in which I’ll tell you how I came to build my own modern thermostat. Stay tuned for more!