TimerWipy
-
Hi , can someone explain how the method
''''timerchannel.irq(*, trigger, priority=1, handler=None)''' works?
I have to use TimerWiPy.PERIODIC.
I don't undestand also handler function.
-
@robert-hh Hi, sorry for my insistence on this topic.
I 'm not able to use thread but I read about it and I think that it's better for my code if I use them . So do you know if is it possibile to use thread to read from two I2C through the code that I posted before?
thank you.
-
@robert-hh I solved the problem creating a new function to compare data acquire by sensor with reference data and then it power on pwm. And in this way the period remain 50 ms.
thank you
-
@vflorio94 For a consistent operation at a period of 0.02 or 50 ms it is required that the handler takes not longer than that, and that is executes the OWM changes at almost the same time within the handler. Looking at your code, I see at least two things that could affect timing:
a) You write to a file. File i/O is buffered. As long as the data is written into the buffer, it's fast. When the buffer will be written, it can be slow.
b) You call lib_imu2.get_euler() several times in the timer handler. I do not know the complexity of that call, but if it includes access to external hardware, then it may take some time. Better call it once, store the result and use that in consecutive statements.
-
@robert-hh Thank you, I solved this problem. I put data as metod.
Now I have a new problem because I want to read data from sensor and after a comparisono with reference data I want to activate pwm. I did it in this way.
But the problem is that the period change a lot, sample time decrease to 0.04.
Is there another way to modify this code for activate pwm that can be better??
I need if it is possible that period remain more possible like 0.02.thank you
import machine import pycom from machine import Timer from machine import idle import time import lib_imu import lib_imu2 from machine import I2C from math import sqrt from math import fabs from machine import PWM from machine import SD import gc import os sd = SD() os.chdir('/sd') from machine import idle # # add the other imports here that you need # fileIMU1 = open('/sd/dati_IMU1.txt', 'w') # # acquire values. The paramters of the constructor are: # class Acquire: def __init__(self, filename_imu1, data, period=0.02, runtime = 60): self.fileIMU1 = open(filename_imu1, "w") self.temp = Timer.Chrono() self.busy = True self.data = data self.runtime = runtime self.temp.start() self.alarm = Timer.Alarm(self.sample_and_write, period , periodic=True) # and add all other init tasks you need def stop(self): self.alarm.cancel() pwm_c2.duty_cycle(0) pwm_c5.duty_cycle(0) self.fileIMU1.close() #self.fileIMU2.close() def sample_and_write(self, alarm): passed = self.temp.read() # check, if done, if the time for sampling is expired, then stop if passed >= self.runtime: self.stop() self.busy = False print('end') else: # get data and write #print(passed, fabs(lib_imu2.get_euler()[2])) self.fileIMU1.write(repr(passed) + repr(lib_imu2.get_euler()) + "\n") # avanti if fabs(lib_imu2.get_euler()[2]) > ( fabs(dati_rif[2]) + 0.2): if fabs(lib_imu2.get_euler()[2]) < (fabs(dati_rif[2]) + 0.4): pwm2 = PWM(0, frequency=1000 ) pwm_c2.duty_cycle(0.5) pwm_c5.duty_cycle(0) elif fabs(lib_imu2.get_euler()[2]) >= (fabs(dati_rif[2]) + 2): pwm2 = PWM(0, frequency=2000 ) pwm_c2.duty_cycle(0.6) pwm_c5.duty_cycle(0) # indietro elif fabs(lib_imu2.get_euler()[2]) < fabs(dati_rif[2]) + 0.2: if fabs(lib_imu2.get_euler()[2]) > (fabs(dati_rif[2]) + 0.4): pwm5 = PWM(0, frequency=1000 ) pwm_c2.duty_cycle(0) pwm_c5.duty_cycle(0.5) elif fabs(lib_imu2.get_euler()[2])< (fabs(dati_rif[2]) + 2): pwm5 = PWM(0, frequency=2000 ) pwm_c2.duty_cycle(0) pwm_c5.duty_cycle(0.5) # and what else you have to do. # # now here the skeleton main_ # sd = SD() os.chdir('/sd') # set up the hardware ''' SET UP IMU 0X29 ''' # Scala Berg: imu L5 - lib_imu - acc lib_imu.set_acc() time.sleep(0.01) lib_imu.set_configmode() time.sleep(0.01) lib_imu.set_units() time.sleep(0.01) lib_imu.set_mode('ndof') time.sleep(0.01) ''' SET UP IMU 0X28 ''' # imu t1 - lib_imu2 - eul lib_imu2.set_configmode() time.sleep(0.01) lib_imu2.set_units() time.sleep(0.01) lib_imu2.set_mode('ndof') time.sleep(0.01) ''' PWM ''' pwm2 = PWM(0, frequency=500 ) pwm5 = PWM(0, frequency=500 ) #This sets up the timer to #oscillate at the specified frequency. timer is an integer from 0 to 3. # frequency is an integer from 1 Hz to 78 KHz pwm_c5 = pwm2.channel(5, pin='P12') #dietro pwm_c2 = pwm5.channel(2, pin='P5') # avanti pwm_c5.duty_cycle(0) time.sleep(0.01) pwm_c2.duty_cycle(0) time.sleep(0.01) ''' START''' with open("/sd/Rif.txt", "r") as f: line = f.read() # now you have a list of one string per line dati_rif = [float(el) for el in line.strip("()\n ").split(",")] # reference data print('start') acquire = Acquire('Acquisition_Vibration.txt', dati_rif[2], 0.02, 30) # # now get the data, until it's done # while acquire.busy: idle() # # whatever you have to do for cleanup, do it here #```
-
@vflorio94 That's a question of scope and visibility in Python.
So most simple but unelegant method is to have that data global. So it is created outside every function. Then at any part of your code you can declare is a global to access it. Example:# at the top level of your code: data_buffer = bytearray(100) data_ptr_in = 0 data_ptr_out = 0 # # class MyClass: def my_func(self): # declare symbols as global global data_buffer, data_ptr_in, data_ptr_out data_buffer[data_ptr_in] = some_data data_ptr_in = (data_ptr_in + 1) % len(data:buffer)
You can also define functions (or better to say methods) to pass along data, and you can use property and setter and getter methods of classes, ...
-
@robert-hh sorry, I describe the problem in a bad way. I have another question.
I have a data that I want to use inside the function 'sample_and_write', but I have some difficulties to pass it from main to the class '''Acquire''' and in the end to the function. Is it possible ? can you help me?
-
@vflorio94 ???
-
@robert-hh yes, I checked and you are right. And about command to activate pwm responding to data acquire by sensor?
-
@vflorio94 said in TimerWipy:
self.pwm = PWM(0.02, frequency=500 )
The first argument of the class instantiation is a timer ID, not a time or the like. The value range is 0 - 3. See: https://docs.pycom.io/firmwareapi/pycom/machine/pwm
So it should be:
self.pwm = PWM(0, frequency=500 )
-
@robert-hh Hello. I have to ask you a new thing correlate with this code that you wrote previously.
I want to implement the code with another part in which I desire to activate PWM depending on the data sample and wrote by IMU. So, the question is:
Is it correct if I introduced a control on the data that I wrote and the command to activate PWM in the fuction 'sample and write'?
And have I also to complete class acquire like this?self.pwm = PWM(0.02, frequency=500 ) #This sets up the timer to #oscillate at the specified frequency. timer is an integer from 0 to 3. # frequency is an integer from 1 Hz to 78 KHz
I know that I have also to set PWM channel where I put set-up Hardware parameters.
I'll be newly grateful if you can help me.
-
@robert-hh I understand all. finally it works without any interrupt
than you a lot.
-
@vflorio94 Timer.Alarm() has to be called only once.
-
@vflorio94 You do not have to call alarm. Actually, it is not a function, it is a timer object. The callback function is called by the Timer periodically without further action by your main program. You main code has to prepare the data & objects needed by the callback and then start the timer. Typically, all of that would be enclosed in a class, and the main program would just instantiate this class. That could look like this:
# from machine import Timer, idle # # add the other imports here that you need # # acquire values. The paramters of the constructor are: # class Acquire: def __init__(self, filename_imu1, period=0.2, runtime = 60): self.fileIMU1 = open(filename_imu1, "w") # or append self.temp = Timer.Chrono() self.busy = True self.runtime = runtime self.temp.start() self.alarm = Timer.Alarm(self.sample_and_write, period ,periodic=True) # and add all other init tasks you need def stop(self): self.alarm.cancel() self.fileIMU1.close() def sample_and_write(self, alarm): passed = self.temp.read() # check, if done, if the time for sampling is expired, then stop if passed >= self.runtime: self.stop() self.busy = False else: # get data and write print(passed, self.runtime) self.fileIMU1.write(repr(passed) + "," + lib_imu.get_euler_int() + "\n") # # and what else you have to do. # # now here the skeleton main_ # # set up the hardware # # and start acquire = Acquire("my_data_file", 0.2, 20) # # now get the data, until it's done # while acquire.busy: idle() # # whatever you have to do for cleanup, do it here #
-
@robert-hh the function can be like this?
import machine import pycom from machine import Timer import time import lib_imu import lib_imu2 from machine import I2C from math import sqrt from machine import PWM from machine import SD import gc import os sd = SD() os.chdir('/sd') PERIOD= 0.02 #sample time lib_imu.set_configmode() time.sleep(0.01) lib_imu.set_units() time.sleep(0.01) lib_imu.set_mode('ndof') time.sleep(0.01) lib_imu2.set_configmode() time.sleep(0.01) lib_imu2.set_units() time.sleep(0.01) lib_imu2.set_mode('ndof') time.sleep(0.01) fileIMU1 = open('/sd/dati_IMU1.txt', 'w') #fileT_IMU1 = open("/sd/datiT_IMU1.txt", "w") fileIMU2 = open('/sd/dati_IMU2.txt', 'w') #fileT_IMU2 = open("/sd/datiT_IMU2.txt", "w") file_tempi = open('/sd/tempi.txt', 'w') list_eul = [ ] list_eul2 = [ ] list_tempi = [] def sample_and_write(timer_obj): #timer_obj?? #list_tempi.append(temp.read()) list_eul.append(lib_imu.get_euler_int()) #list_tempi.append(temp.read()) list_eul2.append(lib_imu2.get_euler_int()) pass def acquisition(sec): t = Timer.Chrono() t.start() while 1: t = t.read() if t <= sec : alarm = Timer.Alarm(sample_and_write, PERIOD, periodic = true) else: alarm.cancel() fileIMU1.write( repr(list_eul) + '\t') fileIMU2.write( repr(list_eul2) + '\t') del list_eul del list_eul2
-
@robert-hh thank you, now i'm trying to modify my function.
- so, is 'timer_obj' my time of acquisition?
- is alarm the command that I have to use in main?
thank you a lot
-
@vflorio94 With that method you can achieve, that a certain function, the handler, is called when the time expires. That is what you need for your project. The setting of timer.PERIODIC means, that it is called over & over again. Like:
from machine import timer PERIOD = 0.2 # call every 0.2 seconds def sample_and_write(timer_obj): # this is a function which reads form the sensor and writes # to disk. timer_obj identifies the timer, which calls this function # Can be ignored pass alarm = Timer.Alarm(sample_and_write, PERIOD, periodic=True)
And when you want to stop it, call
alarm.cancel()
Edit: It should be positively noted that the callback is no interrupt. This means you are free for almost any Python operation, especially allocating memory.