This document expands on the large screen display microscope but instead builds a portable microscope with a small RCA connected screen as well as taking care to implement the button as a means to take snapshots and various other tweaks.
Car LCD screens seem to be suitable for many applications given their very low cost as well as their suitable resolution. Furthermore, the screen is very light such that it can be wall-mounted.
The only modification necessary to the Raspberry Pi is to switch from HDMI output to composite output. This involves soldering two additional pins to the Raspberry Pi board and creating a lead, preferably with an RCA video jack. After the software modification, given the already existing setup described in this document, the Raspberry Pi seems to boot up perfectly and display video on the LCD screen seamlessly without any extra setup needed.
One of the annoyances has been that the Raspberry Pi Zero is to be powered using . Even though the Raspberry Pi Zero can be powered with via the pin, is still needed in order to operate USB devices connected to the Raspberry Pi; in this case, the microscope. This would mean that two separate power regulators would have to be used which makes the project too complex. To work around this issue, a step down has been used and a pass-through has been designed in order to supply the LCD screen with whilst pulling to power on the Raspberry Pi using the pin header.
This is a very simple circuit as can be seen from the following sketch:
+----------+----------------+ -> 12V | 12V -> to LCD car screen +-------+--|----------------+ | | +--|--+-------+-----+ | | Stepdown | 5V -> to Raspberry Pi pin header +--+----------+-----+
Putting it all together, some single use straps are necessary to hold all the cables in place while letting only two connectors dangling: the power jack and the micro USB to USB cable to connect the microscope.
Factoring in the cost of all components, the whole project could sum up to the cheapest LCD microscope on the market but with the extra value that each separate component can at a later time be reused, or even used at the same time for different purposes (ie: displaying an oscilloscope signal as well) thereby offering lots more wiggle room for further developments. That being said, the back of the LCD screen could be simplified and the cables could perhaps be cut down to size but it would reduce the re-usability of the components. In any case, all the circuitry is connected at the back of the LCD screen and the LCD is wall-mounted such that the cables cannot be seen anyway.
Nicely enough, the cheap microscope has two buttons: one for changing the light setting and another button that can be mapped manually to whatever function the user wants to have. One idea is to make Linux read the button state and when pressed, take a snapshot of the microscope image and then save it on a network share for further inspection or processing.
The first problem is that while ffmpeg
will be used to render the microscope image to the screen, when the button is pressed, ffmpeg
would have to be used again to take the screenshot but that will not work because the device will be kept busy by the first instance of ffmpeg
. To work around that issue, the microscope stream is multiplexed from /dev/video0
to /dev/video50
and /dev/video51
using v4l2loopback
as described on the Linux FUSS page. A service file is created at /etc/systemd/system/microscope_clone.service
with the following contents:
[Unit] Description=Microscope Clone After=multi-user.target Before=microscope.service microscope_button.service [Service] ExecStart=/usr/bin/ffmpeg -hide_banner -loglevel quiet -f v4l2 -i /dev/video0 -codec copy -f v4l2 /dev/video50 -codec copy -f v4l2 /dev/video51 Restart=always RestartSec=10 StandardOutput=syslog StandardError=syslog SyslogIdentifier=microscope User=root Group=root Environment=PATH=/usr/bin/:/usr/local/bin/ [Install] WantedBy=microscope.target
Next, ffmpeg
can be used to read the microscope image and then render it directly to the framebuffer. To that end, a service file is created at /etc/systemd/system/microscope.service
with the following contents:
[Unit] Description=Microscope After=microscope_clone.service Before=microscope_button.service [Service] ExecStart=/usr/bin/ffmpeg -hide_banner -loglevel quiet -f v4l2 -video_size 640x420 -i /dev/video50 -pix_fmt rgb565le -f fbdev /dev/fb0 Restart=always RestartSec=10 StandardOutput=syslog StandardError=syslog SyslogIdentifier=microscope User=root Group=root Environment=PATH=/usr/bin/:/usr/local/bin/ [Install] WantedBy=microscope.target
And now a third service file is created that will be responsible for reading the microscope button and then saving the image onto a network share. In order to do that, Samba can be installed, perhaps even by using Samba standalone templates and then a Samba share created that will store the images.
Typically, the kernel will recognize any button as well and will create a device file for the button from which events can be later read.
usb 1-1: Found UVC 1.00 device USB2.0 UVC PC Camera (05e3:0515) input: USB2.0 UVC PC Camera: USB2.0 UV as /devices/platform/soc/20980000.usb/usb1/1-1/1-1:1.0/input/input0
There are multiple ways to read the microscope button, but perhaps the most accessible is to use evtest
in order to check the button device for input events along with a simple polling bash script that will read the input button.
First, create the following filesystem directory structure:
root +--- etc + | +--- camera_button + | +--- 1.d | +--- 0.d
by executing the command:
mkdir -p /etc/camera_button/{0,1}.d
Now the directory /etc/camera_button/1.d
will hold bash scripts that will be run whenever the button is pressed, and /etc/camera_button/0.d
will hold bash scripts that will be run whenever the button is released. For that to work, a script is needed that is created at /etc/camera_button/uvcbutton.sh
with the following contents:
#!/bin/sh ########################################################################### ## Copyright (C) Wizardry and Steamworks 2023 - License: GNU GPLv3 ## ########################################################################### ########################################################################### ## CONFIGURATION ## ########################################################################### # A directory containing scripts to execute on button down. A_DIRECTORY=/etc/camera_button/1.d # A directory containing scripts to execute on button up. B_DIRECTORY=/etc/camera_button/0.d # The input device for the camera button. BUTTON_INPUT_DEVICE="/dev/input/by-id/usb-05e3_USB2.0_UVC_PC_Camera_USB2.0_UVC_PC_Camera-event-if00" ########################################################################### ## INTERNALS ## ########################################################################### a() { for SCRIPT in `find $A_DIRECTORY -type f -executable`; do bash $SCRIPT done } b() { for SCRIPT in `find $B_DIRECTORY -type f -executable`; do bash $SCRIPT done } A='*KEY_CAMERA*value 1*' B='*KEY_CAMERA*value 0*' evtest --grab $BUTTON_INPUT_DEVICE | \ while read LINE; do #DEBUG #echo $LINE # function a (press) and b (release) are forked case $LINE in ($A) a & ;; ($B) b & ;; esac done
The section under the CONFIGURATION
section has to be modified and, in particular, to set the BUTTON_INPUT_DEVICE
variable to the path of the input device generated by the kernel.
The script is then started using a SystemD service file (the third one created in this guide), that is created at /etc/systemd/system/microscope_button.service
and has the following contents:
[Unit] Description=Microscope Button After=multi-user.target microscope_clone.service microscope.service [Service] ExecStart=/etc/camera_button/uvcbutton.sh Restart=always RestartSec=10 StandardOutput=syslog StandardError=syslog SyslogIdentifier=microscope User=root Group=root Environment=PATH=/usr/bin/:/usr/local/bin/ [Install] WantedBy=microscope.target
The service file will run the script placed at /etc/camera_button/uvcbutton.sh
and will then run scripts inside /etc/camera_button/1.d
respectively /etc/camera_button/0.d
when the button is pressed or released. In order to take the snapshot, a script is placed at /etc/camera_button/1.d/snapshot.sh
with the following contents:
#!/bin/sh /usr/bin/ffmpeg \ -hide_banner \ -loglevel quiet \ -f v4l2 \ -video_size 640x480 \ -i /dev/video51 \ -pix_fmt rgb565le \ -vframes 1 \ /mnt/images/snapshot-`date +%s`.jpg
When the script runs due to pressing the button on the microphone, a file is created inside /mnt/images/
following the naming convention snapshot-TIMESTAMP.jpg
where TIMESTAMP
is the epoch time in unix format. It follows that /mnt/images
should then be shared on the network by using Samba, perhaps using the following Samba share configuration:
[images] comment = Microscope Images path = /mnt/images valid users = root pi # Create file under this user - useful for seamlessly copying files. force user = pi force group = pi read only = No create mask = 0664 force create mode = 0664 force directory mode = 0755
where pi
is the Raspberry Pi username (note that the pi
user would have to be added to Samba by using the smbpasswd
command).
In total, there should be three files created inside /etc/systemd/system/
, namely microscope_clone.service
that will be responsible for duplexing the video device, microscope.service
that will be responsible for reading from the microscope and then rendering the image to the Linux frame buffer and a final script named microscope_button.service
that will take care to take a snapshot of the microscope when the microscope button is clicked.
The directory /etc/systemd/system/microscope.target.wants
is created to store links to the three service files.
ln -sf /etc/systemd/system/{microscope_clone,microscope,microscope_button}.service /etc/systemd/system/microscope.target.wants
Finally, the microscope
target file is created at /etc/systemd/system/microscope.target
with the following contents:
[Unit] Description=Microscope Target Requires=multi-user.target After=multi-user.target AllowIsolate=yes
and the default target is changed to the microscope
target by issuing:
systemctl set-default microscope.target
In doing so, this ensures that the microscope
target executes all the three service files after all other services have been started.
Although pitched as "performance" yet pertaining more to "safety", recent Raspbian distribution releases include an option named "Overlay File System Enable/disable read-only file system", that can be accessed from the "Performance Options" menu via the raspi-config
tool.
The purpose of this setting is to extend a memory-only read-only overlay on top of the entire filesystem thereby making the filesystem read-only. Generally this is a good idea because IoT devices are typically more prone to be abused in terms of power with the likelihood that the device will be powered down or up by pulling the cable being very high. Over time, bad powercycling will eventually lead to the deterioration of the filesystem and given that this project is finalized, there is not reason to allow further writes.