WAIT! Before proceeding—if you don't know how to set up CircuitPython, check out: What is RPI PICO W and how to SETUP it?
Index
- Why Rubber Ducky, PICO Ducky, etc. Don't Work on RPI PICO W
- Investigation and Explanation
- How to Fix It?
- What is RPI PICO W and How to SETUP it?
Why Rubber Ducky, PICO Ducky, etc. Don't Work on RPI PICO W?
The answer is simple: Everyone tries to add a fail-safe or trigger to enable/disable storage in boot.py.
But according to CircuitPython documentation, the storage state can only be triggered once.
boot.py– This runs only once before the main code executes.
Investigation and Explanation
Here, I’m using boot.py to manipulate the USB protocol and declare the device as a USB HID to the OS.
boot.py – USB HID Init
import usb_hid, storage
storage.disable_usb_drive()
usb_hid.enable(usb_hid.Devices.KEYBOARD)
code.py – The main keystroke or ducky script
import time
import usb_hid
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keycode import Keycode
from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS
# Setup keyboard
kyb = Keyboard(usb_hid.devices)
layout = KeyboardLayoutUS(kyb)
# Open Notepad (Windows: Win + R → type 'notepad' → Enter)
kyb.press(Keycode.WINDOWS)
kyb.send(Keycode.R)
kyb.release_all()
time.sleep(0.5)
layout.write("notepad")
kyb.send(Keycode.ENTER)
time.sleep(1)
for i in range(10):
layout.write("Hello World From Pico HID\n")
OLAA! Your own ducky script.
WAIT WAIT!
Like everyone else, you may think:
"I can just add a trigger to switch between HID and USB Mass Storage!"
But here's the twist, my friend!
boot.pydoesn't wait (or delay) for GPIO-related tasks.
Even if you add a delay, it skips it.
If anything goes wrong inboot.py, it automatically falls back to USB Mass Storage mode by default.
How to Fix It?
There are two ways to fix this:
Internal Communication (RECOMMENDED)
Here you have more reliable options to communicate between boot.py and code.py.
I recommend using microcontroller.nvm which helps toggle state between the two scripts.
microcontroller.nvm– Persistent Non-Volatile Memory.
Example:
boot.py
import microcontroller
microcontroller.nvm[0] = 1 # Use 1 or 0 depending on mode
code.py
import microcontroller
if microcontroller.nvm[0] == 1:
print("USB drive was enabled")
else:
print("USB drive was disabled")
External Communication
You can also use a simple state.txt file to read/write the current state.
This allows both scripts to enable or disable USB Mass Storage based on that value.
Example:
Get state from file
def getState():
with open("state", "r") as f:
return f.read().replace("\n", "")
Set state to file
def setState(bool_val):
with open("state", "w") as f:
f.write(str(bool_val))
What is RPI PICO W and How to SETUP it?
Hello Beginners!
- RPI – Raspberry Pi
There are two ways to use Python on your RPI PICO W:
- CircuitPython – Easy, stable, and beginner-friendly.
- MicroPython – Gives full control. A bit tricky at first but easy once understood.
In simple terms:
- CircuitPython is like Ubuntu for RPI-based microcontrollers.
- MicroPython is like Arch Linux for RPI-based microcontrollers.
🚀 Speedrun: Setup Process
- Download the CircuitPython
.uf2file from the CircuitPython website. - Download
nuke.uf2from CircuitPython or the Raspberry Pi website. - Download the latest CircuitPython RPI PICO W bundle and unzip it.
- While plugging in your PICO to your PC, hold the
BOOTSELbutton untilRPI-RP2shows up in File Explorer. - Copy
nuke.uf2to theRPI-RP2drive. - WAIT 2 seconds. It will eject and reconnect automatically.
- Now, copy the CircuitPython
.uf2file toRPI-RP2. -
WAIT again—this time it will show as
CIRCUITPY. - From the CircuitPython bundle, find the
usb_hidfolder and copy it to your PICO. - Copy your
code.pyandboot.pyinto the CIRCUITPY drive. - OLAA! DONE!
NOTE: I'm still exploring better solutions to improve this further.
If you have any suggestions or ideas, please comment down below!
Author: Junaid
Sources:
Top comments (0)