Practice Lab Guide

Project 2: Multi-Board Hardware Capability Comparison

Implement an LED-controller and button-reader program in C++ and Python across multiple virtual and hardware systems.
Domain
Cross-Platform Embedded
Difficulty
⭐⭐☆☆☆ (Moderate)
Course Module
Hardware Platforms
Deliverables
Source Code Suite, Capability Matrix
1. Multi-Platform Hardware Pinout & OS Comparison

Different IoT deployments call for different hardware platforms. We categorize microcontroller architectures into two main fields: bare-metal systems (such as Arduino or ESP32) and full operating system computers (such as Raspberry Pi). The schematic below compares the hardware specifications, CPU properties, operating systems, and pin assignments between a standard ESP32 module and a Raspberry Pi. It demonstrates how high-level operating system layers affect GPIO pin interactions.

ESP32 (Bare-Metal Microcontroller) CPU: Xtensa Dual-Core 32-bit (240MHz) Operating OS: None (FreeRTOS or Raw C++ loops) GPIO Voltage: 3.3V Max (Non 5V-Tolerant) Pin Routing: GPIO 2 (Onboard LED), GPIO 4 (Input) RASPBERRY PI / VM (Single-Board PC) CPU: ARM Cortex-A72 Quad-Core (1.5GHz) Operating OS: Debian Linux / Raspberry Pi OS GPIO Voltage: 3.3V Max (Non 5V-Tolerant) Pin Routing: BCM 18 (LED Output), BCM 23 (Input) Equivalent Logic
2. Part 1: Step-by-Step Individual Commands & GUI Steps

Follow these detailed steps to set up your virtual Python environment inside the VirtualBox Linux machine, draft your code, compile the ESP32 files, and run the Python simulator suite.

STEP 1

Launch Terminal and Create Project Directory

Boot your VirtualBox Ubuntu machine. Open the Ubuntu terminal and structure a clean directory workspace for the board comparison project.

ubuntu@iot-vm:~$ mkdir -p ~/workspace/board_comparison
We run `mkdir -p` to verify and generate a clean workspace directory tree at the path `~/workspace/board_comparison` without throwing errors if the parent directories already exist.
STEP 2

Navigate to the Project Folder

Move your current command shell context into the newly generated folder to manage output files locally.

ubuntu@iot-vm:~$ cd ~/workspace/board_comparison
We execute `cd` to change the working directory path of our terminal process, ensuring all subsequent scripts and source code files are created inside the isolated comparison folder.
STEP 3

Install Python Compiler and Virtual Environment Tools

Ensure that the latest Python development packages and pip installation systems are deployed in the OS packages system.

ubuntu@iot-vm:~/workspace/board_comparison$ sudo apt update && sudo apt install -y python3 python3-pip python3-venv
We run `sudo apt update` to refresh the package database list, followed by `apt install` to load Python 3, pip library manager, and virtual environment modules on our VM.
STEP 4

Generate Isolated Python Virtual Environment

Create a sandbox folder containing Python libraries to prevent script execution packages from conflicting with system libraries.

ubuntu@iot-vm:~/workspace/board_comparison$ python3 -m venv env
We run `python3 -m venv env` to create an isolated environment directory named `env` containing a copy of the Python interpreter, protecting our VM's global configuration.
STEP 5

Activate the Virtual Environment

Instruct the current shell to look for Python execution files inside the local project folder path instead of standard root directories.

ubuntu@iot-vm:~/workspace/board_comparison$ source env/bin/activate
We run the `source` command against the activation shell script, modifying terminal PATH variables so that running python packages uses the local virtual environment folders.
STEP 6

Open Text Editor for Python Script Configuration

Invoke the graphical editor "gedit" (or terminal editor "nano") to draft the cross-platform simulated input-output code.

ubuntu@iot-vm:~/workspace/board_comparison$ gedit comparison.py &
We invoke `gedit` alongside the `&` symbol to open the graphical text editor in a background thread, leaving our terminal terminal prompt active for running commands.
STEP 7

Execute the Python Board Simulation

Execute the Python program. Since we are in VirtualBox, the code will load a mock shell system enabling you to trigger virtual button clicks on your keyboard.

(env) ubuntu@iot-vm:~/workspace/board_comparison$ python3 comparison.py
We execute `python3` to run the comparison file, launching the loop that polls console keypresses and outputs simulated LED states.
3. Multi-Language Program Logic Execution Pipeline

The core logic of reading a physical button pin state and outputting an LED signal follows a similar software flow across both C++ (microcontroller) and Python (single-board computer). Below is the logical comparison showing the parallel pipelines of execution.

C++ Core Loop (ESP32 / Arduino) 1. pinMode(INPUT_PIN, INPUT_PULLUP); 2. int state = digitalRead(INPUT_PIN); 3. if (state == LOW) { digitalWrite(LED, HIGH); } 4. else { digitalWrite(LED, LOW); } Python Core Loop (Raspberry Pi / Sim) 1. GPIO.setup(PIN, GPIO.IN, pull_up_down=UP) 2. state = GPIO.input(PIN) 3. if state == False: GPIO.output(LED, True) 4. else: GPIO.output(LED, False)
4. Part 2: Source Code Suite & Line-by-Line Breakdown

Below are the two complete, production-ready code files. The first is written in C++ for the Arduino/ESP32 platforms, and the second is written in Python with a self-contained GUI mock layer that allows local testing within your VirtualBox environment.

Asset 1: ESP32/Arduino C++ Source Code (`blink_button.ino`)

Line-by-Line Code Breakdown

// Practice Project 2: ESP32/Arduino Input/Output C++ Code const int LED_PIN = 2; // Onboard LED GPIO Pin const int BUTTON_PIN = 4; // Button input pin with pull-up configuration void setup() { // Configure onboard LED as output pinMode(LED_PIN, OUTPUT); // Configure button pin with internal pull-up resistor pinMode(BUTTON_PIN, INPUT_PULLUP); } void loop() { // Read state of the input pin int btnState = digitalRead(BUTTON_PIN); // Active-LOW configuration: button connects to GND when pressed if (btnState == LOW) { digitalWrite(LED_PIN, HIGH); // Turn on LED } else { digitalWrite(LED_PIN, LOW); // Turn off LED } // Small delay to stabilize readings delay(50); }

Asset 2: Python / Linux Simulation Script (`comparison.py`)

Line-by-Line Code Breakdown

# Practice Project 2: Python/Linux Input/Output Simulation Script import sys import time import select import tty import termios class MockGPIO: "Mock GPIO simulator for VirtualBox Ubuntu environments" BCM = "BCM" IN = "INPUT" OUT = "OUTPUT" PUD_UP = "PULL_UP" def __init__(self): self._button_pressed = False self._led_state = False def setmode(self, mode): pass def setup(self, pin, direction, pull_up_down=None): pass def input(self, pin): # Returns False if pressed (simulating active-LOW configuration) return not self._button_pressed def output(self, pin, state): if self._led_state != state: self._led_state = state print(f"\r[LED STATE] Onboard LED on pin {pin} is now: {'ON' if state else 'OFF'}") def is_key_pressed(): return select.select([sys.stdin], [], [], 0.05)[0] != [] def main(): GPIO = MockGPIO() GPIO.setmode(GPIO.BCM) LED_PIN = 18 BUTTON_PIN = 23 GPIO.setup(LED_PIN, GPIO.OUT) GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) print("==================================================") print(" Python GPIO Input/Output Simulator Running ") print(" Simulating on VirtualBox Ubuntu Guest OS ") print("==================================================") print("Instructions:") print(" - Press and hold 'p' then hit [Enter] to press button.") print(" - Press any other key to release button.") print(" - Press Ctrl+C to stop simulation.") print("--------------------------------------------------") try: while True: if is_key_pressed(): key = sys.stdin.readline().strip() if key == 'p': GPIO._button_pressed = True else: GPIO._button_pressed = False # Read simulated digital state btnState = GPIO.input(BUTTON_PIN) # If button is pressed (state is False due to active-low) if btnState == False: GPIO.output(LED_PIN, True) else: GPIO.output(LED_PIN, False) time.sleep(0.1) except KeyboardInterrupt: print("\nSimulation stopped by user.") if __name__ == "__main__": main()
5. Deliverables Summary

Created Artifacts

  • Compiled C++ Sketch file: blink_button.ino
  • Executable simulated Python script: comparison.py
  • Completed Hardware Platform Selection Analysis Matrix (PDF/Markdown report).

Verification Proof

  • A video snippet showing the ESP32 built-in LED turning ON when you press the physical button.
  • A screenshot of the Ubuntu terminal running the Python simulation program, showing the LED state logs toggle when you enter 'p'.
6. Closing Explanation: Why We Did This & What It Accomplishes

Architectural Intent & Operational Impact

Why We Did This

What This Accomplishes