This project started with a simple goal: build a dedicated driver’s license scanner that can sit at a counter, scan the barcode on the back of a license, determine the customer’s age, and immediately give the operator a clear result.
I wanted the system to operate independently without requiring a conventional computer at the counter.
The basic concept became:
Driver’s License → PDF417 Scanner → Raspberry Pi → Decode ID → Calculate Age → Display Result → Log Scan
The finished system is intended to:
Read the PDF417 barcode on the back of a U.S. driver’s license
Decode standard AAMVA data contained in the barcode
Determine the person’s date of birth
Calculate their current age
Clearly display whether they are 21 or older
Check the expiration date when that information is available
Record scan information in a spreadsheet
Eventually provide different audible signals for different scan results
Start automatically when the Raspberry Pi is powered on
The goal is a small, dedicated appliance rather than a general-purpose computer.
My first attempt used an older Honeywell MS9590 VoyagerGS USB barcode scanner.
The scanner worked perfectly as a USB device, but scanning a driver’s license produced only a short string of numbers.
That led to an important discovery.
There are multiple barcodes on the back of a driver’s license.
The small conventional barcode can be read by many older 1D laser scanners. The large rectangular barcode made from many stacked rows is a PDF417 2D barcode.
PDF417 is the barcode this project needs.
The PDF417 barcode contains the encoded driver's license information itself. Reading the basic information does not require contacting a state driver's-license database.
A PDF417-capable scanner decodes the information printed on the card and sends that data to the Raspberry Pi.
Important: Reading the barcode is not the same as authenticating a driver's license against a government database. This project reads and evaluates information encoded on the physical card.
Raspberry Pi
microSD card, 32 GB or larger
5V / 3A USB-C Raspberry Pi power supply
Display
Raspberry Pi 4 compatible touchscreen enclosure
Barcode Scanner
PDF417 support
USB connection
Operated in USB/HID keyboard mode
Future Audio
Small speaker mounted to the display enclosure
Audio hardware will be added later
Software will be written with audio support already included
The scanner is connected directly to the Raspberry Pi by USB. Using a wired connection eliminates Bluetooth pairing, battery management, and unnecessary wireless dependencies.
I already had the microSD card and Raspberry Pi power supply, so those added no additional cost to this build.
Component
Cost
Raspberry Pi 4 Model B
$82.00
7" Touchscreen Display
$35.00
PDF417 Barcode Scanners, 2
$45.00
32GB+ microSD Card
Already Owned
Raspberry Pi 5V / 3A Power Supply
Already Owned
TOTAL OUT-OF-POCKET COST
$162.00
The scanner purchase included two scanners, so the effective cost was $22.50 each. Only one is required for the build, leaving the second as a spare or for another project.
Total spent on the project: $162.00
When an ID is scanned, the process is:
1. Scan
The 2D scanner reads the large PDF417 barcode on the back of the driver's license.
2. Decode
The scanner converts the PDF417 barcode into text and sends it to the Raspberry Pi.
3. Parse
The Raspberry Pi searches the AAMVA data for fields such as date of birth and expiration date.
Common AAMVA field identifiers include:
DBB – Date of Birth
DBA – Expiration Date
DAQ – Driver/Customer ID
DCS – Family Name
DAC – First Name
4. Calculate
The software calculates the person's age using the date of birth and the current date.
5. Display
The touchscreen gives the operator an immediate result.
Possible results include:
21+ VERIFIED
UNDER 21
ID EXPIRED
READ ERROR
6. Log
The scan is written to a spreadsheet for recordkeeping.
Each successful scan will create a new row in the scanner log.
The initial system will maintain a local CSV spreadsheet on the Raspberry Pi.
The log can contain fields such as:
Scan Date | Scan Time | Result | Age | Date of Birth | Expiration | First Name | Last Name | License/Customer ID | Issuing Jurisdiction | Raw AAMVA Data
A future version may automatically send the information to a Google Sheet while retaining the local file as a backup.
Because driver's-license barcode data contains personally identifying information, access to the spreadsheet and the Raspberry Pi should be restricted appropriately. Data retention should also be limited to whatever information is actually required for the intended use.
The first version will operate without a speaker.
However, audio support is being included in the software from the beginning so a speaker can be added later without redesigning the application.
The planned sounds are:
🟢 21+ VERIFIED
A short positive two-tone sound
🔴 UNDER 21
A distinctive warning sequence
🟠 EXPIRED ID
A separate warning tone
⚠️ READ ERROR
A low error tone indicating that the ID should be scanned again
The screen will always display the result, so audio will supplement rather than replace the visual indication.
The Raspberry Pi will run Raspberry Pi OS.
The basic installation process is:
Install Raspberry Pi Imager on another computer.
Insert the microSD card.
Select Raspberry Pi OS.
Configure Wi-Fi and user information if desired.
Write the operating system to the microSD card.
Install the card in the Raspberry Pi.
Connect the touchscreen.
Connect the PDF417 scanner by USB.
Power on the Raspberry Pi.
Complete the initial Raspberry Pi OS configuration.
Before installing the age-verification application, the scanner should be tested independently.
Open a text editor on the Raspberry Pi.
Place the cursor in the document and scan the large PDF417 barcode on the back of a driver's license.
A properly configured scanner should produce considerably more information than a conventional UPC-style barcode.
The output should contain AAMVA field identifiers.
For example, you may see fields beginning with:
DAQ
DCS
DAC
DBA
DBB
If this information appears, the scanner is successfully decoding the PDF417 barcode.
If only a short number appears, verify that you are scanning the large PDF417 barcode and that PDF417 decoding is enabled on the scanner.
This device reads information encoded on the driver's license.
It does not automatically contact DPS, DMV, TABC, or another government system.
Therefore:
It can:
Read the encoded DOB, calculate age, read the encoded expiration date, and process other AAMVA information present in the PDF417 barcode.
It cannot, by itself:
Confirm that DPS currently considers the license valid, determine whether a license has subsequently been suspended or revoked, or prove that a sophisticated counterfeit card is genuine.
The scanner should therefore be considered an ID-reading and age-calculation tool, not a government-backed identity authentication system.
✓ Raspberry Pi selected
✓ Touchscreen selected
✓ First 1D scanner tested
✓ Discovered PDF417 requirement
✓ PDF417-capable scanner purchased
✓ New scanner successfully reads driver's licenses
✓ Spreadsheet logging added to design
✓ Audio alerts included in software design
○ Install Raspberry Pi OS
○ Install scanner application
○ Test AAMVA parsing
○ Test age calculations
○ Test expiration detection
○ Test spreadsheet logging
○ Configure automatic startup
○ Add enclosure-mounted speaker
○ Field test completed system
The final result will be a small standalone appliance:
Pick up ID → Scan → Get Result → Continue
No keyboard. No navigating through programs. No manually calculating birthdays.
Just a dedicated Raspberry Pi doing one job and doing it quickly.
Build started: 2026
Once Raspberry Pi OS is installed and the PDF417 scanner has been tested, the next step is preparing the Pi for the actual ID-scanner application.
Open Terminal on the Raspberry Pi.
Copy and paste:
sudo apt update && sudo apt full-upgrade -y
When that finishes, reboot:
sudo reboot
After the Pi restarts, open Terminal again and enter:
mkdir -p ~/id-scanner
cd ~/id-scanner
This folder will contain the scanner program, scan log, configuration, and eventually the sound files.
Raspberry Pi OS normally includes Python. Verify it with:
python3 --version
You should see something similar to:
Python 3.x.x
Enter:
nano ~/id-scanner/id_scanner.py
This opens the text editor where we'll paste the actual program.
Don't write anything in it yet.
The next section of this build contains the complete Python program that receives the PDF417 data, parses the driver's-license fields, calculates age and expiration, displays the result, records the scan in the spreadsheet, and has the hooks ready for our future sound system.
Now we will create the Python program that runs the scanner.
The program will eventually handle five jobs:
Receive the PDF417 data from the USB scanner
Decode the AAMVA driver's-license fields
Calculate the person's age and check the expiration date
Display a large, easy-to-read result on the touchscreen
Record the scan information in a spreadsheet
Audio functions will also be included so different sounds can be added later without rewriting the scanner program.
In Terminal, enter:
nano ~/id-scanner/id_scanner.py
A blank editor window should open.
Copy everything below into the editor:
Press:
CTRL + O
Press:
ENTER
Then press:
CTRL + X
That saves the file and returns you to Terminal.
Before making the scanner start automatically, run it manually.
Enter:
cd ~/id-scanner
python3 id_scanner.py
The touchscreen should switch to a full-screen display showing:
ID AGE VERIFICATION
READY
SCAN DRIVER LICENSE
Now scan the large PDF417 barcode on the back of a driver's license.
If everything is working, the screen should change immediately to one of the following:
21+ VERIFIED
UNDER 21
ID EXPIRED
or
READ ERROR
The calculated age should appear underneath the result.
During testing, press the ESC key to close the application.
Don't set up automatic startup yet.
First we want to test this with several real licenses. Different states and different generations of driver's licenses can format their AAMVA records somewhat differently.
Once we've confirmed the program correctly reads your Texas licenses, we'll inspect the spreadsheet it creates and make any parser adjustments before we turn the Pi into a dedicated kiosk.
The spreadsheet will be located at:
/home/YOUR-USERNAME/id-scanner/vinland_id_scans.csv
After successfully scanning several driver's licenses, verify that the Raspberry Pi is recording the information correctly.
The scanner automatically creates this file:
~/id-scanner/vinland_id_scans.csv
From Terminal, enter:
libreoffice --calc ~/id-scanner/vinland_id_scans.csv
The file should open as a spreadsheet.
Each scan should create one new row.
Verify that the columns contain the correct information:
Scan Date | Scan Time | Result | Age | License Number | First Name | Middle Name | Last Name | Date of Birth | Expiration Date | Issue Date | Sex | Eye Color | Height | Address | City | State | ZIP | Raw AAMVA Data
Compare several rows against the actual licenses used for testing.
Pay particular attention to:
Date of Birth
Make sure the date was decoded correctly.
Age
Make sure the calculated age is correct, especially for someone whose birthday has not occurred yet this year.
Expiration Date
Make sure an expired license produces ID EXPIRED.
Result
Make sure someone 21 or older produces 21+ VERIFIED, while someone under 21 produces UNDER 21.
The final column contains the original AAMVA information received from the scanner.
This is useful during development because if a license from another state does not parse correctly, the raw data allows the program to be updated to recognize that format.
Once testing is complete, whether the system should continue retaining raw ID data can be reconsidered based on the project's actual recordkeeping requirements and privacy policy.
Before configuring automatic startup, test several licenses.
The Pi should consistently:
Scan → Decode → Calculate → Display → Log → Reset → READY
Once that works reliably, the software itself is doing its job.
Once the scanner has been tested and is reliably reading and logging IDs, the next step is turning the Raspberry Pi into a dedicated appliance.
After this setup, the normal operation will be:
Power On → Raspberry Pi Boots → ID Scanner Opens Full Screen → READY
No Terminal window and no manually starting Python.
Open Terminal and enter:
mkdir -p ~/.config/autostart
Enter:
nano ~/.config/autostart/id-scanner.desktop
Paste this entire block into the file:
[Desktop Entry]
Type=Application
Name=ID Scanner
Comment=Driver License Age Verification Scanner
Exec=python3 /home/YOUR-USERNAME/id-scanner/id_scanner.py
Terminal=false
X-GNOME-Autostart-enabled=true
The line containing:
/home/YOUR-USERNAME/id-scanner/id_scanner.py
needs the actual Raspberry Pi username.
If you don't remember the username, open another Terminal and enter:
whoami
For example, if it returns:
clyde
then the Exec line should be:
Exec=python3 /home/clyde/id-scanner/id_scanner.py
Press:
CTRL + O
Then:
ENTER
Then:
CTRL + X
Reboot the Raspberry Pi:
sudo reboot
Don't touch anything after it restarts.
Raspberry Pi OS should load, and then the ID scanner should automatically open full screen.
The display should show:
ID AGE VERIFICATION
SCAN DRIVER LICENSE
Scan an ID and verify the entire sequence:
Scan → Result → Spreadsheet Log → 3-Second Reset → READY
A reboot isn't quite enough for the final test.
Shut the Raspberry Pi down properly:
sudo poweroff
Wait until the Pi has completely shut down.
Disconnect power for several seconds, reconnect it, and allow the system to boot normally.
The scanner application should launch without any intervention.
Once automatic startup is working, using the device should be extremely simple.
1. Power on the Raspberry Pi
2. Wait for READY
3. Scan IDs
That's it.
When an ID is scanned, the screen displays the result for approximately three seconds.
🟢 21+ VERIFIED
🔴 UNDER 21
🟠 ID EXPIRED
🔴 READ ERROR
The system then automatically returns to:
READY
and waits for the next ID.
Because the Raspberry Pi is a computer, do not routinely unplug it while it is running. Doing so can eventually corrupt the microSD card.
For now, shut it down through Raspberry Pi OS or Terminal:
sudo poweroff
Wait for shutdown to complete before disconnecting power.
Every completed scan is automatically recorded by the Raspberry Pi.
The scanner maintains a local CSV spreadsheet at:
~/id-scanner/vinland_id_scans.csv
CSV was chosen because it is simple, reliable, and can be opened by most spreadsheet programs, including:
Microsoft Excel • Google Sheets • LibreOffice Calc
The scanner does not need an internet connection to maintain this log.
Each scan creates a new row in the spreadsheet.
The log contains:
Scan Date
Scan Time
Result
Calculated Age
License Number
First Name
Middle Name
Last Name
Date of Birth
Expiration Date
Issue Date
Sex
Eye Color
Height
Address
City
State
ZIP
Raw AAMVA Data
Keeping the raw AAMVA record during development is especially useful because driver's licenses from different states and different generations of licenses may format their PDF417 data differently.
If the scanner encounters a license that does not parse correctly, the original barcode data can be examined without having to reproduce the problem immediately.
The Raspberry Pi's microSD card contains both the operating system and the scanner records.
Although the SD card could technically be removed to retrieve information, this is not the normal method of getting the spreadsheet.
Instead, the scanner includes a built-in:
function in the touchscreen Admin menu.
This allows scan records to be copied to a standard USB flash drive without removing the Raspberry Pi's microSD card.
Insert a standard USB flash drive into an available USB port on the Raspberry Pi.
The drive should use a commonly supported filesystem such as:
FAT32 or exFAT
This allows the same flash drive to be read easily by Windows, macOS, and Linux computers.
Press and hold:
ADMIN
for approximately three seconds.
The scanner searches for an attached USB storage device.
If a USB drive is found, the current scan log is copied to it.
The original spreadsheet remains on the Raspberry Pi.
Exporting does not erase or reset the scanner's records.
Rather than repeatedly overwriting the same file, the scanner creates a dated and time-stamped copy.
For example:
ID_Scan_Log_2026-09-13_2035.csv
A later export might create:
ID_Scan_Log_2026-09-20_1812.csv
This provides a simple archive of when records were retrieved.
After a successful export, the touchscreen displays:
followed by the name of the file that was created.
For example:
ID_Scan_Log_2026-09-13_2035.csv
The USB drive can then be safely removed and connected to another computer.
The exported CSV can be opened directly in Excel or imported into Google Sheets.
If EXPORT SCAN LOG is selected without a usable USB drive connected, the scanner displays:
No changes are made to the original scan log.
Insert a USB flash drive and try the export again.
Exporting the spreadsheet creates a copy.
The master log remains:
~/id-scanner/vinland_id_scans.csv
New scans continue to be added to that file.
This means an exported USB copy is a snapshot of the scanner records at the time the export was performed.
The microSD card should not normally need to be removed to retrieve scan records.
If it ever does need to be removed for maintenance, the Raspberry Pi must first be shut down using:
ADMIN → SHUT DOWN PI
Wait for the Raspberry Pi to completely shut down before removing the card.
If the card is inserted into a Windows computer and Windows asks to format an unfamiliar partition:
Raspberry Pi OS uses a Linux filesystem that Windows does not normally recognize.
Formatting the card could erase the scanner software, operating system, configuration, and stored scan records.
Driver's-license barcode information contains personally identifiable information.
Exported spreadsheets should therefore be treated as private records.
USB drives containing scan records should be kept secure, and exported files should only be stored where authorized users have access.
The USB export system is intentionally manual. Simply plugging in a flash drive does not copy anything. An operator must enter the Admin menu and select EXPORT SCAN LOG.
The complete record system now works like this:
SCAN ID → DECODE → VERIFY → DISPLAY RESULT → SAVE TO LOCAL LOG
When records are needed:
INSERT USB → HOLD ADMIN → EXPORT SCAN LOG → REMOVE USB → OPEN CSV ON COMPUTER
The Raspberry Pi's operating-system SD card stays safely inside the scanner.
The finished scanner is designed to operate as a standalone touchscreen appliance.
During normal use, staff should not need a keyboard, mouse, or Terminal window.
The normal screen remains intentionally simple:
ID AGE VERIFICATION
SCAN DRIVER LICENSE
A small ADMIN button is located in the upper-right corner.
The Admin menu contains functions that should not be activated accidentally during normal scanning.
For that reason, tapping the ADMIN button does nothing.
Instead:
Press and hold ADMIN for approximately three seconds.
The Admin menu will then open.
This helps prevent a customer or accidental touchscreen press from accessing system controls.
The touchscreen Admin menu contains six controls:
Opens the current local scan log:
~/id-scanner/vinland_id_scans.csv
This allows the records to be reviewed directly on the Raspberry Pi.
Copies the current scan spreadsheet to an attached USB flash drive.
The scanner automatically creates a dated and time-stamped filename such as:
ID_Scan_Log_2026-09-13_2035.csv
The original log remains on the Raspberry Pi and continues collecting new scans.
If no writable USB drive can be found, the screen displays:
USB DRIVE NOT FOUND
If the export succeeds, it displays:
EXPORT COMPLETE
along with the exported filename.
Restarts only the Python scanner application.
The Raspberry Pi itself remains running.
This provides a quick way to reload the scanner software without rebooting the entire computer.
After restarting, the application returns to:
Restarts the entire Raspberry Pi operating system.
Because rebooting interrupts scanner operation, the software asks for confirmation before proceeding:
REBOOT THE SCANNER?
YES, REBOOT
or
CANCEL
After Raspberry Pi OS restarts, the scanner application automatically launches again because of the autostart configuration created earlier.
Safely shuts down Raspberry Pi OS.
A confirmation screen prevents accidental shutdown:
SHUT DOWN THE SCANNER?
YES, SHUT DOWN
or
CANCEL
Once the Raspberry Pi has completely shut down, power can safely be disconnected.
This is the normal way the scanner should be powered off.
Closes the Admin menu without restarting anything.
The scanner immediately returns to:
SCAN DRIVER LICENSE
Once everything is configured, staff operation is intentionally simple:
POWER ON → WAIT FOR READY → SCAN ID → READ RESULT
The result remains on the screen for approximately three seconds before automatically returning to READY.
Administrative functions require:
HOLD ADMIN FOR 3 SECONDS → SELECT FUNCTION
And retrieving records becomes:
INSERT USB DRIVE → HOLD ADMIN → EXPORT SCAN LOG → CONFIRM EXPORT COMPLETE → REMOVE USB DRIVE
No command line should be required during normal day-to-day operation.
Before the scanner is placed into normal use, every major function should be tested.
The goal is to verify the complete system rather than simply confirming that the Python program starts.
The final test covers:
Barcode Reading → AAMVA Decoding → Age Calculation → Expiration Check → Display → Logging → Reset → USB Export → Administration → Startup and Shutdown
Power on the Raspberry Pi.
Do not open Terminal or manually start the scanner.
After Raspberry Pi OS finishes booting, the scanner should automatically appear full screen.
The display should show:
SCAN DRIVER LICENSE
PASS: Scanner launches automatically and reaches READY.
Scan a valid, unexpired driver's license belonging to someone age 21 or older.
Expected result:
The screen should display the person's calculated age.
The background should turn green.
After approximately three seconds, the scanner should automatically return to:
PASS: Correct age, correct result and automatic reset.
When an appropriate test ID is available, scan a valid driver's license belonging to someone under age 21.
Expected result:
The person's calculated age should appear underneath.
The background should turn red.
After approximately three seconds:
should return automatically.
PASS: Correct age and UNDER 21 result.
Scan an expired driver's license.
Expected result:
The calculated age should still appear.
The expiration warning takes priority over displaying 21+ VERIFIED.
The background should appear as the expiration-warning color.
After approximately three seconds, the scanner returns to READY.
PASS: Expired license is identified correctly.
Attempt a deliberately poor barcode read or test an unreadable barcode.
Expected result:
SCAN ID AGAIN
The scanner should not display a successful age verification when it cannot reliably retrieve the date of birth.
After approximately three seconds, it should return to READY.
PASS: Bad data fails safely instead of producing a false verification.
Scan several licenses one after another.
Verify that each complete barcode is processed separately.
The previous result should not contaminate the next scan.
PASS: Each ID produces one independent result.
Open the scan log through:
HOLD ADMIN → VIEW SCAN LOG
Verify that each test scan created its own row.
Check several records manually.
Compare the physical license against the recorded:
Name
Date of Birth
Expiration Date
License Number
Address
Issuing State
and other decoded fields.
Also verify:
Calculated Age
Verification Result
Scan Date
Scan Time
The raw AAMVA data should also be present for troubleshooting during development.
PASS: The information displayed and logged matches the test licenses.
Do not test only one driver's license.
Different states and different generations of licenses may encode or structure AAMVA data differently.
Whenever possible, test:
Several Texas licenses
and then licenses from:
Other states
The scanner should be considered fully tested only after it has successfully processed a reasonable variety of real licenses.
If a particular license produces READ ERROR, preserve its logged raw AAMVA data so the parser can be improved.
Quickly tap ADMIN.
Nothing should happen.
Now press and hold ADMIN for approximately three seconds.
The Admin menu should appear.
PASS: A normal accidental tap does not open Admin, while a deliberate hold does.
Do not connect a USB flash drive.
Select:
EXPORT SCAN LOG
Expected result:
The original spreadsheet should remain unchanged.
PASS: Scanner recognizes that no export device is available.
Insert a USB flash drive.
Wait several seconds for Raspberry Pi OS to recognize and mount it.
Select:
EXPORT SCAN LOG
A successful export should create a file similar to:
ID_Scan_Log_2026-09-13_203500.csv
If the scanner successfully unmounts the drive, the screen should display:
followed by:
Only remove the USB drive after receiving the safe-removal message.
Connect the USB drive to another computer and open the exported CSV.
Verify that the records match the original log.
PASS: Spreadsheet is copied intact and can be opened on another computer.
From the Admin menu select:
RESTART SCANNER
The Python application should close and immediately restart.
The screen should return to:
The Raspberry Pi itself should not reboot.
PASS: Application restarts independently.
Open Admin and select:
REBOOT PI
The confirmation screen should appear.
Select:
CANCEL
Nothing should happen.
Repeat the test and select:
YES, REBOOT
The Raspberry Pi should reboot.
After Raspberry Pi OS starts again, the scanner should automatically launch and return to READY.
PASS: Confirmation works, Pi reboots, and autostart restores the scanner.
Open Admin and select:
SHUT DOWN PI
Verify that the confirmation screen appears.
Select:
YES, SHUT DOWN
The Raspberry Pi should safely shut down.
Wait until shutdown is complete before disconnecting power.
PASS: Scanner can be safely powered down without a keyboard or Terminal.
Once all tests pass, normal operation is:
POWER ON → WAIT FOR READY
SCAN → READ RESULT → AUTOMATIC RESET → READY
INSERT USB → HOLD ADMIN → EXPORT SCAN LOG → SAFE TO REMOVE USB
HOLD ADMIN → SHUT DOWN PI → CONFIRM → WAIT → DISCONNECT POWER
The finished device is a standalone Raspberry Pi driver's-license age verification scanner built around a PDF417 barcode reader and touchscreen interface.
It can:
Read driver's-license PDF417 barcodes
Decode common AAMVA information
Calculate age automatically
Identify under-21 customers
Detect expired IDs
Display a clear result
Maintain a local scan spreadsheet
Export records to USB
Operate from a touchscreen
Start automatically
Restart itself
Reboot the Raspberry Pi
Safely shut itself down
The system is intentionally designed so that normal operation requires no keyboard, mouse, Terminal commands, or internet connection.
This device is an age-verification and barcode-reading aid, not an ID authentication system.
It reads information encoded in the PDF417 barcode and performs calculations using that information. It does not contact a state licensing agency, confirm that an ID is currently valid in a government database, detect every counterfeit or alteration, or replace the judgment and legal responsibilities of the person checking identification.
Build started: 2026
Status: Ready for hardware installation and field testing.