Okay, I think I have this figured out now (I had to go swipe back my loaned-out webcam). I saw your other message too, and I’m sure you can run everything from inside Matlab.
The real mistake yesterday was that you were deleting the com port object after using it once, so the second time you went to use it, it was gone! Since you caught that error and closed/deleted the camera object, when your code tried to close the camera object again it wasn’t there. That second error was un-handled, so it’s the one that got printed out on the command line, but it wasn’t the source of the problem.
Basically you should only ever open an object at the beginning of when you want to use it, and close it when you’re all done. Opening/closing ports is very slow, and it can be a real coding headache.
Anyway, try this version of multiframe.m:
function [ ] = multiframe( old2, vid )
%attempts to track objects which move by using 3 discrete time frames.
%this uses the [1 -2 1] method for difference tracking
noerror = 1;
port = 'COM1';
ser1 = serial(port);
set(ser1, 'InputBufferSize', 2048);
set(ser1, 'BaudRate', 9600);
set(ser1, 'DataBits', 8);
set(ser1, 'Parity', 'none');
set(ser1, 'StopBits', 1);
[h w c] = size(old2);
leftthresh = .35 * w;
rightthresh = .65 * w;
upthresh = .45 * w;
downthresh = .55 * w;
trigger(vid);
old1 = getdata(vid,1);
i=1;
imax=100;%number of frames to record
fopen(ser1);
disp('ok');
while i<imax
try
i=i+1;
trigger(vid);
newI = getdata(vid,1);
diffimg = double(newI) - 2 * double(old1) + double(old2);
rdiff = diffimg(:,:,1); gdiff = diffimg(:,:,2); bdiff = diffimg(:,:,3);
movement = (rdiff > 50) | (gdiff > 50) | (bdiff > 50);
[y x] = find(movement);
avex = mean(x);
pavex = mean(y);
imshow(newI);
hold on;
plot(mean(x),mean(y),'g*');
hold off;
if (avex < leftthresh)
avex = round(avex);
high = binvec2dec(bitget(avex,8:13));
low = binvec2dec(bitget(avex,1:7));
fwrite(ser1, [128, 1, 4, 7, high, low]);
elseif (avex > rightthresh)
avex = round(avex);
high = binvec2dec(bitget(avex,8:13));
low = binvec2dec(bitget(avex,1:7));
fwrite(ser1, [128, 1, 4, 7, high, low]);
elseif (pavex < downthresh)
pavex = round(pavex);
high = binvec2dec(bitget(pavex,8:13));
low = binvec2dec(bitget(pavex,1:7));
fwrite(ser1, [128, 1, 4, 7, high, low]);
elseif (pavex > upthresh)
pavex = round(pavex);
high = binvec2dec(bitget(pavex,8:13));
low = binvec2dec(bitget(pavex,1:7));
fwrite(ser1, [128, 1, 4, 7, high, low]);
end
old2 = old1;
old1 = newI;
catch
lasterr
i=imax;
end
end
fclose(ser1);
delete(ser1);
stop(vid);
delete(vid);
I fixed a typo on the first line (it said multigrame, but still ran), but the real changes are that both the video camera object and the com port are only ever opened once, before the main while loop, and closed once after it. All the error handler does is dump out of the loop, so nothing is closed twice. I also changed the loop to exit after a set number of frames i, because I couldn’t find a nice way to exit the function.
So, this version of the code runs with no Matlab errors, but there is still a slight problem with it. Basically your code is taking the pixel coordinate and using that directly as the servo command, which isn’t going to do what you want.
First off, Pololu mode divides the servo’s range into units from 500 to 5500, and your pixel coordinates are always less than the width/height of the image, in your case 160x120, so they are ALWAYS out of range of the Pololu format. Second, as I’m sure you know, servo positions are absolute, not relative, so if you just feed it the pixel location, the servo will move in that direction, moving the target pixel in it’s image closer to the center of the image, causing the servo to move back to it’s center, moving the target pixel back to a side, etc… Actually it looks like your pixels are being addressed from one corner rather than the center.
So, what you really want to do is maintain some sort of separate servo position variables, and modify them with a little bump up/down/left/right. Something like:
servoposX=3000;
if(imageCenterX-targetPixelX>threshold)
servoposX=servoposX+bump;
if(servoposX>5500)
servoposX=5500;
end
fwrite(ser1, [128, 1, 4, 7, binvec2dec(bitget(servoposX,8:13)),binvec2dec(bitget(servoposX,1:7))]);
else if(imagecenterX-targetPixelX<-threshold)
servoposX=servoposX-bump;
if(servoposX<500)
servoposX=500;
end
fwrite(ser1, [128, 1, 4, 7, binvec2dec(bitget(servoposX,8:13)),binvec2dec(bitget(servoposX,1:7))]);
end
Something like that anyway.
So, how’s it working?
-Adam