Read Digital IO Pins on RaspPi via Python
Date | 2016-02-25 03:11 |
From | Emmett Palaima |
Subject | Read Digital IO Pins on RaspPi via Python |
Hi, I am currently working on an effects pedal/live audio processing unit that uses csound on the raspberry pi. I successfully have audio running through it and being processed in real time, now I am working on getting realtime controls like pots and switches to control the parameters in my csd files. I know one way to do this is midi, but I was also looking at doing it through the python opcodes, reading directly from the raspi's digital io pins.
Csound mailing list
Csound@listserv.heanet.ie
https://listserv.heanet.ie/cgi-bin/wa?A0=CSOUND
Send bugs reports to
https://github.com/csound/csound/issues
Discussions of bugs and features can be posted here
I am using the following method for reading off of the pins, which approximates analog in with a digital pin, modified for my project: When I run my file I get many of these messages: WARNING: Buffer underrun in real-time audio input |
Date | 2016-02-25 03:15 |
From | Emmett Palaima |
Subject | Re: Read Digital IO Pins on RaspPi via Python |
Sorry Last message sent before I was finished typing: Hi, I am currently working on an effects pedal/live audio processing unit that uses csound on the raspberry pi. I successfully have audio running through it and being processed in real time, now I am working on getting realtime controls like pots and switches to control the parameters in my csd files. I know one way to do this is midi, but I was also looking at doing it through the python opcodes, reading directly from the raspi's digital io pins. I am using the following method for reading off of the pins, which approximates analog in with a digital pin, modified for my project: When I run my file I get many of these messages: WARNING: Buffer underrun in real-time audio input I have tried many different k rates, changing my k rate does not seem to effect how often the python program runs as it executes its at the same speed regardless of what my k rate is set to. Here is my code, any help is much appreciated: <CsoundSynthesizer> <CsOptions> -odac:hw:1,0 -iadc:hw:1,0 -b 2048 -B 2048 </CsOptions> <CsInstruments> sr = 48000 ksmps = 1 nchnls = 2 0dbfs = 1.0 gkvol init 0 turnon 1 turnon 2 pyinit instr 1 pyrun{{ import RPi.GPIO as GPIO import time out = 0.0 GPIO.setmode(GPIO.BCM) def RCtime(PiPin): measurement = 0.0 GPIO.setup(PiPin, GPIO.OUT) GPIO.output(PiPin, GPIO.LOW) time.sleep(0.1) GPIO.setup(PiPin, GPIO.IN) while (GPIO.input(PiPin) ==GPIO.LOW): measurement += 1 return measurement print 'pin' print RCtime(4) out = RCtime(4) print 'ran' print 'out' print out }} kout pyeval "out" printk 1, kout gkvol = kout printk 1, gkvol endin instr 2
kgain invalue "Gain" ain, ain2 ins outs ain, ain2*(gkvol/1000) endin
</CsInstruments> <CsScore> ;i 1 0 10000 ;i 2 0 10000
</CsScore> </CsoundSynthesizer> On Wed, Feb 24, 2016 at 10:11 PM, Emmett Palaima <epalaima@berklee.edu> wrote:
|
Date | 2016-02-25 05:11 |
From | kelly hirai |
Subject | Re: Read Digital IO Pins on RaspPi via Python |
i suspect this loop is spin locking. its a guess. while (GPIO.input(PiPin) == GPIO.LOW): measurement += 1 how high is measurement getting? could you get away with put some tiny sleeps in there? kelly On 02/24/2016 10:15 PM, Emmett Palaima
wrote:
|
Date | 2016-02-25 05:25 |
From | kelly hirai |
Subject | Re: Read Digital IO Pins on RaspPi via Python |
i suspect this loop is spin locking. its a guess. while (GPIO.input(PiPin) == GPIO.LOW): measurement += 1 how high is measurement getting? could you get away with put some tiny sleeps in there? kelly On 02/24/2016 10:15 PM, Emmett Palaima
wrote:
|
Date | 2016-02-25 06:05 |
From | kelly hirai |
Subject | Re: Read Digital IO Pins on RaspPi via Python |
sorry, i didn't notice you have your python in the orc. i don't think its recommended you sleep in embeded python sections at all. you may have to move all your timing code into the csound part. that way it can get some things done in between gpio reads. i think you also want to break your initialization of the gpio into a part of the code that gets run only once and not every k period. kelly On 02/24/2016 10:15 PM, Emmett Palaima
wrote:
|
Date | 2016-02-25 07:21 |
From | Emmett Palaima |
Subject | Re: Read Digital IO Pins on RaspPi via Python |
That makes sense. Is there a way I could run the Python program in parallel to csound and check the state of the out variable at k rate? If not do you have any suggestions for how I could build the sleep time into the Orc? Really appreciate your help. Thanks, Emmett
|
Date | 2016-02-25 07:40 |
From | Richard |
Subject | Re: Read Digital IO Pins on RaspPi via Python |
A different approach is to not use the GPIO pins at all, but use an
Arduino for the interfacing to hardware. Then you can use serial
communication either in a separate python program or the with the
csound serial opcodes. This leaves the vulnerable GPIO pins alone. The Arduino gets its power via the USB interface and uses this to communicate. Richard On 25/02/16 08:21, Emmett Palaima
wrote:
|
Date | 2016-02-25 07:57 |
From | Emmett Palaima |
Subject | Re: Read Digital IO Pins on RaspPi via Python |
Just checked the serial opcodes out, it looks like that would be a very effective method. Is there any way to read multiple inputs from the serial port? I am trying to control several parameters, rather than just one. On Thu, Feb 25, 2016 at 2:40 AM, Richard <zappfinger@gmail.com> wrote:
|
Date | 2016-02-25 08:28 |
From | Sigurd Saue |
Subject | Re: Read Digital IO Pins on RaspPi via Python |
You could take a look at the chapter on Arduino in the Csound Floss manual: http://write.flossmanuals.net/csound/b-csound-and-arduino/ Near the bottom of the page you will find a method for reading multiple parameters with a resolution better than 8 bit. Sigurd From: A discussion list for users of Csound [mailto:CSOUND@LISTSERV.HEANET.IE]
On Behalf Of Emmett Palaima
Just checked the serial opcodes out, it looks like that would be a very effective method. Is there any way to read multiple inputs from the serial port? I am trying to control several parameters, rather than just one.
On Thu, Feb 25, 2016 at 2:40 AM, Richard <zappfinger@gmail.com> wrote:
Csound mailing list Csound@listserv.heanet.ie https://listserv.heanet.ie/cgi-bin/wa?A0=CSOUND Send bugs reports to https://github.com/csound/csound/issues Discussions of bugs and features can be posted here |
Date | 2016-02-25 08:35 |
From | Richard |
Subject | Re: Read Digital IO Pins on RaspPi via Python |
Yes, you can format the serial data anyway you want. So for example
in the Arduino you write a program that creates a serial message
like: 'value1, value2, value3' where value 1 and 2 could be a pot
meter value, 3 could be a button. On the receiving end you just have
to parse this message. Richard On 25/02/16 08:57, Emmett Palaima
wrote:
|
Date | 2016-02-25 11:20 |
From | Tarmo Johannes |
Subject | Re: Read Digital IO Pins on RaspPi via Python |
Hi, Or if you want to stay with one piece of hardware I suggest to move the python GPIO out from csound code, write a python script that uses Csound API to pass the values via channels to Csound - works more reliably. There are examples for Csound API python (look for it, cannot find the link with thumbs so easily). Tarmo 25.02.2016 10:38 kirjutas kuupäeval "Sigurd Saue" <sigurd.saue@ntnu.no>:
Csound mailing list
Csound@listserv.heanet.ie
https://listserv.heanet.ie/cgi-bin/wa?A0=CSOUND
Send bugs reports to
https://github.com/csound/csound/issues
Discussions of bugs and features can be posted here
|
Date | 2016-02-26 21:28 |
From | Emmett Palaima |
Subject | Re: Read Digital IO Pins on RaspPi via Python |
How would I got about parsing a serial message from the arduino and putting that into an array? I tried a method which used the following code, which worked fine except that the controllers would sometimes switch which values they were controlling the program. Its based upon writing to the serial port, then reading from a given analog pin based on the value given. It seems like the problem here was the arduino's serial writes and csound's k passes running at different rates. Code: csound: <CsoundSynthesizer> <CsInstruments> ksmps = 100 ; the default krate can be too fast for the arduino to handle 0dbfs = 1 instr 1 ; connect to the arduino with baudrate = 9600 iPort serialBegin "/dev/tty.usbserial-AH02OC4V", 9600 ;serialWrite_i iPort, 1 ; read our knob value kGain init 16 ;serialFlush iPort serialWrite iPort, 1 kVal serialRead iPort printk .02, kVal if (kVal != -1) then kGain = kVal/128 endif ;serialFlush iPort serialWrite iPort, 2 kVal2 serialRead iPort printk .02, kVal2 if (kVal2 != -1) then kfreq = kVal2*4 endif ; get our audio input and get its rms asig oscil .5*kGain, kfreq aclip clip asig, 0, 0dbfs out aclip printk .02, kGain printk .02, kfreq ; scale the rms to a good value for the LED and send it out ; must be in range: 0-255 endin </CsInstruments> <CsScore> f 1 0 1024 10 1 1 1 1 1 1 i 1 0 200 e </CsScore> </CsoundSynthesizer> arduino: void setup() { // enable serial communication Serial.begin(9600);
} void loop() { // only do something if we received something (this should be at csound's k-rate) if (Serial.available()) { // while we are here, get our knob value and send it to csound int i = Serial.read(); if(i == 1){ int sensorValue = analogRead(A0); Serial.write(sensorValue/4); // scale to 1-byte range (0-255) ///delay(10); } if(i == 2){ int sensorValue = analogRead(A1); Serial.write(sensorValue/4); } } } On Thu, Feb 25, 2016 at 6:20 AM, Tarmo Johannes <tarmo.johannes@otsakool.edu.ee> wrote:
|
Date | 2016-02-26 22:18 |
From | Richard |
Subject | Re: Read Digital IO Pins on RaspPi via Python |
The Csound serial opcode only reads one byte at a time. So if you
have 3 values, make sure that they are sent as byte values (0-255)
without separators like comma's between them and do 3 times a
serialRead. But then you have the problem of synchronization. Maybe
the first byte you read in Csound is the second byte sent by the
Arduino. Then you have to use at least 2 fixed characters (like CR
and LF) to terminate the series of bytes to fix that problem. You could also use python to read the serial messages, that gives you more flexibility. It is easy to read a string terminated by CR/LF and parse the values (that would not have to be bytes), that now could be separated by commas. But then in Python you have to use the Cound API to send these received values via channel messages to Csound, where you the use a chnget to read them... BTW, I recommend not to use serialWrites in between the reads. You only want to react to controllers, I presume? Richard On 26/02/16 22:28, Emmett Palaima
wrote:
|
Date | 2016-02-27 01:09 |
From | Emmett Palaima |
Subject | Re: Read Digital IO Pins on RaspPi via Python |
Is there anything I can use where the arduino will wait for an input from csound before outputting a serial message? I feel like that would be very helpful to keeping messages from getting confused. On Fri, Feb 26, 2016 at 5:18 PM, Richard <zappfinger@gmail.com> wrote:
|
Date | 2016-02-27 02:01 |
From | Emmett Palaima |
Subject | Re: Read Digital IO Pins on RaspPi via Python |
Alternatively, how would I set up a csd to read the series of bytes and characters and format them based on that? On Fri, Feb 26, 2016 at 8:09 PM, Emmett Palaima <epalaima@berklee.edu> wrote:
|
Date | 2016-02-27 07:34 |
From | Richard |
Subject | Re: Read Digital IO Pins on RaspPi via Python |
Yes of course, that is called a handshake. In this case Csound does
send some characters first and then let the arduino return
something. E.g. you send 'P1' to ask for Pot1 Value, 'S1' for switch1, etc. I'll try to come up with an example. Richard On 27/02/16 02:09, Emmett Palaima
wrote:
|
Date | 2016-02-27 08:57 |
From | Emmett Palaima |
Subject | Re: Read Digital IO Pins on RaspPi via Python |
How does that differ from what I was doing with sending a serial write message and then reading the response from the arduino? It seems like that is the same concept of sending a message that tells which analog port to read from and then reading the response, which is exactly what i was trying to do with the code I posted. On Sat, Feb 27, 2016 at 2:34 AM, Richard <zappfinger@gmail.com> wrote:
|
Date | 2016-02-27 09:05 |
From | Richard |
Subject | Re: Read Digital IO Pins on RaspPi via Python |
You are right, that is the correct way to ensure synchronization. I
was misled because I saw some comments about sending the RMS value
to a LED. It seems the example in the Floss manual should do it. It
uses only one handshake character- a number, indicating what value
to read. I'll give it a try. Richard On 27/02/16 09:57, Emmett Palaima
wrote:
|
Date | 2016-02-27 14:42 |
From | Richard |
Subject | Re: Read Digital IO Pins on RaspPi via Python |
The last example on that Floss page works well. There is only a
small error: In the 'if' there is a: out aOut but since nchannels=2, this should be: outs aOut, aOut Richard On 27/02/16 09:57, Emmett Palaima
wrote:
|
Date | 2016-02-27 18:39 |
From | Tarmo Johannes |
Subject | Re: Read Digital IO Pins on RaspPi via Python |
Hi, you have different solution, but if it helps as an example, I once did similar thing so that arduino sent first a control byte with command code and when Csound caught that, read following byte for data. That means that you need to reserve something from 0..255 as values for the command codes (say above 250) and map your value to 0..250 (or what ever you take). The snippets: // arduino const uint8_t SENSOR = 101; //... if (distance>farLimit) distance=farLimit; result = map(distance,closeLimit,farLimit,100,0); if (result!=lastSensorResult[index]) { Serial.write(SENSOR+index); Serial.write((uint8_t)result); lastSensorResult[index]= result; } ; Csound #define IR1 #101# ; distance sensors #define IR2 #102# instr _arduino ;... giPort serialBegin "/dev/ttyACM0" ,38400 kbyte1 serialRead giPort kcounter init 0 ;... if (kbyte1 != -1 && kbyte1>=$IR1 && kbyte1<$PEDAL1) then ;ifirst sensor - 101 2. - 102; 2. byte data value 0..100 kbyte2 serialRead giPort ;printk2 kbyte2 if (kbyte1==$IR1 && kbyte2!=-1) then ; byte comes in 0..100 ;kval1= 1 + kbyte2*0.06 ; to 1..7 kval1 = iminrvbvol + (imaxrvbvol-iminrvbvol)*kbyte2*0.01 ; to iminrvbvol..imaxrvbvol elseif (kbyte1==$IR2 && kbyte2!=-1) then kval2 = kbyte2/100 endif endif ;... It is part of code and vague but gives the idea - arduino sent the data with Serial.write only if there was sufficient change and Csound controlled for incoming command byte and according to that manipulated the second data byte. If I would do the same thing again and used Raspberry as the main computerm I would not use Arduino as extra board but a AD converter and RPi GPIO pins. But there are many ways, like always. https://learn.adafruit.com/reading-a-analog-in-and-controlling-audio-volume-with-the-raspberry-pi/overview Do you know also the COSMO project http://cosmoproject.github.io/ - Alex and Bernt have a lot of experiece using RPis for live situations. Best! tarmo On Friday 26 February 2016 16:28:47 you wrote: > How would I got about parsing a serial message from the arduino and putting > that into an array? I tried a method which used the following code, which > worked fine except that the controllers would sometimes switch which values > they were controlling the program. Its based upon writing to the serial > port, then reading from a given analog pin based on the value given. It > seems like the problem here was the arduino's serial writes and csound's k > passes running at different rates. > > Code: > > *csound:* > > |