I thought I’d dig out my pico W and have a go at doing this. I found a micro-pyrthon-osc library under development and the client side of this works with Sonic PI.
The program I used was this
#Pico W OSC client using uosc.client library
#download zip file of library from https://github.com/SpotlightKid/micropython-osc
#install using Thonny
#best to comment ALL print commands once you hacve things working to run it independently as main.py
import network
from machine import Pin, ADC
import usocket as socket
from time import sleep
import secrets
from uosc.client import Client
import gc #garbage collection
adcpin = 4
sensor = machine.ADC(adcpin)
#set up onboard led to turn on when connected
led = machine.Pin('LED', machine.Pin.OUT)
led.on()
sleep(.3)
led.off()
sleep(.3)
# Wi-Fi configuration
ssid = secrets.SSID
password = secrets.PASSWORD
# Static IP address configuration (if required)
ip_address = secrets.PICOIP
subnet_mask = "255.255.255.0"
gateway = "192.168.1.1" # Replace with your gateway IP
# OSC settings
sp_host = secrets.SPIP # Replace with your Sonic Pi IP address
sp_port = secrets.SPPORT # Replace with required OSC port (4560 for Sonic PI)
sp_dest = socket.getaddrinfo(sp_host, sp_port)[0][-1]
#print(sp_dest) #turn off all prints for standalone operation
# GPIO pin configuration
gpio_pin = machine.Pin(7, machine.Pin.IN, machine.Pin.PULL_UP) #used to gtrigger OSC call
# Connect to Wi-Fi
def connect_to_wifi(ssid, password):
wlan = network.WLAN(network.STA_IF)
if not wlan.isconnected():
print("Connecting to WiFi...")
wlan.active(True)
led.off()
#uncomment next line for static address. Otherwise uses dhcp
#wlan.ifconfig((ip_address, subnet_mask, gateway, "8.8.8.8")) # Set static IP
wlan.connect(ssid, password)
while not wlan.isconnected():
#print(".",end=".")
sleep(1) # Add a delay of 1 seconds
#print("Connected to WiFi")
#print("IP Address:", wlan.ifconfig()[0])
# LED on for wifi connected
led.on()
def ReadTemperature():
adc_value = sensor.read_u16()
volt = (3.3/65535) * adc_value
temperature = 27 - (volt - 0.706)/0.001721
return round(temperature, 1)
def ReadPot(): #originally I used a potentiometer rather than the LDR to vary the input signal
pot = ADC(26) #gp26 physical pin 31
pot_value = pot.read_u16()
return round(pot_value*120/65535,1) #range 0-220
def sm(state): #send OSC message
osc = Client(sp_dest)
osc.send('/pico/pot',state )
gc.collect() #necessary or runs out of memory
# Main program loop
connect_to_wifi(ssid, password)
while True:
p=ReadPot()
sm(p)
sleep(0.1)
It has an associated secrets.py file which is this:
SSID = "yourSSIDhere"
PASSWORD = 'yoiurPasswordhere'
SPIP = 'ipo address of Sonic Pi computer'
PICOIP = 'fixed IP for Pico'
SPPORT = 4560
The library is by SpotLightKid and is on github here
Download it from the Code button as a zip file. You can then install it using Thonny to your pico W using Tools menu → Manage Packages…-> Install from local file click here
I made a small demo video showing the program in action. I set it up to measure the input to ADC0 (actual pin 31, or GP26) Initially I used a 10K potentiometer connected to ground and 3v3 with the “slider” connected to GP26, but in the video I changed this for an Light Dependent Resistor I found with a resistor in series, and measured the voltage at the junction. I scaled the readings in range 0-120 which covered more or less the midi audio range.
One or two “gotcha” I found out. I found it necessary to include a garbage collection call after the OSC sm function was called, or the program stopped with a memory complaint. Goggling led to the solution which seems to work OK.
Secondly, I put in various print statements as the program was being developed. In order to run it automatically without being connected to Thonny, it is a good idea to comment all of these out so that the pico doesn’t try and send serial data along the usb cable and hang because there isn’t a suitable serial receiver active.
The program has the option to use a static IP address for the pico, or you can just use a dhcp allocated address. It’s just a matter of including an extra line or otherwise.
I haven’t tried the server side of things, so you can only send from the pico to SP at the moment.
EDIT ADDITONAL NOTES
1
the program I used on Sonic Pi to receive the OSC call and produce a sound related to the data is shwon below. A long 100 second tone is started. A referenced to the tone is stored in :y
This is then used to control the pitch value of the tone in the live loop, with changes smoothed out by the note_slide:
parameter
use_synth :sine
y=play 50,sustain: 1000,amp: 0.5
set :y,y
live_loop :temp do
use_real_time
t=sync "/osc*/pico/pot"
puts t[0].to_i
control get(:y), note: t[0].to_i,note_slide: 0.1
end
2 The pico program contains a function def ReadTemperature():
This is not actually used. It reads the temperature of the internal sensor in the pico processor chip. you can if you wish adjust the program to send the temperature reading instead of the adc reading in the OSC call.
- You can change the OSC address from
/pico/pot
to anything you like: eg /pico/temp
or /pico/lightlevel
Just make sure you use the appropriate address on the Sonic Pi side. Note this has /osc*
prepended to the address.