I'm working on a project where I use a photoelectric sensor to detect a reflector attached to a motor axis. Every time the reflector reflects the light from the LED from the sensor it sends a pulse (voltage) to the raspberry pi (with a voltage divider). With some help I've come to the following code and I've noticed that the results that I'm getting are way too high. Anybody got any suggestions on how to improve it? I've seen other examples of RPM code online, but I wanted to learn it myself and the ones that I've found did not use the same method as me. Thanks in advance!
import time
from gpiozero import Button
sensor = Button(17)
i=1
timestampeven=0
timestamponeven=0
def pulsen():
global i
global timestampeven
global timestamponeven
if (i % 2) ==0:
timestampeven = time.time_ns()
i+=1
elif (i % 2) == 1:
timestamponeven = time.time_ns()
i+=1
periode = timestamponeven-timestampeven
frequentie = 1/(periode*10e09)
rpm = frequentie*60
print("rpm=" + str(rpm))
print("teller = " +str(i))
print("periode = " +str(periode))
print("frequentie = " +str(frequentie))
sensor.when_pressed = pulsen
while True:
pass
I'm working on a Raspberry Pi (3 B+) making a data collection device and I'm
trying to spawn a process to record the data coming in and write it to a file. I have a function for the writing that works fine when I call it directly.
When I call it using the multiprocess approach however, nothing seems to happen. I can see in task monitors in Linux that the process does in fact get spawned but no file gets written, and when I try to pass a flag to it to shut down it doesn't work, meaning I end up terminating the process and nothing seems to have happened.
I've been over this every which way and can't see what I'm doing wrong; does anyone else? In case it's relevant, these are functions inside a parent class, and one of the functions is meant to spawn another as a thread.
Code I'm using:
from datetime import datetime, timedelta
import csv
from drivers.IMU_SEN0 import IMU_SEN0
import multiprocessing, os
class IMU_data_logger:
_output_filename = ''
_csv_headers = []
_accelerometer_headers = ['Accelerometer X','Accelerometer Y','Accelerometer Z']
_gyroscope_headers = ['Gyroscope X','Gyroscope Y','Gyroscope Z']
_magnetometer_headers = ['Bearing']
_log_accelerometer = False
_log_gyroscope= False
_log_magnetometer = False
IMU = None
_writer=[]
_run_underway = False
_process=[]
_stop_value = 0
def __init__(self,output_filename='/home/pi/blah.csv',log_accelerometer = True,log_gyroscope= True,log_magnetometer = True):
"""data logging device
NOTE! Multiple instances of this class should not use the same IMU devices simultaneously!"""
self._output_filename = output_filename
self._log_accelerometer = log_accelerometer
self._log_gyroscope = log_gyroscope
self._log_magnetometer = log_magnetometer
def __del__(self):
# TODO Update this
if self._run_underway: # If there's still a run underway, end it first
self.end_recording()
def _set_up(self):
self.IMU = IMU_SEN0(self._log_accelerometer,self._log_gyroscope,self._log_magnetometer)
self._set_up_headers()
def _set_up_headers(self):
"""Set up the headers of the CSV file based on the header substrings at top and the input flags on what will be measured"""
self._csv_headers = []
if self._log_accelerometer is not None:
self._csv_headers+= self._accelerometer_headers
if self._log_gyroscope is not None:
self._csv_headers+= self._gyroscope_headers
if self._log_magnetometer is not None:
self._csv_headers+= self._magnetometer_headers
def _record_data(self,frequency,stop_value):
self._set_up() #Run setup in thread
"""Record data function, which takes a recording frequency, in herz, as an input"""
previous_read_time=datetime.now()-timedelta(1,0,0)
self._run_underway = True # Note that a run is now going
Period = 1/frequency # Period, in seconds, of a recording based on the input frequency
print("Writing output data to",self._output_filename)
with open(self._output_filename,'w',newline='') as outcsv:
self._writer = csv.writer(outcsv)
self._writer.writerow(self._csv_headers) # Write headers to file
while stop_value.value==0: # While a run continues
if datetime.now()-previous_read_time>=timedelta(0,1,0): # If we've waited a period, collect the data; otherwise keep looping
print("run underway value",self._run_underway)
if datetime.now()-previous_read_time>=timedelta(0,Period,0): # If we've waited a period, collect the data; otherwise keep looping
previous_read_time = datetime.now() # Update previous readtime
next_row = []
if self._log_accelerometer:
# Get values in m/s^2
axes = self.IMU.read_accelerometer_values()
next_row += [axes['x'],axes['y'],axes['z']]
if self._log_gyroscope:
# Read gyro values
gyro = self.IMU.read_gyroscope_values()
next_row += [gyro['x'],gyro['y'],gyro['z']]
if self._log_magnetometer:
# Read magnetometer value
b= self.IMU.read_magnetometer_bearing()
next_row += b
self._writer.writerow(next_row)
# Close the csv when done
outcsv.close()
def start_recording(self,frequency_in_hz):
# Create recording process
self._stop_value = multiprocessing.Value('i',0)
self._process = multiprocessing.Process(target=self._record_data,args=(frequency_in_hz,self._stop_value))
# Start recording process
self._process.start()
print(datetime.now().strftime("%H:%M:%S.%f"),"Data logging process spawned")
print("Logging Accelerometer:",self._log_accelerometer)
print("Logging Gyroscope:",self._log_gyroscope)
print("Logging Magnetometer:",self._log_magnetometer)
print("ID of data logging process: {}".format(self._process.pid))
def end_recording(self,terminate_wait = 2):
"""Function to end the recording multithread that's been spawned.
Args: terminate_wait: This is the time, in seconds, to wait after attempting to shut down the process before terminating it."""
# Get process id
id = self._process.pid
# Set stop event for process
self._stop_value.value = 1
self._process.join(terminate_wait) # Wait two seconds for the process to terminate
if self._process.is_alive(): # If it's still alive after waiting
self._process.terminate()
print(datetime.now().strftime("%H:%M:%S.%f"),"Process",id,"needed to be terminated.")
else:
print(datetime.now().strftime("%H:%M:%S.%f"),"Process",id,"successfully ended itself.")
====================================================================
ANSWER: For anyone following up here, it turns out the problem was my use of the VS Code debugger which apparently doesn't work with multiprocessing and was somehow preventing the success of the spawned process. Many thanks to Tomasz Swider below for helping me work through issues and, eventually, find my idiocy. The help was very deeply appreciated!!
I can see few thing wrong in your code:
First thing
stop_value == 0 will not work as the multiprocess.Value('i', 0) != 0, change that line to
while stop_value.value == 0
Second, you never update previous_read_time so it will write the readings as fast as it can, you will run out of disk quick
Third, try use time.sleep() the thing you are doing is called busy looping and it is bad, it is wasting CPU cycles needlessly.
Four, terminating with self._stop_value = 1 probably will not work there must be other way to set that value maybe self._stop_value.value = 1.
Well here is a pice of example code based on the code that you have provided that is working just fine:
import csv
import multiprocessing
import time
from datetime import datetime, timedelta
from random import randint
class IMU(object):
#staticmethod
def read_accelerometer_values():
return dict(x=randint(0, 100), y=randint(0, 100), z=randint(0, 10))
class Foo(object):
def __init__(self, output_filename):
self._output_filename = output_filename
self._csv_headers = ['xxxx','y','z']
self._log_accelerometer = True
self.IMU = IMU()
def _record_data(self, frequency, stop_value):
#self._set_up() # Run setup functions for the data collection device and store it in the self.IMU variable
"""Record data function, which takes a recording frequency, in herz, as an input"""
previous_read_time = datetime.now() - timedelta(1, 0, 0)
self._run_underway = True # Note that a run is now going
Period = 1 / frequency # Period, in seconds, of a recording based on the input frequency
print("Writing output data to", self._output_filename)
with open(self._output_filename, 'w', newline='') as outcsv:
self._writer = csv.writer(outcsv)
self._writer.writerow(self._csv_headers) # Write headers to file
while stop_value.value == 0: # While a run continues
if datetime.now() - previous_read_time >= timedelta(0, 1,
0): # If we've waited a period, collect the data; otherwise keep looping
print("run underway value", self._run_underway)
if datetime.now() - previous_read_time >= timedelta(0, Period,
0): # If we've waited a period, collect the data; otherwise keep looping
next_row = []
if self._log_accelerometer:
# Get values in m/s^2
axes = self.IMU.read_accelerometer_values()
next_row += [axes['x'], axes['y'], axes['z']]
previous_read_time = datetime.now()
self._writer.writerow(next_row)
# Close the csv when done
outcsv.close()
def start_recording(self, frequency_in_hz):
# Create recording process
self._stop_value = multiprocessing.Value('i', 0)
self._process = multiprocessing.Process(target=self._record_data, args=(frequency_in_hz, self._stop_value))
# Start recording process
self._process.start()
print(datetime.now().strftime("%H:%M:%S.%f"), "Data logging process spawned")
print("ID of data logging process: {}".format(self._process.pid))
def end_recording(self, terminate_wait=2):
"""Function to end the recording multithread that's been spawned.
Args: terminate_wait: This is the time, in seconds, to wait after attempting to shut down the process before terminating it."""
# Get process id
id = self._process.pid
# Set stop event for process
self._stop_value.value = 1
self._process.join(terminate_wait) # Wait two seconds for the process to terminate
if self._process.is_alive(): # If it's still alive after waiting
self._process.terminate()
print(datetime.now().strftime("%H:%M:%S.%f"), "Process", id, "needed to be terminated.")
else:
print(datetime.now().strftime("%H:%M:%S.%f"), "Process", id, "successfully ended itself.")
if __name__ == '__main__':
foo = Foo('/tmp/foometer.csv')
foo.start_recording(20)
time.sleep(5)
print('Ending recording')
foo.end_recording()
I want to write a program that can:
Open an application. (I successfully executed the application using the subprocess module)
Use the application. (How do I automate a task on that particular software? Is it possible? For example, the software would require me login and python and automatically login with my credentials and proceed to automate my typical usage like opening projects)
Close the application.
from datetime import datetime
import time
import os
import subprocess
os.chdir("../../Desktop/Sublime/Sublime Text 2") #Directory need to adjust to find teamviewer
print "Starting python..."
switch = True
activator1 = True
activator2 = True
startBoolean = True
exitBoolean = True
container = None
def startTimer(startTime , exitTime):
global dateTime
global startBoolean
global exitBoolean
dateTime = datetime.now().strftime('%H%M%S')
print "Current Time: " +dateTime+ "| Start Time: " +startTime +"| Exit Time: "+exitTime
if dateTime >= startTime:
startBoolean = False
print "start boolean: "+ str(startBoolean)
if dateTime >= exitTime:
exitBoolean = False
print "exit boolean: "+ str(exitBoolean)
return [startBoolean,exitBoolean]
def startApplication(startTime):
if dateTime >= startTime:
print "Launching Application..."
process = subprocess.Popen(["./sublime_text"],shell=True) #This is using ubuntu terminal command. Might need to change the command to fits other OS.
def stopApplication(exitTime):
if dateTime >= exitTime:
print "Exiting Application..."
process = subprocess.Popen(["killall sublime_text"],shell=True)
startTime = raw_input("Project Launch Time: ")
exitTime = raw_input("Project Exit time: ")
while switch:
startTimer(startTime , exitTime)
global container
container = startTimer(startTime , exitTime)
if container!=None:
if activator1==True:
if container[0] == False:
print "clear1"
activator1 = False #Cannot activate < 1.
startApplication(startTime)
if activator2==True:
if container[1] == False:
print "clear2"
activator2 = False #Cannot activate < 1.
stopApplication(exitTime)
Hi you can use pyAutoIt
I am giving sample code for Notepad to save it in required location and required path.
import autoit,time
autoit.run("notepad.exe")
autoit.win_wait_active("Untitled - Notepad")
time.sleep(5)
autoit.control_send("Untitled - Notepad", "Edit1", "hello world{!}")
autoit.control_send("Untitled - Notepad", "Edit1", "test-2")
#time.sleep(5)
autoit.win_close("Untitled - Notepad")
autoit.control_click("Notepad", "Button1")
#time.sleep(5)
autoit.win_wait_active("Save As")
#time.sleep(5)
autoit.control_send("Save As", "Edit1","Path-to-save")
autoit.control_send("Save As", "Edit1", "file-name")
autoit.control_click("Save As", "Button1")
pywinauto is also great GUI automation solution on Python.
Example:
from pywinauto import Application
app = Application().start(r"C:\Program Files\Sublime Text 2\sublime_text.exe")
app.untitled_SublimeText2.Wait('ready', timeout=10) # just for possible slow start
app.untitled_SublimeText2.MenuSelect('File->Open file')
app.Open.FilenameEdit.SetText('path to the project')
app.Open.Open.Click()
app.Open.WaitNot('visible') # just to make sure it's closed
main_window = app["project_name - Sublime Text 2"]
# print access names for all available controls on the main window
main_window.PrintControlIdentifiers()
There is also GUI helper SWAPY, pywinauto object inspector and code generator.
I use a template of a python script (running on Raspberry Pi) to send sensor data (i2c) via WiFi to my PC. The problem is, the values are not static. If I start the Web application, it reads the data from the sensor only once. So, if I check the values from my PC, I can see it sent the data correctly, but they won't change.
How can I modify the script to refresh the i2c_output value, without starting the script over and over again?
Here is what I have tried so far:
import web
import sys, os
import smbus
import math
#
# Lot of initialisation... forget that part
#
accel_xout = read_word_2c(0x3b)
accel_yout = read_word_2c(0x3d)
accel_zout = read_word_2c(0x3f)
afs_sel = read_word_2c(0x28)
LSB_afs_sel = 16384.0
accel_xout_sc = accel_xout / LSB_afs_sel
accel_yout_sc = accel_yout / LSB_afs_sel
accel_zout_sc = accel_zout / LSB_afs_sel
i2c_output = str(accel_xout_sc) + str(accel_yout_sc) + str(accel_zout_sc)
urls = ( '/','Index',
)
class Index:
def GET(self):
return i2c_output
if __name__=="__main__":
app=web.application(urls,globals())
app.run()
Move the code that retrieves the sensor data into a method and invoke that method each time the index is called.
def get_sensor_output():
#
# Lot of initialisation... forget that part
#
accel_xout = read_word_2c(0x3b)
accel_yout = read_word_2c(0x3d)
accel_zout = read_word_2c(0x3f)
afs_sel = read_word_2c(0x28)
LSB_afs_sel = 16384.0
accel_xout_sc = accel_xout / LSB_afs_sel
accel_yout_sc = accel_yout / LSB_afs_sel
accel_zout_sc = accel_zout / LSB_afs_sel
i2c_output = str(accel_xout_sc) + str(accel_yout_sc) + str(accel_zout_sc)
return i2c_output
class Index:
def GET(self):
return get_sensor_output()
Note: You may want to implement some sort of cache depending on how often this get method is called. currently each call will retrieve the sensor data, which may or may not be an expensive operation that will drain the battery on your pi
I'm using TKinter to draw a GUI for a python program im making, and I have it updating at about 200ms, but when the program queries the data it locks the program because it takes a second to get the data. I tried to write it into multi processing so each query would be its own process and just share the info with global variables because my program is a real time program that uses wmi to get performance data. At least thats what I have so far. Not the end goal just the start. So if you could help me figure out why even with multiprocessing if it queries the info while I'm dragging the app across the screen it will freeze for a second.
import wmi
import time
import Tkinter as tk
from multiprocessing import cpu_count
import Image
from PIL import ImageTk
from Tkinter import Button, Label
import threading
from multiprocessing import Process, Value, Array
window = Tk();
global pct_in_use
global available_mbytes
global utilization
global hours_up
a= 0
b=0
def build_labels(gui, string):
var = StringVar()
label = Label( gui, textvariable=var, relief=RAISED )
var.set(string)
return label
def get_uptime():
global hours_up
c = wmi.WMI()
secs_up = int([uptime.SystemUpTime for uptime in c.Win32_PerfFormattedData_PerfOS_System()][0])
hours_up = secs_up / 3600
return hours_up
def get_cpu():
global utilization
c = wmi.WMI()
utilizations = [cpu.LoadPercentage for cpu in c.Win32_Processor()]
utilization = int(sum(utilizations) / len(utilizations)) # avg all cores/processors
return utilization
def get_mem_mbytes():
global available_mbytes
c = wmi.WMI()
available_mbytes = int([mem.AvailableMBytes for mem in c.Win32_PerfFormattedData_PerfOS_Memory()][0])
return available_mbytes
def get_mem_pct():
global pct_in_use
c = wmi.WMI()
pct_in_use = int([mem.PercentCommittedBytesInUse for mem in c.Win32_PerfFormattedData_PerfOS_Memory()][0])
return pct_in_use
def Draw():
global mem_per_lb
global cpu_lb
global up_time_lb
global mb_used_lb
mem_pct = 0
mem_per_lb = tk.Label(text='Memory % ' + str(mem_pct))
mem_per_lb.place(x=10, y=10)
cpu = 0
cpu_lb = tk.Label(text='CPU % ' + str(cpu))
cpu_lb.place(x=10, y=30)
mem_pct = 0
up_time_lb = tk.Label(text='UP Time % ' + str(mem_pct))
up_time_lb.place(x=10, y=50)
mem_pct = 0
mb_used_lb = tk.Label(text='Memory MB ' + str(mem_pct))
mb_used_lb.place(x=10, y=70)
def Refresher():
global mem_per_lb
global cpu_lb
global up_time_lb
global mb_used_lb
mem_pct = get_mem_pct()
cpu = get_cpu()
up_time = get_uptime()
mbused = get_mem_mbytes()
window.wm_title('Vision' + time.asctime())
mem_per_lb.configure(text='Memory % ' + str(pct_in_use))
cpu_lb.configure(text='CPU ' + str(utilization))
up_time_lb.configure(text='UP Time ' + str(hours_up))
mb_used_lb.configure(text='Memory MB ' + str(available_mbytes))
window.after(200, Refresher) # every second...
def draw_window(): #creates a window
window.geometry('704x528+100+100')
image = Image.open('bg.jpg') #gets image (also changes image size)
image = image.resize((704, 528))
imageFinal = ImageTk.PhotoImage(image)
label = Label(window, image = imageFinal) #creates label for image on window
label.pack()
label.place(x = a, y = b) #sets location of label/image using variables 'a' and 'b'
Draw()
Refresher()
window.mainloop()
up_time_p = Process(target=get_uptime())
cpu_p = Process(target=get_cpu())
mb_p = Process(target=get_mem_mbytes())
pct_p = Process(target=get_mem_pct())
win_p = Process(target=draw_window())
up_time_p.start()
mb_p.start()
pct_p.start()
cpu_p.start()
win_p.start()
up_time_p = Process(target=get_uptime())
cpu_p = Process(target=get_cpu())
mb_p = Process(target=get_mem_mbytes())
pct_p = Process(target=get_mem_pct())
win_p = Process(target=draw_window())
I don't think you're supposed to include parentheses when you supply targets to a process. If you do that, the functions will execute in the main thread, and whatever those functions return will become the target.
up_time_p = Process(target=get_uptime)
cpu_p = Process(target=get_cpu)
mb_p = Process(target=get_mem_mbytes)
pct_p = Process(target=get_mem_pct)
win_p = Process(target=draw_window)
As per Kevin's answer, you're calling the functions when you create each process instance. So they are all actually running in the main process.
However, once you fix that problem your 'global' variables aren't going to work as you expect. When a process is created it takes a COPY of the parent processes memory. Any changes to that memory are not shared between the processes.
To achieve the result you want you'll have to use Python's threading library. Not the multiprocess library.
Threads share the same memory space as the parent process. Which can lead to its own problems. Though in your case the global variables you're changing are just integer constants so it should be okay.
from threading import Thread
data_funcs = (
get_uptime,
get_cpu,
get_mem_mbytes,
get_mem_pct,
draw_window
)
threads = [Thread(target=f) for f in data_funcs]
for t in threads:
t.start()
Is the general pattern you should use. You'll then have to figure out a way of killing those threads when you shut down the main process or it will hang.