skills/smithery.ai/badger-hardware

badger-hardware

SKILL.md

Badger 2350 Hardware Integration

Interface with GPIO pins, sensors, and external hardware on the Badger 2350 badge using I2C, SPI, and digital I/O.

GPIO Basics

Pin Configuration

from machine import Pin

# Configure pin as output (LED, relay, etc.)
led = Pin(25, Pin.OUT)
led.value(1)  # Turn on (HIGH)
led.value(0)  # Turn off (LOW)
led.toggle()  # Toggle state

# Configure pin as input (button, switch, etc.)
button = Pin(15, Pin.IN, Pin.PULL_UP)
if button.value() == 0:  # Button pressed (pulled to ground)
    print("Button pressed!")

# Configure pin as input with pull-down
sensor = Pin(16, Pin.IN, Pin.PULL_DOWN)

PWM (Pulse Width Modulation)

from machine import Pin, PWM

# Control LED brightness or servo motor
pwm = PWM(Pin(25))
pwm.freq(1000)  # Set frequency to 1kHz

# Set duty cycle (0-65535, where 65535 is 100%)
pwm.duty_u16(32768)  # 50% brightness
pwm.duty_u16(16384)  # 25% brightness
pwm.duty_u16(65535)  # 100% brightness

# Cleanup
pwm.deinit()

Interrupts

from machine import Pin

button = Pin(15, Pin.IN, Pin.PULL_UP)

def button_callback(pin):
    print(f"Button pressed! Pin: {pin}")

# Trigger on falling edge (button press)
button.irq(trigger=Pin.IRQ_FALLING, handler=button_callback)

# Trigger on rising edge (button release)
button.irq(trigger=Pin.IRQ_RISING, handler=button_callback)

# Trigger on both edges
button.irq(trigger=Pin.IRQ_RISING | Pin.IRQ_FALLING, handler=button_callback)

I2C Communication

I2C Setup

from machine import I2C, Pin

# Initialize I2C (QWIIC connector uses specific pins)
i2c = I2C(0, scl=Pin(5), sda=Pin(4), freq=400000)

# Scan for connected devices
devices = i2c.scan()
print(f"Found {len(devices)} I2C devices:")
for device in devices:
    print(f"  Address: 0x{device:02x}")

Reading from I2C Device

# Read data from I2C device
address = 0x48  # Example: Temperature sensor
data = i2c.readfrom(address, 2)  # Read 2 bytes
print(f"Raw data: {data}")

# Read from specific register
register = 0x00
i2c.writeto(address, bytes([register]))  # Select register
data = i2c.readfrom(address, 2)  # Read data

Writing to I2C Device

# Write single byte
address = 0x48
data = bytes([0x01, 0xA0])
i2c.writeto(address, data)

# Write to specific register
register = 0x01
value = 0xFF
i2c.writeto(address, bytes([register, value]))

Common I2C Sensors

BME280 (Temperature, Humidity, Pressure)

from machine import I2C, Pin
import time

class BME280:
    def __init__(self, i2c, address=0x76):
        self.i2c = i2c
        self.address = address

    def read_temp(self):
        # Read temperature register
        data = self.i2c.readfrom_mem(self.address, 0xFA, 3)
        temp_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4)
        # Apply calibration (simplified)
        temp_c = temp_raw / 100.0
        return temp_c

    def read_humidity(self):
        # Read humidity register
        data = self.i2c.readfrom_mem(self.address, 0xFD, 2)
        hum_raw = (data[0] << 8) | data[1]
        humidity = hum_raw / 1024.0
        return humidity

# Usage
i2c = I2C(0, scl=Pin(5), sda=Pin(4), freq=400000)
sensor = BME280(i2c)

temp = sensor.read_temp()
humidity = sensor.read_humidity()
print(f"Temp: {temp:.1f}°C, Humidity: {humidity:.1f}%")

APDS9960 (Gesture, Proximity, Color Sensor)

class APDS9960:
    def __init__(self, i2c, address=0x39):
        self.i2c = i2c
        self.address = address
        self._init_sensor()

    def _init_sensor(self):
        # Enable device
        self.i2c.writeto_mem(self.address, 0x80, bytes([0x01]))
        # Enable gesture mode
        self.i2c.writeto_mem(self.address, 0x93, bytes([0x01]))

    def read_gesture(self):
        # Read gesture FIFO
        fifo_level = self.i2c.readfrom_mem(self.address, 0xAE, 1)[0]
        if fifo_level > 0:
            data = self.i2c.readfrom_mem(self.address, 0xFC, 4)
            # Process gesture data
            return self._detect_gesture(data)
        return None

    def _detect_gesture(self, data):
        # Simplified gesture detection
        if data[0] > data[2]:
            return "UP"
        elif data[0] < data[2]:
            return "DOWN"
        elif data[1] > data[3]:
            return "LEFT"
        else:
            return "RIGHT"

# Usage
i2c = I2C(0, scl=Pin(5), sda=Pin(4), freq=400000)
gesture_sensor = APDS9960(i2c)

gesture = gesture_sensor.read_gesture()
if gesture:
    print(f"Gesture detected: {gesture}")

VL53L0X (Time-of-Flight Distance Sensor)

class VL53L0X:
    def __init__(self, i2c, address=0x29):
        self.i2c = i2c
        self.address = address

    def read_distance(self):
        # Start measurement
        self.i2c.writeto_mem(self.address, 0x00, bytes([0x01]))

        # Wait for measurement
        time.sleep(0.05)

        # Read distance (mm)
        data = self.i2c.readfrom_mem(self.address, 0x14, 2)
        distance = (data[0] << 8) | data[1]
        return distance

# Usage
i2c = I2C(0, scl=Pin(5), sda=Pin(4), freq=400000)
tof = VL53L0X(i2c)

distance = tof.read_distance()
print(f"Distance: {distance}mm")

SPI Communication

SPI Setup

from machine import SPI, Pin

# Initialize SPI
spi = SPI(0, baudrate=1000000, polarity=0, phase=0,
          sck=Pin(2), mosi=Pin(3), miso=Pin(4))

# Chip select pin
cs = Pin(5, Pin.OUT)
cs.value(1)  # Deselect initially

# Read/write data
cs.value(0)  # Select device
spi.write(bytes([0x01, 0x02, 0x03]))  # Write data
data = spi.read(3)  # Read 3 bytes
cs.value(1)  # Deselect device

print(f"Received: {data}")

SD Card Reader (SPI)

from machine import SPI, Pin
import sdcard
import os

# Initialize SPI and SD card
spi = SPI(0, baudrate=1000000, sck=Pin(2), mosi=Pin(3), miso=Pin(4))
cs = Pin(5, Pin.OUT)

sd = sdcard.SDCard(spi, cs)

# Mount SD card
os.mount(sd, '/sd')

# Write file
with open('/sd/data.txt', 'w') as f:
    f.write('Hello from Badger!')

# Read file
with open('/sd/data.txt', 'r') as f:
    print(f.read())

# Unmount
os.umount('/sd')

Analog Input (ADC)

from machine import ADC, Pin

# Initialize ADC on GPIO pin
adc = ADC(Pin(26))

# Read raw value (0-65535 for 16-bit ADC)
raw_value = adc.read_u16()
print(f"Raw ADC: {raw_value}")

# Convert to voltage (assuming 3.3V reference)
voltage = (raw_value / 65535) * 3.3
print(f"Voltage: {voltage:.2f}V")

# Example: Read potentiometer
while True:
    value = adc.read_u16()
    percentage = (value / 65535) * 100
    print(f"Pot: {percentage:.1f}%")
    time.sleep(0.1)

NeoPixel (WS2812B) LEDs

from machine import Pin
import neopixel
import time

# Initialize NeoPixel strip (8 LEDs on pin 25)
num_leds = 8
np = neopixel.NeoPixel(Pin(25), num_leds)

# Set individual LED color (R, G, B)
np[0] = (255, 0, 0)    # Red
np[1] = (0, 255, 0)    # Green
np[2] = (0, 0, 255)    # Blue
np[3] = (255, 255, 0)  # Yellow
np.write()  # Update LEDs

# Rainbow effect
def rainbow_cycle(wait):
    for j in range(255):
        for i in range(num_leds):
            pixel_index = (i * 256 // num_leds) + j
            np[i] = wheel(pixel_index & 255)
        np.write()
        time.sleep(wait)

def wheel(pos):
    """Generate rainbow colors across 0-255 positions"""
    if pos < 85:
        return (pos * 3, 255 - pos * 3, 0)
    elif pos < 170:
        pos -= 85
        return (255 - pos * 3, 0, pos * 3)
    else:
        pos -= 170
        return (0, pos * 3, 255 - pos * 3)

rainbow_cycle(0.001)

Servo Motor Control

from machine import Pin, PWM
import time

class Servo:
    def __init__(self, pin):
        self.pwm = PWM(Pin(pin))
        self.pwm.freq(50)  # 50Hz for servo

    def angle(self, degrees):
        """Set servo angle (0-180 degrees)"""
        # Convert angle to duty cycle
        # 0° = 1ms (3.2% duty)
        # 90° = 1.5ms (7.5% duty)
        # 180° = 2ms (10% duty)
        min_duty = 1638   # 2.5% of 65535
        max_duty = 8192   # 12.5% of 65535
        duty = int(min_duty + (degrees / 180) * (max_duty - min_duty))
        self.pwm.duty_u16(duty)

    def deinit(self):
        self.pwm.deinit()

# Usage
servo = Servo(25)

# Sweep servo
for angle in range(0, 181, 10):
    servo.angle(angle)
    time.sleep(0.1)

servo.deinit()

Relay Control

from machine import Pin
import time

class Relay:
    def __init__(self, pin):
        self.pin = Pin(pin, Pin.OUT)
        self.off()

    def on(self):
        self.pin.value(1)

    def off(self):
        self.pin.value(0)

    def toggle(self):
        self.pin.toggle()

# Usage
relay = Relay(25)

relay.on()
time.sleep(2)
relay.off()

# Pulse relay
for i in range(5):
    relay.toggle()
    time.sleep(0.5)

Integration with Badge Display

Display Sensor Data

import badger2040
from machine import I2C, Pin
import time

badge = badger2040.Badger2040()
i2c = I2C(0, scl=Pin(5), sda=Pin(4), freq=400000)

def display_sensor_data():
    # Read sensor (example)
    temp = read_temperature()  # Your sensor function
    humidity = read_humidity()

    badge.set_pen(15)
    badge.clear()
    badge.set_pen(0)

    badge.text("Sensor Monitor", 10, 10, scale=2)
    badge.text(f"Temp: {temp:.1f}C", 10, 40, scale=2)
    badge.text(f"Humidity: {humidity:.1f}%", 10, 70, scale=2)

    badge.update()

while True:
    display_sensor_data()
    time.sleep(1)

Interactive Hardware Control

import badger2040
from machine import Pin
import time

badge = badger2040.Badger2040()
led = Pin(25, Pin.OUT)
led_state = False

def draw_ui():
    badge.set_pen(15)
    badge.clear()
    badge.set_pen(0)

    badge.text("LED Control", 10, 10, scale=2)

    status = "ON" if led_state else "OFF"
    badge.text(f"Status: {status}", 10, 50, scale=2)

    badge.text("A: Toggle", 10, 100, scale=1)

    badge.update()

while True:
    draw_ui()

    if badge.pressed(badger2040.BUTTON_A):
        led_state = not led_state
        led.value(1 if led_state else 0)
        time.sleep(0.2)  # Debounce

Power Management for Hardware

from machine import Pin
import machine

# Power control for external hardware
power_pin = Pin(23, Pin.OUT)

def power_on():
    power_pin.value(1)

def power_off():
    power_pin.value(0)

# Use with sleep modes
power_on()
# ... do work with sensor ...
power_off()
machine.lightsleep(5000)  # Sleep 5 seconds

Troubleshooting

I2C device not detected: Check wiring, verify device address, ensure pull-up resistors are present

GPIO not working: Verify pin is not used by internal badge functions, check if pin is input/output capable

SPI communication fails: Check clock polarity and phase, verify baudrate is within device specs

PWM not smooth: Increase PWM frequency, ensure duty cycle calculations are correct

Sensor readings unstable: Add delays between readings, use averaging, check power supply stability

Hardware Safety

  • Never exceed 3.3V on GPIO pins
  • Use level shifters for 5V devices
  • Add current-limiting resistors for LEDs
  • Use flyback diodes with motors and relays
  • Keep I2C wires short (< 20cm) or use bus extenders
  • Use proper power supply for high-current devices

Pinout Reference

Common Badger 2350 pins available for external hardware:

  • GPIO 0-22: General purpose I/O
  • GPIO 26-28: ADC capable (analog input)
  • I2C QWIIC: SCL (Pin 5), SDA (Pin 4)
  • SPI: SCK, MOSI, MISO (check documentation)

Refer to official Badger 2350 pinout diagram for complete details.

Weekly Installs
1
First Seen
8 days ago
Installed on
qwen-code1