OSC proper fader control algorithm - python

I am coding in python 2.7 to accommodate OSC communication from my ipad to my rasp pi using the 'touchOSC' app from the app store. (this is not for music or midi, but simply to access values to control stepper motors etc..) I am using windows to code and then I transfer the .py to my rasp pi (not the issue here). I set up the fader in touch OSC's layout software with the name, IP address that is in the code below. Also, I set the range value of the fader in the software that touchOSC has provided from 0 to 1.
The issue is that I am receiving only zeros when I invoke the fader on my ipad. What I wish to see is the values incrementing from 0 to 1 by floating values. I believe I would need to use some sort range function? This is the issue, How can specify that I want the fader to increment in the code below?
Right now the code is:
from OSC import OSCServer,OSCClient, OSCMessage
server = OSCServer( ("192.168.0.8", 8000) )
client = OSCClient()
def handle_timeout(self):
print ("I'm IDLE")
#This here is just to do something while the script recieves no information....
server.handle_timeout = types.MethodType(handle_timeout, server)
def fader_0(path, tags, args, source):
value=int(args[0]) # Value is the variable that will transform the input from the faders into whole numbers(easier to deal with)
print "Fader Value:", value
server.addMsgHandler("/1/fader1", fader)
My question regards the Def fader_0(path, tags, args, source)
When I input: value = int(args[0]), I receive a zero when I adjust the fader on my ipad via touch OSC. this is obvious; however, I wish to access the floating points in between 0 and 1 as the fader is incremented.
I assume the code would be: value = float(args[someLoop]) maybe something like value = float(args[range(0,1,.125)])
Thank you in advance.

The values coming from TouchOSC are floats between 0 and 1. In the fader_0 function, you currently transform the float from TouchOSC, args[0] to an int which rounds any number less than 1 down to 0, thus your program prints out zero every time.
You can easy see how this happens in the python interpreter:
In [2]: int(0.7)
Out[2]: 0
The solution is just to remove the int function from fader_0 like so:
def fader_0(path, tags, args, source):
value=args[0]
print "Fader Value:", value

Related

PyQt readyRead: set text from serial to multiple labels

In PyQt5, I want to read my serial port after writing (requesting a value) to it. I've got it working using readyRead.connect(self.readingReady), but then I'm limited to outputting to only one text field.
The code for requesting parameters sends a string to the serial port. After that, I'm reading the serial port using the readingReady function and printing the result to a plainTextEdit form.
def read_configuration(self):
if self.serial.isOpen():
self.serial.write(f"?request1\n".encode())
self.label_massGainOutput.setText(f"{self.serial.readAll().data().decode()}"[:-2])
self.serial.write(f"?request2\n".encode())
self.serial.readyRead.connect(self.readingReady)
self.serial.write(f"?request3\n".encode())
self.serial.readyRead.connect(self.readingReady)
def readingReady(self):
data = self.serial.readAll()
if len(data) > 0:
self.plainTextEdit_commandOutput.appendPlainText(f"{data.data().decode()}"[:-2])
else: self.serial.flush()
The problem I have, is that I want every answer from the serial port to go to a different plainTextEdit form. The only solution I see now is to write a separate readingReady function for every request (and I have a lot! Only three are shown now). This must be possible in a better way. Maybe using arguments in the readingReady function? Or returning a value from the function that I can redirect to the correct form?
Without using the readyRead signal, all my values are one behind. So the first request prints nothing, the second prints the first etc. and the last is not printed out.
Does someone have a better way to implement this functionality?
QSerialPort has asyncronous (readyRead) and syncronous API (waitForReadyRead), if you only read configuration once on start and ui freezing during this process is not critical to you, you can use syncronous API.
serial.write(f"?request1\n".encode())
serial.waitForReadyRead()
res = serial.read(10)
serial.write(f"?request2\n".encode())
serial.waitForReadyRead()
res = serial.read(10)
This simplification assumes that responces comes in one chunk and message size is below or equal 10 bytes which is not guaranteed. Actual code should be something like this:
def isCompleteMessage(res):
# your code here
serial.write(f"?request2\n".encode())
res = b''
while not isCompleteMessage(res):
serial.waitForReadyRead()
res += serial.read(10)
Alternatively you can create worker or thread, open port and query requests in it syncronously and deliver responces to application using signals - no freezes, clear code, slightly more complicated system.

Get a wrong cpu_frequence from raspberry pi in python

i want use python to get the cpu_freq value from raspberry pi 4B
def GetCpuInfo():
# Get CPU frequence
cpu_freq =open("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq").read()
return cpu_freq
when i print the cpu_freq data, the output always fixed in 1800000(it's the max cpu frequence 1.8Ghz of raspberry pi),but when each time i use the
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
this command in terminal,it give me the dynamic valve(600000-1800000)
So why do i get wrong value when using the python? is it a wrong way to read this file?
There's nothing wrong with your read().
The very act of starting Python can itself take enough cycles to cause the CPU to ramp up to full frequency, especially on a small system like a Pi.
To prevent that, add a delay to let it spool back down before you take your readings. For example:
import time
def GetCpuInfo():
with open("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq") as f:
return f.read()
for _ in range(20):
time.sleep(1)
print(GetCpuInfo())

Python PySerial Program Not Reading Data Correctly

Before I get into the background of what's going on, the problem, and the steps I've taken to fix it, here's a quick summary of the equipment I'm using for my project
Equipment I'm using:
Infrared Encoder: https://www.amazon.ca/dp/B07B3PLZZ2/ref=cm_sw_r_oth_api_glt_i_NCFT5KHJBARTBC76XG7Y?_encoding=UTF8&psc=1
Arduino Mega 2560 w/ 9V 1A power adapter: https://www.amazon.ca/gp/product/B01H4ZDYCE/ref=ppx_yo_dt_b_asin_title_o01_s00?ie=UTF8&psc=1
Computer: Macbook Pro 2020, M1 Chip, 8 GB RAM
IDE: Pycahrm Community Edition
Python Interpreter: Python 3.8
Background:
I have a fan that spins at a constant speed. Intercepting the blades of the fan is my Infrared encoder that's hooked up to my Arduino. as the blades spin through the infrared encoder, the Arduino script I wrote is supposed to print a '1' if the sensor is triggered and a '0' if it isn't.
This works fine.
Now, I want to be able to use this '1' and '0' data in Python because I have an idea for a video game I want to prototype using Pygame.
On Pycharm, I installed pyserial so I'm able to access all the data. In order to capture the 1's and 0's in Pycharm, here's the code I've written:
Variables
serialInst = serial.Serial()
serialInst.port = '/dev/cu.usbmodem11301'
serialInst.baudrate = 9600
serialInst.timeout = 0.5
serialInst.open()
Read Data Function
def readData(self):
if serialInst.inWaiting():
packet = serialInst.readline()
if int(packet.decode('utf').rstrip('\n')) == 1:
print('1')
elif int(packet.decode('utf').rstrip('\n')) == 0:
print('0')
The way it works is fairly simple. As I described before, if the fan triggers the sensor, Arduino prints out a '1', and then Python reads the data and confirms it with the if statement.
Same operation for when the sensor is not triggered.
The Problem
This function is the first function called in the main while loop of my python code. There are other functions that are called afterward before it loops around to the readData function however when those functions are called, it's almost as if the Arduino data stops checking to see if there have been any changes.
What the problem looks like
No matter if the fan's blades go through the sensor, the output is always 0
If I comment out any function that's used in the main while loop, everything works 100% fine. The issue only happens when I start to introduce other functions into the main while loop.
What I've tried
I currently have 9 other tabs open with similar Pyserial issues people have reported here on StackOverflow and here are some of the things I've read about and tried:
Adding a serialInst.timeout value. I played with a variety of numbers from 0.01 to 0.5 and haven't found success
Using serialInst.reset_output_buffer(), serialInst.flushOutput(), serialInst.reset_input_buffer(), or serialInst.flushInput() in a variety of different locations
And I've tried many more potential solutions however, this was when my problem was even worse... Before, I had the readData function as part of a Class in another however, every time I tried to run it from the main while loop, it would skip data, not give any data, show very odd characters... it was just a nightmare.
Now I have the readData function in the main game Class and just need to solve this last issue and everything will work.
Summary
I have a python function called readData that reads data coming from an Arduino that's either a '1' or a '0'. When the readData is the only function being called in the main while loop of my program, everything works fine; there are '1's when there should be and '0' when there should be.
The problem arises when I uncomment the other functions in the while loop that I have to use.
The program definitely loops through the entire while loop however, when it reaches the readData function, it gets "stuck" at reading just '0'... even when there's supposed to be a '1'.
What I need
The readData function if statements should print out a '1' or '0' correctly, no matter if the other functions in the main while loop are commented out or not.
I need to "unfreeze" whatever is holding up that part of the program.
Please let me know if you need any more information. I really appreciate your time.
Update
It seems as though when the other functions are called, everything works fine however, when I can pygame.display.update(), that's when the arduino data starts to "freeze".
I'm not sure why updating the screen for my game will cause the program to stop working...
I also added a Serial.flush() to the Arduino code... if that helps...
Fixed the problem
I was wrong in thinking it was the other functions that I was calling in the while loop that caused the problem.
It turns out, when I uncommented the other functions, my code ran as expected:
There were 1's when the fan triggered the sensor and 0s when there was no sensor activity.
So what exactly was the problem?
It was a few things:
1. pygame.display.update()
When I uncommented pygame.display.update(), this is when my realData() function (the function who's job it is to output the 1's and 0's) would "freeze."
It was look like this:
0
0
0
0
0
0
0
It would never pick up a '1' even though the fan was clearly hitting the sensor.
The reason for this, I still have no idea... but I found a way past it.
To fix this, I added this:
serialInst.reset_input_buffer()
to the end of the realData() function.
After this, I was introduced to a new problem:
The data outputted 1's, 0's and a bunch of spaces I didn't want. It would look like this:
1
0
0
0
0
0
0
0
1
0
1
I didn't want those spaces because my realData() function was programmed with certain if statements that would perform certain tasks if there was a 1 OR a 0... not a newline/space.
The reason this happened was because of the Arduino.
Here's the code on the Arduino side that was causing the problem:
void loop() {
// read the state of the pushbutton value:
x = digitalRead(sensor);
// check if the fan hit the sensor. If it is, the sensor is HIGH:
if (sensor == HIGH) {
Serial.print(1);
} else {
Serial.print(0);
}
}
The problem was, I was using:
Serial.println(1)
// and
Serial.println(0)
This would tell Pycharm that I wanted to send 1's, 0's, and new lines. Therefore, I changed that code to:
Serial.print(1)
// and
Serial.print(0)
This eliminated Pycharm from receiving the random new lines
After, there was still two last issues on the Pycharm side to fix which was easy:
Instead of capturing the data in Pycharm with:
packet = serialInst.readline()
I used:
packet = serialInst.read()
The final part was to simply decode the message because it would output things like:
b'0'
b'0'
b'0'
b'1'
b'0'
b'0'
So I simply used:
x = int(packet.decode('utf'))
The final product looked like this:
0
0
0
0
0
0
0
0
1
0
0
0
0
0
0
0
0
1
0
0
Etc...
Now I can use the if statements to further progress my game depending on if a '1' is in the output or a '0'.
It's now perfect. I truly hope this helps anyone who is experiencing the same issues I was.

micrpython machine library i2c write functions do not seem to work at all--any idea why?

I am currently working on a simple project in micropython, using a BMP388 barometric pressure sensor (datasheet here: https://www.mouser.com/pdfdocs/BST-BMP388-DS001-01.pdf). I am having trouble with Micropython's writeto_mem() and writeto() functions (documentation: https://docs.micropython.org/en/latest/library/machine.I2C.html). I do not understand why these functions appear unable to write to my registers, while the readfrom_mem() function works just fine.
Here are code snippets I've tried:
from machine import I2C
from time import sleep
_address = 0x76 #or 0x77 if I disconnect a certain pin, but this is not an issue.
i2c = I2C(scl=Pin(22), sda=Pin(21))
def set_sampling_v1():
i2c.writeto(_address, bytes(0x1c), False)
i2c.writeto(_address, bytes(0x0d), True)
#I also tried i2c.writeto(_address, bytes(0x1c0d), True)
print(i2c.readfrom_mem(_address, 0x1c, 1)) #get what I just wrote
print(i2c.readfrom_mem(_address, 0x00, 1)) #get device ID, confirm we're able to read
def set_sampling_v2():
i2c.writeto_mem(_address, 0x1C, bytes(0x0D))
print(i2c.readfrom_mem(_address, 0x1c, 1)) #get what I just wrote
print(i2c.readfrom_mem(_address, 0x00, 1)) #get device ID, confirm we're able to read
set_sampling_v1()
#Or try:
#set_sampling_v2()
In both set_sampling functions, the readfrom_mem() functions return:
x00
b'P' #which is just x50, and is the correct value.
In the case of v1, I am unsure how exactly micropython handles writeto(), but the I2C protocol takes the device address, a "RW" bit, and then a pair of bytes, before a stop condition, with the RW bit set to 0 for "write". So I tried both attempts at writing which made sense to try. In v2, since it is using the "convenience" function, I assume writeto_mem() replicates what I tried to do in the first version. I also assume micropython is able to supply the correct RW bit value when supplied with an address. Presumably it's doing something like (_address | 0x01) in the underlying function.
To summarize i2c operation, the BMP388 takes the device's address and a RW bit set to tell it whether to read or write. Then it takes a pair of bytes, one specifying the register and one specifying the data to be written. A stop condition follows at the end, to tell it that communication is complete. This is also why I've tried writing 0x1c0d as well as trying two separate write commands, since I was concerned the writeto() function would send the address register once per function call instead of just once. The writeto_mem() function supposedly just needs the device address, target register, and byte to be written, and so I didn't both testing alternative approaches. It's also worth noting, in version 1 of the sample function, the line
i2c.writeto(_address, 0x1c0d, True)
has the same x00 and b'p' result when I call the readfrom_mem() function.
Since the read functions return the correct device ID, I trust that x00 is what's actually in the the 0x1c register (which is where you set the sensor's oversampling rate for pressure and temperature). I've also successfully used the readfrom_mem() function on other registers to read and confirm their default values. Taken together, this convinces me that the function is reading the value in 0x1c and returning x00 because the writeto functions are failing to write.
Any insight into this would be welcome. I am about to review the datasheet to ensure there isn't something that must be set in a different register before I'm able to alter the contents of read/write registers, but I don't recall seeing such a thing before, and I'm wondering if anyone has insight into this problem.
If you need additional information I haven't provided, please let me know, and I will attempt to update this post as promptly as I can.

Handling time-out for Python-script with RS485 & minimalmodbus

Presently have a read-out on an RS485-bus of 1 (one) RS485 kWh-meter, type DDS238-1ZN by means of a Python-script 'assisted' by module minimalmodbus.
Adding more kWh-meters means that (prior or during installation) the Slave-Adress of the added kWh-meter has to be shifted from the initial '1'.
Such shift-action starts with scanning the RS485-bus to determine where kWh-meter(s) are actually located.
First step is the following simple Python-script
import serial
import minimalmodbus
# Check address 00 = broadcast
instrument = minimalmodbus.Instrument('/dev/ttyAMA0',0) # port name, slave address
instrument.serial.baudrate = 9600
instrument.serial.timeout = 0.5
instrument.debug = True
print instrument
print instrument.read_register(21,0) # registernumber, number of decimals
# Check address 01 = slave 01
instrument = minimalmodbus.Instrument('/dev/ttyAMA0',1) # port name, slave address
print instrument
print instrument.read_register(21,0) # registernumber, number of decimals
# Check address 02 = slave02
instrument = minimalmodbus.Instrument('/dev/ttyAMA0',2) # port name, slave address
print instrument
print instrument.read_register(21,0) # registernumber, number of decimals
The check on Slave-addresses 00 and 01 produces the result (257) as expected, but (due to absence of a device) obviously response on Slave-adress 02 is failing with a time-out.
For further problem-description see http://www.domoticz.com/forum/viewtopic.php?f=31&t=13592#p102901
From test runs, I can see that a time-out occurs.
A time-out-signal could be trigger to step-over to check for next slave-address, if I knew the layout of such time-out-signal for a Python-script with minimalmodbus ....
Searching the internet for an alternative, I see all kind of 'wonderful &elaborate' solutions to trap a time-out, but in the perspective of my simple script I am looking for something very basic (preferably a 'one-liner') to enable stepping out of the time-out to check the next slave-address 3, etc.
Looking at those solutions mentioned above, could perhaps the following setup with semi-code be a simple/basic solution? [for which I have been looking in direction of the C-function fread() ]
start of loop
start time-counter
read register from slave address x
N = number of characters received
if time-counter at value t, then
look if N > 0
if N == 0 then
x = x + 1
jump to start of loop
Any hint for a script using Python or MinimalModbus to perform the semi-code, compatible with the first script?
No working solution found/received in this Forum, but a pragmatic, simple remedy has been developed, tested and put in action, as described at http://www.domoticz.com/forum/viewtopic.php?f=14&t=5808&start=20#p113697
Due to the characteristics of it's data-protocol, the remedy is specific for kWh-meter type DDS238-1ZN, but the idea can possibly be applied for other, comparable kWh-meters with RS485-interface.

Categories