How to create a callback function to start and stop recording EMG Button in real time for Delsys Trigno.
4 次查看(过去 30 天)
显示 更早的评论
Hello,
I am trying to create a start stop to record a data stream for the Delsys Trigno System in MATLAB. If I run the file as is, then it will automatically run the signal, and stop when the figures are closed, but I would like to control it will through a button. I have pasted the Matlab code that runs the data stream and displays in figures below. But, I am struggles to also seperate the functionality of controlling the data stream and displaying it in figures. When I try to pass the commObject between files, which is needed to communicate, it continues to give me errors. I would be greateful if somebody could help. All the code below is from the delsys Trigno SDK.
function real_time_data_stream_plotting
% CHANGE THIS TO THE IP OF THE COMPUTER RUNNING THE TRIGNO CONTROL UTILITY
HOST_IP = '10.101.29.77';
%%
%This example program communicates with the Delsys SDK to stream 16
%channels of EMG data and 48 channels of ACC data.
%% Create the required objects
%Define number of sensors
NUM_SENSORS = 4;
%handles to all plots
global plotHandlesEMG;
plotHandlesEMG = zeros(NUM_SENSORS,1);
global plotHandlesACC;
plotHandlesACC = zeros(NUM_SENSORS*3, 1);
global rateAdjustedEmgBytesToRead;
%TCPIP Connection to stream EMG Data
interfaceObjectEMG = tcpip(HOST_IP,50041);
interfaceObjectEMG.InputBufferSize = 6400;
%TCPIP Connection to stream ACC Data
interfaceObjectACC = tcpip(HOST_IP,50042);
interfaceObjectACC.InputBufferSize = 6400;
%TCPIP Connection to communicate with SDK, send/receive commands
global commObject;
commObject = tcpip(HOST_IP,50040);
% handles.commObject = commObject;
%Timer object for drawing plots.
t = timer('Period', .1, 'ExecutionMode', 'fixedSpacing', 'TimerFcn', {@updatePlots, plotHandlesEMG});
global data_arrayEMG
data_arrayEMG = [];
global data_arrayACC
data_arrayACC = [];
%% Set up the plots
axesHandlesEMG = zeros(NUM_SENSORS,1);
axesHandlesACC = zeros(NUM_SENSORS,1);
%initiate the EMG figure
figureHandleEMG = figure('Name', 'EMG Data','Numbertitle', 'off', 'CloseRequestFcn', {@localCloseFigure, interfaceObjectEMG, interfaceObjectACC, commObject, t});
set(figureHandleEMG, 'position', [50 200 750 750])
for i = 1:NUM_SENSORS
axesHandlesEMG(i) = subplot(2,2,i);
plotHandlesEMG(i) = plot(axesHandlesEMG(i),0,'-y','LineWidth',1);
set(axesHandlesEMG(i),'YGrid','on');
%set(axesHandlesEMG(i),'YColor',[0.9725 0.9725 0.9725]);
set(axesHandlesEMG(i),'XGrid','on');
%set(axesHandlesEMG(i),'XColor',[0.9725 0.9725 0.9725]);
set(axesHandlesEMG(i),'Color',[.15 .15 .15]);
set(axesHandlesEMG(i),'YLim', [-.025 .025]);
set(axesHandlesEMG(i),'YLimMode', 'auto');
set(axesHandlesEMG(i),'XLim', [0 2000]);
set(axesHandlesEMG(i),'XLimMode', 'manual');
if(mod(i, 4) == 1)
ylabel(axesHandlesEMG(i),'V');
else
set(axesHandlesEMG(i), 'YTickLabel', '')
end
if(i >12)
xlabel(axesHandlesEMG(i),'Samples');
else
set(axesHandlesEMG(i), 'XTickLabel', '')
end
%save('test.mat','axesHandlesEMG')
title(sprintf('EMG %i', i))
end
%initiate the ACC figure
figureHandleACC = figure('Name', 'ACC Data', 'Numbertitle', 'off', 'CloseRequestFcn', {@localCloseFigure, interfaceObjectEMG, interfaceObjectACC, commObject, t});
set(figureHandleACC, 'position', [850 200 750 750]);
for i= 1:NUM_SENSORS
axesHandlesACC(i) = subplot(2, 2, i);
hold on
plotHandlesACC(i*3-2) = plot(axesHandlesACC(i), 0, '-y', 'LineWidth', 1);
plotHandlesACC(i*3-1) = plot(axesHandlesACC(i), 0, '-y', 'LineWidth', 1);
plotHandlesACC(i*3) = plot(axesHandlesACC(i), 0, '-y', 'LineWidth', 1);
hold off
set(plotHandlesACC(i*3-2), 'Color', 'r')
set(plotHandlesACC(i*3-1), 'Color', 'b')
set(plotHandlesACC(i*3), 'Color', 'g')
set(axesHandlesACC(i),'YGrid','on');
%set(axesHandlesACC(i),'YColor',[0.9725 0.9725 0.9725]);
set(axesHandlesACC(i),'XGrid','on');
%set(axesHandlesACC(i),'XColor',[0.9725 0.9725 0.9725]);
set(axesHandlesACC(i),'Color',[.15 .15 .15]);
set(axesHandlesACC(i),'YLim', [-3 1]);
set(axesHandlesACC(i),'YLimMode', 'auto');
set(axesHandlesACC(i),'XLim', [0 2000/13.5]);
set(axesHandlesACC(i),'XLimMode', 'manual');
if(i > 12)
xlabel(axesHandlesACC(i),'Samples');
else
set(axesHandlesACC(i), 'XTickLabel', '');
end
if(mod(i, 4) == 1)
ylabel(axesHandlesACC(i),'g');
else
set(axesHandlesACC(i) ,'YTickLabel', '')
end
title(sprintf('ACC %i', i))
end
%%Open the COM interface, determine RATE
fopen(commObject);
pause(1);
fread(commObject,commObject.BytesAvailable);
fprintf(commObject, sprintf(['RATE 2000\r\n\r']));
pause(1);
% fread(commObject,commObject.BytesAvailable);
% fprintf(commObject, sprintf(['RATE?\r\n\r']));
% pause(1);
data = fread(commObject,commObject.BytesAvailable);
emgRate = strtrim(char(data'));
if(strcmp(emgRate, '1925.926'))
rateAdjustedEmgBytesToRead=1664;
else
rateAdjustedEmgBytesToRead=1728;
end
%% Setup interface object to read chunks of data
% Define a callback function to be executed when desired number of bytes
% are available in the input buffer
bytesToReadEMG = rateAdjustedEmgBytesToRead;
interfaceObjectEMG.BytesAvailableFcn = {@localReadAndPlotMultiplexedEMG,plotHandlesEMG,bytesToReadEMG};
interfaceObjectEMG.BytesAvailableFcnMode = 'byte';
interfaceObjectEMG.BytesAvailableFcnCount = bytesToReadEMG;
bytesToReadACC = 384;
interfaceObjectACC.BytesAvailableFcn = {@localReadAnPlotMultiplexedACC, plotHandlesACC, bytesToReadACC};
interfaceObjectACC.BytesAvailableFcnMode = 'byte';
interfaceObjectACC.BytesAvailableFcnCount = bytesToReadACC;
drawnow
start(t);
%pause(1);
%
%Open the interface object
try
fopen(interfaceObjectEMG);
fopen(interfaceObjectACC);
catch
localCloseFigure(figureHandleACC,1 ,interfaceObjectACC, interfaceObjectEMG, commObject, t);
delete(figureHandleEMG);
error('CONNECTION ERROR: Please start the Delsys Trigno Control Application and try again');
end
disp('now press start');
%%
% Send the commands to start data streaming
disp('it came here');
fprintf(commObject, sprintf(['START\r\n\r']));
%%
% Display the plot
snapnow;
%% Implement the bytes available callback
%The localReadandPlotMultiplexed functions check the input buffers for the
%amount of available data, mod this amount to be a suitable multiple.
%Because of differences in sampling frequency between EMG and ACC data, the
%ratio of EMG samples to ACC samples is 13.5:1
%We use a ratio of 27:2 in order to keep a whole number of samples.
%The EMG buffer is read in numbers of bytes that are divisible by 1728 by the
%formula (27 samples)*(4 bytes/sample)*(16 channels)
%The ACC buffer is read in numbers of bytes that are divisible by 384 by
%the formula (2 samples)*(4 bytes/sample)*(48 channels)
%Reading data in these amounts ensures that full packets are read. The
%size limits on the dataArray buffers is to ensure that there is always one second of
%data for all 16 sensors (EMG and ACC) in the dataArray buffers
function localReadAndPlotMultiplexedEMG(interfaceObjectEMG, ~,~,~, ~)
global rateAdjustedEmgBytesToRead;
bytesReady = interfaceObjectEMG.BytesAvailable;
bytesReady = bytesReady - mod(bytesReady, rateAdjustedEmgBytesToRead);%%1664
if (bytesReady == 0)
return
end
global data_arrayEMG
data = cast(fread(interfaceObjectEMG,bytesReady), 'uint8');
data = typecast(data, 'single');
if(size(data_arrayEMG, 1) < rateAdjustedEmgBytesToRead*19)
data_arrayEMG = [data_arrayEMG; data];
else
data_arrayEMG = [data_arrayEMG(size(data,1) + 1:size(data_arrayEMG, 1));data];
save('data_ArrayEMG.mat', 'data_arrayEMG')
end
function localReadAnPlotMultiplexedACC(interfaceObjectACC, ~, ~, ~, ~)
bytesReady = interfaceObjectACC.BytesAvailable;
bytesReady = bytesReady - mod(bytesReady, 384);
if(bytesReady == 0)
return
end
global data_arrayACC
data = cast(fread(interfaceObjectACC, bytesReady), 'uint8');
data = typecast(data, 'single');
if(size(data_arrayACC, 1) < 7296)
data_arrayACC = [data_arrayACC; data];
else
data_arrayACC = [data_arrayACC(size(data, 1) + 1:size(data_arrayACC, 1)); data];
end
%% Update the plots
%This timer callback function is called on every tick of the timer t. It
%demuxes the dataArray buffers and assigns that channel to its respective
%plot.
function updatePlots(obj, Event, tmp)
global data_arrayEMG
global plotHandlesEMG
for i = 1:size(plotHandlesEMG, 1)
data_ch = data_arrayEMG(i:16:end);
set(plotHandlesEMG(i), 'Ydata', data_ch)
end
global data_arrayACC
global plotHandlesACC
for i = 1:size(plotHandlesACC, 1)
data_ch = data_arrayACC(i:48:end);
set(plotHandlesACC(i), 'Ydata', data_ch)
end
drawnow
%% Implement the close figure callback
%This function is called whenever either figure is closed in order to close
%off all open connections. It will close the EMG interface, ACC interface,
%commands interface, and timer object
function localCloseFigure(figureHandle,~,interfaceObject1, interfaceObject2, commObject, t)
%%
% Clean up the network objects
if isvalid(interfaceObject1)
fclose(interfaceObject1);
delete(interfaceObject1);
clear interfaceObject1;
end
if isvalid(interfaceObject2)
fclose(interfaceObject2);
delete(interfaceObject2);
clear interfaceObject2;
end
if isvalid(t)
stop(t);
delete(t);
end
if isvalid(commObject)
fclose(commObject);
delete(commObject);
clear commObject;
end
%%
% Close the figure window
delete(figureHandle);
2 个评论
Manuel Duarte
2021-11-24
Hello! I am working with the Delsys Trigno system and my project is to acquire and filter data in real time using matlab. I am running into the same issues you were, by the time you posted this. I would be greateful if you could help me out.
晴晴
2022-11-22
Hello! I also met the same problem recently. Have you solved this problem?I would be greateful if you could help me out.
回答(1 个)
Benjamin Kraus
2022-11-22
I didn't dig into your code specifically, but here is code for a simple app with a timer and a start/stop button that shows how you can control a timer using a button. The key bits you need for your app are most likely the line that creates the button, and the buttonClicked callback function.
function simpleTimerApp
% Create a timer with a callback function.
% Note that I'm using an anonymous function to pass the figure handle (fig)
% into the timer fcn. I will set the TimerFcn later, once I have a figure
% handle to use.
t = timer('Period', 1, 'ExecutionMode', 'fixedSpacing');
% I'm using an onCleanup object to make sure the timer is always deleted
% when the figure closes. Deleting the onCleanup object will delete the
% timer.
c = onCleanup(@() cleanupTimer(t));
% Create a figure for the app.
fig = uifigure('Name', string(0));
% By storing a handle to the onCleanup object in the figure's UserData, the
% onCleanup object will be deleted automatically when the figure closes,
% which will stop and delete the timer.
fig.UserData = c;
% Now that I have a figure handle, create a TimerFcn on the timer that
% calls updateCounter. I'm using an anonymous function to pass the figure
% handle into the updateCounter function.
t.TimerFcn = @(~,~) updateCounter(fig);
% The button that can start or stop the timer. I'm once again using an
% anonymous function, passing both the button and timer handles into
% "buttonClicked". The button handle will be used to update the label on
% the button.
uibutton(fig,'Text','Start','ButtonPushedFcn', @(b,~) buttonClicked(b,t));
end
function updateCounter(fig)
% This function is called by the timer every time it executes, with a
% frequency based on the "Period" of the timer. I'm going to use the "Name" field in the figure as a counter for
% simplicity, but the body of this function should do whatever needs to be
% done every execution of the timer.
fig.Name = string(str2double(fig.Name)+1);
end
function buttonClicked(b, t)
% This function runs whenever the button is clicked. It will check the
% state of the timer and either start or stop the timer.
disp('Button Clicked')
if isvalid(t)
if (t.Running == "on")
% Timer is running, stop it.
stop(t);
% The next time the button is pressed it will start the timer, so
% update the button text to say "Start".
b.Text = "Start";
else
% Timer is stopped, start it.
start(t);
% The next time the button is pressed it will stop the timer, so
% update the button text to say "Stop".
b.Text = "Stop";
end
end
end
function cleanupTimer(t)
% This function will run when the onCleanup object is deleted due to the
% figure being closed. It needs to stop and delete the timer.
if isvalid(t)
stop(t)
delete(t)
end
end
0 个评论
另请参阅
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!