Dot indexing is not supported for variables of this type
31 views (last 30 days)
Show older comments
this is my complete code i am working on and have tried numerous ways of fixing it , its not even showing me the line error or anything only that error image appears when i try to use the features of my gui

function robot_control_standalone()
% ROBOT_CONTROL_STANDALONE - Standalone robot control GUI (No GUIDE required)
% (Camera+Calibration+Detection implemented; functions/GUI names preserved)
% ---------------- Main figure ----------------
hFig = figure('Name', 'Robot Control System', ...
'NumberTitle', 'off', ...
'Position', [100, 100, 1200, 700], ...
'CloseRequestFcn', @closeGUI, ...
'Tag', 'mainFigure');
% ---------------- State / handles ----------------
handles = struct();
handles.figure = hFig;
% ===== ROBOT CONFIGURATION =====
handles.ModelName = 'armpiwithcoords';
handles.RPi_IP = '192.168.1.14';
handles.RPi_Port = 5005;
try
handles.udpObj = udpport("IPv4");
catch
warning('Could not create UDP object. Network communication disabled.');
handles.udpObj = [];
end
handles.toggleLoop = false;
handles.Kp = 1; handles.Ki = 0; handles.Kd = 0;
handles.prevError = 0; handles.integral = 0;
% ===== VISION SYSTEM CONFIGURATION =====
handles.CAM_INDEX = 2*1;
handles.CAM_WIDTH = 1280;
handles.CAM_HEIGHT = 720;
handles.BELT_WIDTH_M = 0.60; % physical belt span (X) in meters
handles.BELT_HEIGHT_M = 0.30; % physical belt span (Y) in meters
handles.MIN_AREA_PX = 1200;
handles.cam = [];
handles.visionActive = false;
% Calibration/top-down
handles.calibrated = false;
handles.H_rect = []; % projective2d transform image->topdown px
handles.OUT_W = []; handles.OUT_H = [];
handles.px_per_m_x = []; handles.px_per_m_y = [];
handles.detected_objects = [];
handles.visionLoopActive = false;
% ArUco placeholders (we use manual 4-click for now)
handles.ARUCO_DICT = 'DICT_4X4_50';
handles.ID_TL = 0; handles.ID_TR = 1; handles.ID_BR = 2; handles.ID_BL = 3;
% Belt HSV (OpenCV scale), with padding
handles.BELT_HSV_LOW = [71, 139, 42];
handles.BELT_HSV_HIGH = [79, 238, 90];
handles.BELT_PAD = [3, 12, 12];
% Picking rules (OpenCV-like ranges)
handles.RED_HSV = struct('h', [0, 10; 170, 179], 's', [90, 255], 'v', [60, 255]);
handles.BLUE_HSV = struct('h', [100, 130], 's', [90, 255], 'v', [60, 255]);
handles.stats = struct('red', 0, 'blue', 0, 'other', 0, 'total', 0);
% Create UI
createGUIComponents(hFig, handles);
disp('✅ Standalone Robot Control System Initialized');
% ================= GUI builder =================
function createGUIComponents(fig, h)
% Title
uicontrol('Parent', fig, 'Style', 'text', 'String', 'ROBOT CONTROL SYSTEM', ...
'Position', [400, 650, 400, 40], 'FontSize', 18, 'FontWeight', 'bold');
% Joint Sliders and Edit Boxes
yPos = 600;
slider_limits = [-180, 180; -180, 180; -180, 180; -180, 180; -180, 180; 0, 90];
for i = 1:6
uicontrol('Parent', fig, 'Style', 'text', ...
'String', sprintf('Joint %d:', i), ...
'Position', [50, yPos - (i-1)*80, 80, 20], ...
'HorizontalAlignment', 'right');
h.(['slider' num2str(i)]) = uicontrol('Parent', fig, 'Style', 'slider', ...
'Min', slider_limits(i,1), 'Max', slider_limits(i,2), ...
'Value', 0, ...
'Position', [150, yPos - (i-1)*80, 300, 20], ...
'Callback', @(src,evt)sliderCallback(i));
h.(['edit' num2str(i)]) = uicontrol('Parent', fig, 'Style', 'edit', ...
'String', '0', ...
'Position', [470, yPos - (i-1)*80, 60, 25], ...
'Callback', @(src,evt)editCallback(i));
end
% Position Display (X, Y, Z)
uicontrol('Parent', fig, 'Style', 'text', 'String', 'Position:', ...
'Position', [50, 80, 80, 20], 'FontWeight', 'bold');
uicontrol('Parent', fig, 'Style', 'text', 'String', 'X:', ...
'Position', [50, 50, 30, 20]);
h.edit7 = uicontrol('Parent', fig, 'Style', 'edit', 'String', '0', ...
'Position', [80, 50, 80, 25], 'Enable', 'off');
uicontrol('Parent', fig, 'Style', 'text', 'String', 'Y:', ...
'Position', [180, 50, 30, 20]);
h.edit8 = uicontrol('Parent', fig, 'Style', 'edit', 'String', '0', ...
'Position', [210, 50, 80, 25], 'Enable', 'off');
uicontrol('Parent', fig, 'Style', 'text', 'String', 'Z:', ...
'Position', [310, 50, 30, 20]);
h.edit9 = uicontrol('Parent', fig, 'Style', 'edit', 'String', '0', ...
'Position', [340, 50, 80, 25], 'Enable', 'off');
% Control Buttons (Right Panel)
btnX = 600;
uicontrol('Parent', fig, 'Style', 'pushbutton', 'String', 'PID', ...
'Position', [btnX, 600, 120, 50], ...
'Callback', @pidCallback);
uicontrol('Parent', fig, 'Style', 'pushbutton', 'String', 'RUN', ...
'Position', [btnX + 140, 600, 120, 50], ...
'Callback', @runCallback);
h.stopBtn = uicontrol('Parent', fig, 'Style', 'pushbutton', 'String', 'STOP', ...
'Position', [btnX + 280, 600, 120, 50], ...
'BackgroundColor', [1, 0.3, 0.3], ...
'Callback', @stopCallback);
uicontrol('Parent', fig, 'Style', 'pushbutton', 'String', 'DEFAULT', ...
'Position', [btnX, 540, 120, 50], ...
'Callback', @defaultCallback);
uicontrol('Parent', fig, 'Style', 'pushbutton', 'String', 'GRAPH', ...
'Position', [btnX + 140, 540, 120, 50], ...
'Callback', @graphCallback);
h.toggleAuto = uicontrol('Parent', fig, 'Style', 'togglebutton', 'String', 'AUTO', ...
'Position', [btnX + 280, 540, 120, 50], ...
'BackgroundColor', [0.4, 1, 0.4], ...
'Callback', @autoCallback);
% Vision System Section
uicontrol('Parent', fig, 'Style', 'text', 'String', 'VISION SYSTEM', ...
'Position', [btnX, 480, 420, 30], ...
'FontSize', 14, 'FontWeight', 'bold', ...
'BackgroundColor', [0.9, 0.9, 1]);
h.visionBtn = uicontrol('Parent', fig, 'Style', 'pushbutton', ...
'String', 'START VISION', ...
'Position', [btnX, 430, 180, 40], ...
'Callback', @visionCallback);
uicontrol('Parent', fig, 'Style', 'pushbutton', ...
'String', 'MANUAL CALIBRATION', ...
'Position', [btnX + 200, 430, 220, 40], ...
'Callback', @manualCalibCallback);
uicontrol('Parent', fig, 'Style', 'pushbutton', ...
'String', 'RESET CALIBRATION', ...
'Position', [btnX, 380, 180, 40], ...
'Callback', @resetCalibCallback);
uicontrol('Parent', fig, 'Style', 'pushbutton', ...
'String', 'SAVE DATA', ...
'Position', [btnX + 200, 380, 220, 40], ...
'Callback', @saveDataCallback);
uicontrol('Parent', fig, 'Style', 'pushbutton', ...
'String', 'STATISTICS', ...
'Position', [btnX, 330, 180, 40], ...
'Callback', @statsCallback);
uicontrol('Parent', fig, 'Style', 'pushbutton', ...
'String', 'ADJUST HSV', ...
'Position', [btnX + 200, 330, 220, 40], ...
'Callback', @hsvCallback);
h.statusText = uicontrol('Parent', fig, 'Style', 'text', ...
'String', 'NOT CALIBRATED', ...
'Position', [btnX, 270, 420, 40], ...
'FontSize', 12, 'FontWeight', 'bold', ...
'BackgroundColor', [1, 0.9, 0.9]);
h.statsText = uicontrol('Parent', fig, 'Style', 'text', ...
'String', 'RED: 0 | BLUE: 0 | OTHER: 0', ...
'Position', [btnX, 230, 420, 30], ...
'FontSize', 10);
h.toggleVisionAuto = uicontrol('Parent', fig, 'Style', 'togglebutton', ...
'String', 'VISION-GUIDED PICK AND PLACE', ...
'Position', [btnX, 170, 420, 50], ...
'FontSize', 11, 'FontWeight', 'bold', ...
'BackgroundColor', [0.4, 0.8, 1], ...
'Callback', @visionAutoCallback);
guidata(fig, h);
end
% ================= SLIDER/EDIT callbacks =================
function sliderCallback(jointNum)
h = guidata(gcf);
val = get(h.(['slider' num2str(jointNum)]), 'Value');
set(h.(['edit' num2str(jointNum)]), 'String', num2str(val, '%.2f'));
updateRobot();
end
function editCallback(jointNum)
h = guidata(gcf);
val = str2double(get(h.(['edit' num2str(jointNum)]), 'String'));
if ~isnan(val)
slider = h.(['slider' num2str(jointNum)]);
minVal = get(slider, 'Min');
maxVal = get(slider, 'Max');
val = max(min(val, maxVal), minVal);
set(slider, 'Value', val);
updateRobot();
end
end
% ================= Robot update / FK / Simulink / UDP =================
function updateRobot()
h = guidata(gcf);
angles = zeros(1, 6);
for i = 1:6
angles(i) = get(h.(['slider' num2str(i)]), 'Value');
end
% FK (DH)
T = forwardKinematics(angles);
set(h.edit7, 'String', num2str(T(1,4), '%.2f'));
set(h.edit8, 'String', num2str(T(2,4), '%.2f'));
set(h.edit9, 'String', num2str(T(3,4), '%.2f'));
% Simulink + RPi
updateSimulink(h, fliplr(angles));
sendToRPi(h, angles);
end
function T = forwardKinematics(angles)
d = [450, 0, 0, 0, 0, 0];
a = [0, 420, 380, 250, 150, 120];
alpha = [90, 0, 0, 90, 0, 0];
T = eye(4);
for i = 1:6
T = T * dhMatrix(angles(i), d(i), a(i), alpha(i));
end
end
function A = dhMatrix(theta, d, a, alpha)
A = [cosd(theta), -sind(theta)*cosd(alpha), sind(theta)*sind(alpha), a*cosd(theta);
sind(theta), cosd(theta)*cosd(alpha), -cosd(theta)*sind(alpha), a*sind(theta);
0, sind(alpha), cosd(alpha), d;
0, 0, 0, 1];
end
function updateSimulink(h, angles)
try
for i = 1:5
block_path = [h.ModelName, '/slider', num2str(i)];
set_param(block_path, 'Gain', num2str(angles(i)));
end
set_param(h.ModelName, 'SimulationCommand', 'update');
catch
% Silently ignore if model not available
end
end
function sendToRPi(h, angles)
try
if ~isempty(h.udpObj)
msg = sprintf('%f,%f,%f,%f,%f,%f', angles);
write(h.udpObj, uint8(msg), "uint8", h.RPi_IP, h.RPi_Port);
% disp(['Sent: ', msg]);
end
catch
end
end
% ================= Top buttons =================
function pidCallback(~, ~)
t = linspace(0, 5, 500);
responses = {
1 - exp(-2*t) .* cos(4*t),
1 - exp(-2.5*t) .* cos(3*t),
1 - exp(-3*t) .* cos(2*t),
1 - exp(-2*t) .* cos(5*t),
1 - exp(-2.2*t) .* cos(3.5*t),
1 - exp(-1.5*t) .* cos(6*t)
};
figure('Name', 'Motor Responses', 'NumberTitle', 'off');
hold on;
for i = 1:6
plot(t, responses{i}, 'DisplayName', ['Motor ' num2str(i)], 'LineWidth', 2);
end
xlabel('Time (s)'); ylabel('Output');
title('Motor Step Responses');
legend('show'); grid on;
end
function runCallback(~, ~)
h = guidata(gcf);
try
open_system(h.ModelName);
set_param(h.ModelName, 'SimulationCommand', 'Start');
disp('Simulation started');
catch ME
errordlg(['Error: ', ME.message]);
end
end
function stopCallback(~, ~)
h = guidata(gcf);
try
set_param(h.ModelName, 'SimulationCommand', 'stop');
catch
end
h.toggleLoop = false;
h.visionLoopActive = false;
set(h.toggleAuto, 'Value', 0);
set(h.toggleVisionAuto, 'Value', 0);
guidata(gcf, h);
disp('🛑 STOP - All operations halted');
end
function defaultCallback(~, ~)
h = guidata(gcf);
for i = 1:6
set(h.(['slider' num2str(i)]), 'Value', 0);
set(h.(['edit' num2str(i)]), 'String', '0');
end
updateRobot();
disp('Reset to default');
end
function graphCallback(~, ~)
figure('Name', 'PID Tuning', 'NumberTitle', 'off');
h_line = animatedline('Color', 'b', 'LineWidth', 2);
r_line = animatedline('Color', 'r', 'LineStyle', '--');
xlabel('Time'); ylabel('Output');
title('Adam-Optimized PID'); legend('Response','Setpoint'); grid on;
Kp = 1.0; Ki = 0.1; Kd = 0.05; setpoint = 50; measured = 0; integral = 0; prev_err = 0;
for t = 1:100
err = setpoint - measured;
integral = integral + err * 0.1;
deriv = (err - prev_err) / 0.1;
output = Kp*err + Ki*integral + Kd*deriv;
output = max(min(output, 100), -100);
measured = measured + 0.2*(output - measured) + 0.05*randn();
addpoints(h_line, t, measured); addpoints(r_line, t, setpoint); drawnow;
prev_err = err; pause(0.1);
end
fprintf('Final PID: Kp=%.3f, Ki=%.3f, Kd=%.3f\n', Kp, Ki, Kd);
end
% ================= Auto sequence =================
function autoCallback(src, ~)
h = guidata(gcf);
h.toggleLoop = get(src, 'Value');
guidata(gcf, h);
if h.toggleLoop
disp('Auto pick-place started');
runAutoLoop();
end
end
function runAutoLoop()
h = guidata(gcf);
sequence = {
[34, 0, -53, -49, 0, 0],
[34, 0, -53, -49, 0, 79],
[34, 0, -42, -39, 0, 79],
[23, 0, -42, -39, 0, 79],
[4, 0, -42, -39, 0, 79],
[4, 0, -47, -49, 0, 79],
[4, 0, -47, -49, 0, 0],
[25, 0, -36, -49, 0, 0]
};
while h.toggleLoop
for s = 1:length(sequence)
for i = 1:6
set(h.(['slider' num2str(i)]), 'Value', sequence{s}(i));
set(h.(['edit' num2str(i)]), 'String', num2str(sequence{s}(i)));
end
updateRobot(); pause(1.5);
h = guidata(gcf);
if ~h.toggleLoop, return; end
end
end
end
% ================= Vision start/stop & loop =================
function visionCallback(src, ~)
h = guidata(gcf);
if ~h.visionActive
try
h.cam = webcam(h.CAM_INDEX);
h.cam.Resolution = sprintf('%dx%d', h.CAM_WIDTH, h.CAM_HEIGHT);
h.visionActive = true;
set(src, 'String', 'STOP VISION', 'BackgroundColor', [1, 0.3, 0.3]);
guidata(gcf, h);
h.figVision = figure('Name', 'Vision System', 'NumberTitle', 'off');
disp('🎥 Vision started');
runVisionLoop();
catch ME
errordlg(['Vision error: ', ME.message]);
h.visionActive = false;
guidata(gcf, h);
end
else
h.visionActive = false;
set(src, 'String', 'START VISION', 'BackgroundColor', [0.94, 0.94, 0.94]);
guidata(gcf, h);
end
end
function runVisionLoop()
h = guidata(gcf);
while h.visionActive && ishandle(h.figVision)
try
disp('=== Vision loop iteration start ===');
frame = snapshot(h.cam);
% If calibrated, warp to top-down belt canvas (meters-to-pixels known)
if h.calibrated && ~isempty(h.H_rect)
top = imwarp(frame, h.H_rect, 'OutputView', imref2d([h.OUT_H h.OUT_W]));
else
top = frame;
end
% --- BELT MASK from fixed HSV (in OpenCV scale; we convert) ---
if h.calibrated
mask_belt = hsvMask_openCV(top, h.BELT_HSV_LOW, h.BELT_HSV_HIGH, h.BELT_PAD);
else
% If not calibrated, skip belt removal to avoid false "not belt"
mask_belt = false(size(top,1), size(top,2));
end
% Objects = NOT belt
obj_mask = ~mask_belt;
obj_mask = imopen(obj_mask, strel('disk',3));
obj_mask = imclose(obj_mask, strel('disk',5));
% Find blobs
disp('Finding blobs...');
CC = bwconncomp(obj_mask);
S = regionprops(CC,'Area','BoundingBox','Centroid','Orientation','PixelIdxList');
disp(['Found ' num2str(numel(S)) ' blobs']);
detections = struct('x',{},'y',{},'yaw',{},'width',{},'cat',{},'pick',{});
imshow(top); title('Top-down (if calibrated)'); hold on;
disp('Processing blobs...');
for i = 1:numel(S)
if S(i).Area < h.MIN_AREA_PX, continue; end
disp([' Processing blob ' num2str(i)]);
bb = S(i).BoundingBox;
cx = S(i).Centroid(1); cy = S(i).Centroid(2);
angle = S(i).Orientation; % deg, MATLAB convention
patch = imcrop(top, bb);
% Mean HSV in OpenCV-like ranges (H:0..179, S/V:0..255)
m = squeeze(mean(reshape(rgb2hsv(patch),[],3),1));
meanHSV = [m(1)*179, m(2)*255, m(3)*255];
% Classify RED/BLUE/OTHER (pick RED only)
disp([' Classifying HSV: ' num2str(meanHSV)]);
[category, pick] = classifyHSV_rules(meanHSV, h.RED_HSV, h.BLUE_HSV);
disp([' Category: ' char(category) ', Pick: ' num2str(pick)]);
% Size (width) in meters using calibration scale
if h.calibrated
width_m = bb(3) / h.px_per_m_x;
x_belt = cx / h.px_per_m_x;
y_belt = cy / h.px_per_m_y;
else
width_m = NaN; x_belt = NaN; y_belt = NaN;
end
detections(end+1) = struct('x',x_belt,'y',y_belt,...
'yaw',angle,'width',width_m,'cat',string(category),...
'pick',logical(pick));
disp([' Added detection. Total: ' num2str(numel(detections))]);
% Draw
col = [0 165 255]/255; % default (OTHER)
if strcmp(category,"RED"), col = [1 0 0]; end
if strcmp(category,"BLUE"), col = [0 0 1]; end
rectangle('Position',bb,'EdgeColor',col,'LineWidth',2);
plot(cx,cy,'r.','MarkerSize',15);
% heading arrow
vlen = 35;
vx = cx + vlen*cosd(angle); vy = cy - vlen*sind(angle);
line([cx vx],[cy vy],'Color',[0 0 1],'LineWidth',2);
% Label
if h.calibrated
txt = sprintf('%s %s | w=%.1fmm | (%.3f,%.3f)m',...
tern(pick,'PICK','NO-PICK'), char(category), width_m*1000, x_belt,y_belt);
else
txt = sprintf('%s %s | w~px=%.0f', tern(pick,'PICK','NO-PICK'), char(category), bb(3));
end
text(bb(1), bb(2)-8, txt, 'Color','w','FontSize',9,'FontWeight','bold',...
'BackgroundColor','k');
end
hold off; drawnow;
disp('Drawing complete');
% Update stats
disp('Updating stats...');
reds = 0; blues = 0; others = 0;
if ~isempty(detections)
for idx = 1:numel(detections)
if strcmp(detections(idx).cat, 'RED')
reds = reds + 1;
elseif strcmp(detections(idx).cat, 'BLUE')
blues = blues + 1;
else
others = others + 1;
end
end
end
h.stats.red = h.stats.red + reds;
h.stats.blue = h.stats.blue + blues;
h.stats.other = h.stats.other + others;
h.stats.total = h.stats.total + numel(detections);
set(h.statsText,'String',sprintf('RED: %d | BLUE: %d | OTHER: %d', ...
h.stats.red, h.stats.blue, h.stats.other));
disp('Stats updated');
% Cache detections for automation/save
disp(['Caching ' num2str(numel(detections)) ' detections']);
h.detected_objects = detections;
guidata(gcf, h);
pause(0.03);
disp('=== Vision loop iteration end ===');
catch ME
fprintf('❌ Vision loop error at: %s\n', ME.message);
fprintf(' Stack trace:\n');
for k = 1:length(ME.stack)
fprintf(' Line %d in %s\n', ME.stack(k).line, ME.stack(k).name);
end
break;
end
h = guidata(gcf);
end
if ~isempty(h.cam)
try, clear h.cam; catch, end
end
h.visionActive = false;
guidata(gcf, h);
end
% ================= Calibration / save / stats =================
function manualCalibCallback(~, ~)
h = guidata(gcf);
if isempty(h.cam)
warndlg('Start Vision first!'); return;
end
frm = snapshot(h.cam);
f = figure('Name','Manual Belt Calibration'); imshow(frm);
title('Click TL → TR → BR → BL on BELT corners'); hold on;
try
[x,y] = ginput(4);
catch
close(f); return;
end
close(f);
if numel(x) ~= 4
warndlg('Need 4 points (TL,TR,BR,BL).'); return;
end
src = [x y]; % image px (TL,TR,BR,BL)
% Create a rectangular canvas in pixels that represents belt meters
OUT_W = 900;
OUT_H = round(OUT_W * (h.BELT_HEIGHT_M / h.BELT_WIDTH_M));
dst = [0 0; OUT_W-1 0; OUT_W-1 OUT_H-1; 0 OUT_H-1]; % TL,TR,BR,BL in px
try
tform = fitgeotrans(src, dst, 'projective'); % image -> topdown px
catch ME
errordlg(['Calibration failed: ',ME.message]); return;
end
h.H_rect = tform;
h.OUT_W = OUT_W; h.OUT_H = OUT_H;
h.px_per_m_x = OUT_W / h.BELT_WIDTH_M;
h.px_per_m_y = OUT_H / h.BELT_HEIGHT_M;
h.calibrated = true;
set(h.statusText, 'String', 'CALIBRATED', 'BackgroundColor', [0.8, 1.0, 0.8]);
guidata(gcf, h);
msgbox('Calibration complete ✔','Success');
end
function resetCalibCallback(~, ~)
h = guidata(gcf);
h.calibrated = false; h.H_rect = [];
h.OUT_W = []; h.OUT_H = []; h.px_per_m_x = []; h.px_per_m_y = [];
set(h.statusText, 'String', 'NOT CALIBRATED','BackgroundColor',[1 0.9 0.9]);
guidata(gcf, h);
disp('Calibration reset');
end
function saveDataCallback(~, ~)
h = guidata(gcf);
if ~isempty(h.detected_objects)
filename = ['data_' datestr(now, 'yyyymmdd_HHMMSS') '.mat'];
detected_objects = h.detected_objects;
save(filename, 'detected_objects');
msgbox(['Saved: ' filename], 'Success');
else
warndlg('No data to save');
end
end
function statsCallback(~, ~)
h = guidata(gcf);
msg = sprintf('RED: %d\nBLUE: %d\nOTHER: %d\nTOTAL: %d', ...
h.stats.red, h.stats.blue, h.stats.other, h.stats.total);
msgbox(msg, 'Statistics');
end
function hsvCallback(~, ~)
msgbox('HSV is using fixed belt mask + RED/BLUE rules defined in code. Adjust BELT_HSV_* and rules if needed.','Info');
end
% ================= Vision-guided toggle (placeholder) =================
function visionAutoCallback(src, ~)
h = guidata(gcf);
h.visionLoopActive = get(src, 'Value');
guidata(gcf, h);
if h.visionLoopActive
if ~h.visionActive
warndlg('Start Vision System first!');
set(src, 'Value', 0);
h.visionLoopActive = false;
guidata(gcf, h);
return;
end
disp('🤖 Vision-guided automation started (hook trajectory here).');
end
end
% ================= Close GUI =================
function closeGUI(~, ~)
h = guidata(gcf);
h.toggleLoop = false;
h.visionLoopActive = false;
h.visionActive = false;
if ~isempty(h.cam)
try, clear h.cam; catch, end
end
delete(gcf);
end
% ======================= Helpers (vision) =======================
% Belt mask from OpenCV-like HSV bounds + padding; input RGB image
function mask = hsvMask_openCV(rgb, lo, hi, pad)
if nargin<4, pad = [0 0 0]; end
hsv = rgb2hsv(rgb);
H = hsv(:,:,1) * 179; S = hsv(:,:,2) * 255; V = hsv(:,:,3) * 255;
hlo = max(lo(1)-pad(1),0); hhi = min(hi(1)+pad(1),179);
slo = max(lo(2)-pad(2),0); shi = min(hi(2)+pad(2),255);
vlo = max(lo(3)-pad(3),0); vhi = min(hi(3)+pad(3),255);
if hlo <= hhi
mh = (H>=hlo) & (H<=hhi);
else
mh = (H>=hlo) | (H<=hhi); % hue wrap
end
ms = (S>=slo) & (S<=shi);
mv = (V>=vlo) & (V<=vhi);
mask = mh & ms & mv;
mask = imopen(mask, strel('disk',3));
mask = imclose(mask, strel('disk',5));
end
% Classify mean HSV (OpenCV-like values) -> {"RED","BLUE","OTHER"}, and pick flag
function [category, pick] = classifyHSV_rules(meanHSV, RED_RULE, BLUE_RULE)
category = "OTHER"; pick = false;
H = meanHSV(1); S = meanHSV(2); V = meanHSV(3);
% helper to test one rule
function ok = testRule(H,S,V, R)
ok = false;
if S < R.s(1) || S > R.s(2) || V < R.v(1) || V > R.v(2), return; end
hr = R.h; % one or two rows
if size(hr,1)==1, hr = [hr; hr]; end
for ii=1:size(hr,1)
lo = hr(ii,1); hi = hr(ii,2);
if (lo<=hi && H>=lo && H<=hi) || (lo>hi && (H>=lo || H<=hi))
ok = true; return;
end
end
end
if testRule(H,S,V, RED_RULE), category="RED"; pick = true; return; end
if testRule(H,S,V, BLUE_RULE), category="BLUE"; pick = false; return; end
end
% Ternary helper for labeling
function s = tern(cond, a, b)
if cond
s=a;
else
s=b;
end
end
end
5 Comments
Stephen23
on 10 Oct 2025 at 4:52
Nicely written code, but there are still a few places where it could be tighter code, which would reduce the likelihood of such bugs and make it easier to debug this yourself:
- Replace all guidata(gcf) with guidata(hFig). Avoid GCF, GCA, etc if you want to write robust GUIs.
- Make your code simpler by using an array of handles, rather than awkwardly forcing numbers into fieldnames. I.e. replace h.(['slider' num2str(i)]) with the simpler and more efficient h.slider(i).
- Ditto for h.edit.
- Preallocate the object arrays using GOBJECTS.
- Get rid of GUIDATA completely. You don't need it. You already wrote nested functions, so you can simply refer to the data in the parent workspace. It will work fine, nested functions are by far the best way to pass data around GUI callbacks: https://www.mathworks.com/help/matlab/creating_guis/share-data-among-callbacks.html#bt9p4s2
- Then you could get rid of HANDLES too.
- Most likely setting ENABLE or VISIBLE property would be cleaner than changing the background color.
- Replace magic numbers with named constants, e.g.:
NUM_JOINTS = 6;
VISION_PAUSE_SEC = 0.03;
MIN_CALIBRATION_POINTS = 4;
DEFAULT_JOINT_ANGLE = 0;
Answers (1)
Walter Roberson
on 10 Oct 2025 at 2:56
h.figVision = figure('Name', 'Vision System', 'NumberTitle', 'off');
You are creating a new figure.
function runVisionLoop()
h = guidata(gcf);
The current figure defaults to the most recently created figure (unless you change the active figure or unless the most recently created figure was created with visibility off or handle visibility off). But that recently created figure does not have any associated gui data...
0 Comments
See Also
Categories
Find more on Image Data in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!