start 2 timers simultaneously in a matlab function - matlab

I have a program with 2 timer functions like this (p_maj_input and p_maj_output_motion are equal so the period of both timer is the same):
maj_input = timer('ExecutionMode','fixedRate','Period',p_maj_input,'TasksToExecute', ...
floor(Tmeasurement/p_maj_input)-1,'TimerFcn',{#time_append,p_maj_input,HR_all,freq_HR, ...
BVP_all,freq_BVP,TEMP_all,freq_TEMP,ACC_x_all,ACC_y_all,ACC_z_all,freq_ACC,EDA_all,freq_EDA, ...
folder_all,all_dir,num_dir}); start(maj_input);
maj_output_motion=timer('ExecutionMode','fixedRate','Period',p_maj_output_motion,'TasksToExecute', ...
floor(Tmeasurement/p_maj_output_motion)-1,'TimerFcn',{#output_motion_append, ...
freq_MOTION,freq_mvt_score,freq_walk,p_maj_output_motion,p_maj_output_walk,folder_all,all_dir,num_dir});%,'StartDelay',min(5,p_maj_output_motion)); %startDelay must be min 5 for walk detection start(maj_output_motion);
In each timer callback function there is a loop over subfolders contained in a folder that is selected at the beginning of the program.
output_motion_append(obj,event,freq_MOTION,freq_mvt_score,freq_walk,p_maj_output_motion,p_maj_output_walk,folder_all,all_dir,num_dir)
fprintf('motion %d\n',obj.TasksExecuted)
toc
for folder_index=1:num_dir
[folder_original,folder_fictive] = subfolderFunction(all_dir, folder_all, folder_index);
fileName=strcat(folder_fictive,'\ACC.csv');
[ACC_time, ACC_x, ACC_y, ACC_z] = loadValuesE4_acc(fileName);
% Motion Amount
[agitation,agitation_ts] = identifyAgitation(ACC_x,ACC_y,ACC_z,ACC_time);
agitation=agitation';
len1=length(agitation);
if len1<=freq_MOTION*p_maj_output_motion
i_init1=1;
elseif len1>freq_MOTION*p_maj_output_motion
i_init1=len1-freq_MOTION*p_maj_output_motion+1;
end
writematrix([agitation(i_init1:len1)],strcat(folder_fictive,'\MOTION_output.csv'),'WriteMode','Append');
writematrix([mvt_score(i_init2:len2)],strcat(folder_fictive,'\neurologicScore_output.csv'),'WriteMode','Append');
end
end
Everything works fine if the number of subfolders is lower than 4 : the good values appear in the files on which is carried out the writematrix function. And the timer callback function are are called one after the other, so both timer work simultaneously.
However if there are 5 subfolders or more, it is not the good values and using the debugging I noticed that the first callback function is triggered the number of 'TasksToExecute', and then only the second callback function seems to be called. That is to say the 2 timers don't work simultaneously.
I have tried to increase p_maj_input and p_maj_output_motion to see if the problem is that matlab can't finish to run before another timer callback function is called but still for 5 subfolders I get the same problem.
Does anyone know where my problem is coming from?

This behavior occurs because one timer hasn't finished executing by the time it triggers again, so the second timer never has a chance to execute until the first timer is finished. If you change the ExecutionMode from 'fixedRate' to 'fixedSpacing', then you'll guarantee that there's time for the second timer to execute.
function duelingTimers()
disp('With ExecutionMode = fixedRate')
t1 = timer('ExecutionMode','fixedRate','Period',0.1,'TasksToExecute',5,'TimerFcn',#timerFcn1);
t2 = timer('ExecutionMode','fixedRate','Period',0.1,'TasksToExecute',5,'TimerFcn',#timerFcn2);
cleanup = onCleanup(#()delete([t1,t2]));
function timerFcn1(~,~)
pause(0.2)
disp('Timer 1');
end
function timerFcn2(~,~)
pause(0.2)
disp('Timer 2');
end
start(t1),start(t2)
wait(t1)
wait(t2)
disp(newline)
disp('With ExecutionMode = fixedSpacing')
t1.ExecutionMode = 'fixedSpacing';
t2.ExecutionMode = 'fixedSpacing';
start(t1),start(t2)
wait(t1)
wait(t2)
end

Related

Why is the turtlebot not moving continously?

if __name__ == '__main__':
rospy.init_node('gray')
settings = termios.tcgetattr(sys.stdin)
pub = rospy.Publisher('cmd_vel', Twist, queue_size=1)
x = 0
th = 0
node = Gray()
node.main()
We make the publisher(cmd_vel) in main, and run the main function of class gray.
def __init__(self):
self.r = rospy.Rate(10)
self.selecting_sub_image = "compressed" # you can choose image type "compressed", "raw"
if self.selecting_sub_image == "compressed":
self._sub = rospy.Subscriber('/raspicam_node/image/compressed', CompressedImage, self.callback, queue_size=1)
else:
self._sub = rospy.Subscriber('/usb_cam/image_raw', Image, self.callback, queue_size=1)
self.bridge = CvBridge()
init function makes a subscriber, which runs 'callback' when it gets data.
def main(self):
rospy.spin()
Then it runs the spin() function.
v, ang = vel_select(lvalue, rvalue, left_angle_num, right_angle_num, left_down, red_dots)
self.sendv(v, ang)
Inside the callback function, it gets a linear speed and angular speed value, and runs a sendv function to send it to the subscribers.
def sendv(self, lin_v, ang_v):
twist = Twist()
speed = rospy.get_param("~speed", 0.5)
turn = rospy.get_param("~turn", 1.0)
twist.linear.x = lin_v * speed
twist.angular.z = ang_v * turn
twist.linear.y, twist.linear.z, twist.angular.x, twist.angular.y = 0, 0, 0, 0
pub.publish(twist)
and... sendv function sends it to the turtlebot.
It has to move continuously, because if we do not publish data, it still has to move with the speed it got from the last publish. Also, callback function runs every 0.1 seconds, so it keeps sending data.
But it does not move continously. It stops for a few seconds, and go for a very short time, and stops again, and go for a very short time, and so on. The code which selects the speed works correctly, but the code who sents it to the turtlebot does not work well. Can anyone help?
Also, callback function runs every 0.1 seconds.
I believe this is incorrect. I see that you have made a self.r object but never used it anywhere in the code to achieve an update rate of 10hz. If you want to run the main loop at every 0.1 seconds, you will have to call your commands within the following loop (see rospy-rates) before calling rospy.spin():
self.r = rospy.Rate(10)
while not rospy.is_shutdown():
<user commands>
self.r.sleep()
However, this would not help you either since your code is publishing to /cmd_vel within the subscriber callback which gets called only on receiving some data from the subscriber. So basically, your /cmd_vel is not being published at the rate of 10hz but rather at the rate at which you are receiving the data from the subscribed topic ('/raspicam_node/image/compressed'). Since these are image topics, they might be taking a lot of time to be updated hence the delay in your velocity commands to the robot.

View start time of Matlab timer object

How do you view and amend the start time of a timer object in Matlab? The closest I can get is the "StartDelay" element of the timer object :
all_timers = get(timerfind);
where each element of the returned structure array is one timer object. The various elements of the structure are (for example):
AveragePeriod: NaN
BusyMode: 'drop'
ErrorFcn: ''
ExecutionMode: 'singleShot'
InstantPeriod: NaN
Name: 'timer-1'
ObjectVisibility: 'on'
Period: 1
Running: 'on'
StartDelay: 7.200175000000000e+003
StartFcn: ''
StopFcn: ''
Tag: ''
TasksExecuted: 0
TasksToExecute: Inf
TimerFcn: #myFcn
Type: 'timer'
UserData: []
According to:
http://www.mathworks.co.uk/help/matlab/ref/timer-class.html
"StartDelay" is: Number greater than or equal to 0 that specifies the delay, in seconds, between the start of the timer and the first execution of the function specified in TimerFcn.
but unless I know when the timer object was started/created/initiated, the StartDelay is no real help?
The startFun can be used to evaluate a function on timer start, which could store the start time in the userData of the timer
Most simple
Define a function such as;
function myStartFcn(hTimer,~)
hTimer.UserData = now;
end
and set this to be the startFcn of the timer
hTimer = timer();
hTimer.StartFcn = #myStartFcn
A better? example
userData is a useful field we may want to use it for many things, in which case making it a structure and setting this as a field would be better. also now gives datenum format which may not be ideal, clock is another possibility;
function myStartFcn(hTimer,~)
tempStruct = hTimer.UserData;
tempStruct.startTime = clock;
hTimer.UserData = tempStruct;
end
Also it may be worth clearing this when the timer is stopped and storing the last run time in seconds
function myStopFcn(hTimer,~)
tempStruct = hTimer.UserData;
tempStruct.lastRunTime = etime(clock,tempStruct.startTime)
tempStruct.startTime = []
hTimer.UserData = tempStruct;
end

Using fixedRate timer in MATLAB with different data for each interval (trying to replace for loop with timer)

Is there a way to have a MATLAB timer pass different data on each subsequent call to the timer function? My goal is to cycle through intervals at a fixed rate, and the pause function inside a loop is not precise enough.
I have workng MATLAB code that uses a for loop to send data via serial ports, then wait a specified time before the next iteration of the loop. The serial communication varies in speed, so if I specify 300 seconds as the period, the loop actually executes every 340-360 seconds. Here is the existing code:
clear all;
testFile = input('What is the name of the test data file (with extension): ', 's');
measurementData = csvread(testFile);
intervalDuration = input('What is the measurement change period (seconds): ');
intervalNumber = size(measurementData,2);
% Set up the COM PORT communication
sensorComPort = [101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120];
controllerComPort = [121,122,123,124];
for j=1:intervalNumber
tic
fprintf('\nInterval # %2d\n',rem(j,24));
sensorMeasurementPS = [measurementData(1,j),measurementData(2,j),measurementData(3,j),measurementData(4,j),measurementData(5,j), measurementData(6,j),measurementData(7,j),measurementData(8,j),measurementData(9,j),measurementData(10,j), measurementData(11,j),measurementData(12,j),measurementData(13,j),measurementData(14,j),measurementData(15,j), measurementData(16,j),measurementData(17,j),measurementData(18,j),measurementData(19,j),measurementData(20,j)];
serialSensorObj = startsensorPSWithoutReset(sensorComPort, sensorMeasurementPS);
serialSensorObj = changeMeasurement(serialSensorObj, sensorMeasurementPS);
rc = stopsensorPS(serialSensorObj);
controllerMeasurementPS = [measurementData(21,j),measurementData(22,j),measurementData(23,j),measurementData(24,j)];
serialControllerObj = startControllerPSWithoutReset(controllerComPort, controllerMeasurementPS);
serialControllerObj = changeMeasurement(serialControllerObj, controllerMeasurementPS);
rc2 = stopControllerPS(serialControllerObj);
pause(intervalDuration);
t = toc;
fprintf('Elapsed time = %3.4f\n',t);
end
clear serialSensorObj;
clear serialControllerObj;
The serial functions are specified in other files and they are working as intended.
What I need to do is have the serial communication execute on a more precise 5-minute interval. (The actual timing of the commands inside the interval will still vary slightly, but the commands will kick off every 5 minutes over the course of 24 hours. The current version loses time and gets out of sync with another system that is reading the measurements I'm setting by serial port.)
My first thought is to use a MATLAB timer with the fixedRate execution mode, which queues the function at fixed intervals. However, it doesn't appear that I can send the timer function different data for each interval. I thought about having the timer function change a counter in the workspace, similar to j in my existing for loop, but I know that having functions interact with the workspace is not recommended.
Here's what I've come up with so far for the timer method:
function [nextJ] = changeMeasurement_fcn(obj,event,j,sensorComPort,controllerComPort)
tic
fprintf('\nInterval # %2d\n',rem(j,24));
sensorMeasurementPS = [measurementData(1,j),measurementData(2,j),measurementData(3,j),measurementData(4,j),measurementData(5,j), measurementData(6,j),measurementData(7,j),measurementData(8,j),measurementData(9,j),measurementData(10,j), measurementData(11,j),measurementData(12,j),measurementData(13,j),measurementData(14,j),measurementData(15,j), measurementData(16,j),measurementData(17,j),measurementData(18,j),measurementData(19,j),measurementData(20,j)];
serialSensorObj = startSensorPSWithoutReset(sensorComPort, sensorMeasurementPS);
serialSensorObj = changeMeasurement(serialSensorObj, sensorMeasurementPS);
rc = stopSensorPS(serialSensorObj);
controllerMeasurementPS = [measurementData(21,j),measurementData(22,j),measurementData(23,j),measurementData(24,j)];
serialControllerObj = startControllerPSWithoutReset(controllerComPort, controllerMeasurementPS);
serialControllerObj = changeMeasurement(serialControllerObj, controllerMeasurementPS);
rc2 = stopControllerPS(serialControllerObj);
t2 = toc;
fprintf('Elapsed time = %3.4f\n',t2);
and this is how I would call it from the main m file:
t = timer('TimerFcn',#changeMeasurement,'ExecutionMode','fixedRate','period',intervalDuration);
% then I need some code to accept the returned nextJ from the timer function
This feels a bit sloppy so I'm hoping there's a built-in way to have a timer cycle through a data set.
Another idea I had was to keep the for loop but change the pause function to use a value calculated based on how much time would add up to 5 minutes for the iteration.
To summarize my question:
a) Can I have a timer pass different data to the timer function on each iteration?
b) Is that a good way to go about cycling through the intervals in my data on a precise 5-minute interval?
Thanks!
I stumbled on this page: http://www.mathworks.com/company/newsletters/articles/tips-and-tricks-simplifying-measurement-and-timer-callbacks-with-nested-functions-new-online-support-features.html
and learned that timer callback functions can be nested inside other functions (but not regular scripts).
Using that information, I cut my scenario to the basics and came up with this code:
function timerTestMain_fcn
testFile = input('What is the name of the test data file (with extension): ', 's');
testData = csvread(testFile);
intervalDuration = input('What is the voltage change period (seconds): ');
intervalNumber = size(testData,2);
t = timer('ExecutionMode','fixedRate','period',intervalDuration,'TasksToExecute',intervalNumber);
t.TimerFcn = {#timerTest_fcn};
start(t);
wait(t);
delete(t);
function timerTest_fcn(obj,event)
tic
event_time = datestr(event.Data.time);
interval_id = t.TasksExecuted;
data_value = testData(1,interval_id);
txt1 = 'Interval ';
txt2 = num2str(interval_id);
txt3 = ' occurred at ';
txt4 = ' with data value of ';
txt5 = num2str(data_value);
msg = [txt1 txt2 txt3 event_time txt4 txt5];
disp(msg)
t2 = toc;
fprintf('Elapsed time = %3.4f\n',t2);
end
end
The test data file it requests must be a csv containing a row vector. For example, you could put the values 11,12,13,14,15 across the first row of the csv. The output message would then say 'Interval 1 occurred at [time] with data value of 11', 'Interval 2 occurred at [time] with data value of 12', etc.
The key is that by nesting the functions, the timer callback can reference both the test data and the timer attributes contained in the outer function. The TasksExecuted property of the timer serves as the counter.
Thanks to anyone who thought about my question. Comments welcome.

MATLAB change repeating timer period

Is it possible to change the Period of a repeating timer (in TimerFcn)?
Intuitively, when programming for Windows, I would handle WM_TIMER messages and use SetTimer to edit the period of a timer, but a similar approach doesn't seem to work in MATLAB, because the timer needs to be restarted in order to change the Period property. This messes up execution, which can be best described as changing the period to near-zero. No errors are produced.
Here's some example code that's used to create a task array: each task item consists of something to do and a delay. The array is basically walked by a timer, which should change its Period based on the current task delay.
function obj = Scheduler(~)
obj.scheduletimer = timer(...
'TimerFcn',#obj.OnTimer,...
'BusyMode','queue',...
'TasksToExecute',length(obj.tasklist),...
'ExecutionMode','fixedRate');
end
function OnTimer(obj,source,event)
obj.Start(); // Executed task, schedule next
end
function Start(obj)
// Stop timer if needed
if(strcmp(obj.scheduletimer.Running,'on'))
stop(obj.scheduletimer);
end;
// Set new period and resume
if(~isempty(obj.tasklist))
obj.scheduletimer.Period = obj.tasklist(1).something;
start(obj.scheduletimer);
end;
end
When I don't mess with the timer in OnTimer, everything obviously works fine, but I'd like to change the Period each iteration.
Edit: I've tried to implement the pingpong solution suggested by Pursuit, but it's still not working. Note that the switching timers idea does work, but periods still don't seem to be applied.
function obj = Scheduler(~)
obj.timer1 = timer(...
'TimerFcn',#obj.OnTimer);
obj.timer2 = timer(...
'TimerFcn',#obj.OnTimer);
end
function OnTimer(obj,source,event)
obj.Start(); // Executed task, schedule next
end
function Start(obj)
if(strcmp(obj.timer1.Running,'on'))
obj.timer2.Period = obj.tasklist{1}{2};
start(obj.timer2);
else
obj.timer1.Period = obj.tasklist{1}{2};
start(obj.timer1);
end;
end
Ugh.
Use two timers, (e.g. timerNamePing and timerNamePong). At the end of the action for each timer setup the next timer to execute once in single shot mode with some delay.
This avoids the need to constantly tear down and create new timers, and avoids the error which occurs when you try and edit a timer which is currently executing.
Here is a working example to demonstrate:
function setupPingPong
timerPing = timer;
timerPong = timer;
timerPing.TimerFcn = #(~,~)pingPongActivity(true, timerPing, timerPong);
timerPing.Name = 'PingTimer';
timerPong.TimerFcn = #(~,~)pingPongActivity(false, timerPing, timerPong);
timerPong.Name = 'PongTimer';
timerPing.StartDelay = 0;
start(timerPing);
function pingPongActivity(isPing, timerPing, timerPong)
if isPing
disp(['PING (' datestr(now,'yyyy-mm-dd HH:MM:SS.FFF') ')'])
else
disp(['PONG (' datestr(now,'yyyy-mm-dd HH:MM:SS.FFF') ')'])
end
delayTime = ceil(rand*10);
display([' delaying ' num2str(delayTime) ' sec.'])
if isPing
nextTimer = timerPong;
else
nextTimer = timerPing;
end
set(nextTimer,'StartDelay', delayTime);
start(nextTimer);
Once this is going, to stop the madness, I use:
t = timerfind; stop(t); delete(t)
I use the 'StopFcn' property in timer object again to restart the counter.
something like this ('TimerScale' changes the next period)
init :
Timer_OBJ = timer( 'ExecutionMode', 'singleShot', ...
'StartDelay', SystemTicksSecs/TimerScale, ...
'TimerFcn', #(src,evt)obj.TimerCallBack,...
'StopFcn', #(src,evt)obj.TimerStopCallBack );
start(Timer_OBJ);
and inside TimerStopCallBack
set(Timer_OBJ, 'StartDelay', SystemTicksSecs/TimerScale);
start(Timer_OBJ);

How to Stop a MATLAB Timer Object From The Function's Workspace After It's Executed

Say I've got a function that evaluates to:
function test_timer()
a = timer ;
set(a, 'executionMode', 'fixedRate','TimerFcn','disp(rand)')
start(a)
end
..and I've accidentally left out 'stop(a)' within the function's clause.
How do you stop the timer object (or all timer objects) from running without closing MATLAB using the command window?
You can use timerfind to find the timers you would like to stop.
Like this:
tmr = timer('Name', 'timer1', 'TimerFcn', #(x,y)disp('Timer running'));
start(tmr);
stop(timerfind('Name', 'timer1'));
You can basically search any property you can define in timer function.
EDIT: You can use the delete function to delete the timers.
Let's create a couple of timers to find and delete them:
tmr1=timer('Name', 'timer1', 'Period', 5, 'TimerFcn', #(x,y)disp('Timer 1 running'));
tmr2=timer('Name', 'timer2', 'Period', 5, 'TimerFcn', #(x,y)disp('Timer 2 running'));
start(tmr1);
start(tmr2);
tmrList=timerfind('Period', 5); % Find the timers whose periods are 5 seconds.
stop(tmrList);
timerfind
Timer Object Array
Index: ExecutionMode: Period: TimerFcn: Name:
1 singleShot 5 1x1 function_handle arraytimer1
2 singleShot 5 1x1 function_handle arraytimer2
delete(tmrList);
timerfind
ans =
[]