Another Matlab Problem..Need help

hello all,

i’m new to pololu servo controller and tried using Pololu mode. I have problem when using code example from this thread:


What i want to do is grabbing a image from a camera, finding red blobs in the
image, then finding the centroid of the red blobs and putting a green
* at the centroid. Then it wil call servo to moveleft, moveright,mevedown and moveup to tell the
camera to aim itself in an attempt to put/keep the red blob(s)
centroid at the center of the image.

It only for unsigned integer, but my programming have signed integer. So i get this code when run the programming:

ans =

Error using ==> bitget
Inputs must be non-negative integers.

??? Reference to a cleared variable vid.

Error in ==> multiframe at 76
stop(vid);

Error in ==> activevision at 11
multiframe(background, vid); %track movement across 3 frames with [1 -2 1]

Here my Full programming
Download:
mihd.net/a9tvl4s

Or should i change to Mini SSC II Mode?

Yeah, Matlab handles data types and typecasting very badly. I’ve run into that problem before when I’m dealing with integer results of non-integer operations. What the function bitget really wants is not an unsigned integer, but rather a signed integer that happens to be positive (weird!).

Looking at your code, I’m not sure that the numbers you’re using are even necessarily integers, let alone positive. For example, in trackedge.m, you say “avex=mean(x)”, then “bitget(avex,8:13)”. In Matlab, the mean of integers isn’t necessarily an integer itself. Are you sure avex is what you want to use as your servo command?

Anyway, in these sorts of cases I usually throw in the “round” command, which outputs the proper kind of signed integer, and so long as it’s positive it will make the bitget command happy. If it’s between 500 and 5500, it will make your servo controller happy.

So, if X is your Pololu mode servo command (500<=X<=5500, but other than that it doesn’t even have to be an integer at this point) just throw in an:
X=round(x);
Before:
fwrite(ser,[128,1,4,servonumber,binvec2dec(bitget(x,8:13)),binvec2dec(bitget(x,1:7))]);

Does that do the trick?

-Adam

P.S. If you switched to MiniSSC-II mode you would still need to force your variables to be positive integers, and you would loose the extra precision and features!

i use avex = round(avex) and that solve the problem of integer, but the servo twist a little then stop. And this error come out:

ans =

Error using ==> serial.fopen
Instrument object OBJ is an invalid object.

??? Reference to a cleared variable vid.

Error in ==> multiframe at 80
stop(vid);

Is it i need to create device object? I have tried using this example and still cant work.
mathworks.com/access/helpdes … =firefox-a

I think you’re seeing yet another unfortunate Matlab bug. Can you post the full text of the current .m file that’s causing the current problem?

Matlab is very finicky with com port objects. For example, if errors occur while running a function after opening a com port, the function is halted and the port is never closed. The next time you run the function and it tries to open the port, it isn’t available and you get this sort of error. In Matlab R2008a you can close the port from the command line, but I’m not sure this is the case in previous versions.

-Adam

here the full text for current .m

function [ ] = multigrame( 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);

disp('ok');
while noerror
    try
        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));
            fopen(ser1);
            fwrite(ser1, [128, 1, 4, 7, high, low]);
            fclose(ser1);
            delete(ser1);
	    clear ser1
        elseif (avex > rightthresh)
            avex = round(avex);
            high = binvec2dec(bitget(avex,8:13));
            low = binvec2dec(bitget(avex,1:7));
            fopen(ser1);
            fwrite(ser1, [128, 1, 4, 7, high, low]);
            fclose(ser1);
            delete(ser1);
	    clear ser1
         elseif (pavex < downthresh)
            pavex = round(pavex);
            high = binvec2dec(bitget(pavex,8:13));
            low = binvec2dec(bitget(pavex,1:7));
            fopen(ser1);
            fwrite(ser1, [128, 1, 4, 7, high, low]);
            fclose(ser1);
            delete(ser1);
	    clear ser1
         elseif (pavex > upthresh)
            pavex = round(pavex);
            high = binvec2dec(bitget(pavex,8:13));
            low = binvec2dec(bitget(pavex,1:7));
            fopen(ser1);
            fwrite(ser1, [128, 1, 4, 7, high, low]);
            fclose(ser1);
            delete(ser1);
	    clear ser1
        end
        
        old2 = old1;
        old1 = newI;
    catch
        lasterr
        stop(vid);
        delete(vid);
        clear vid
        noerror = 0;
    end
end
stop(vid);
delete(vid);
clear vid

maybe your are right, port never closed. So i add one more command clear ser1 to make sure port really closed. And then now i got this answer:

ans =

Reference to a cleared variable ser1.

??? Reference to a cleared variable vid.

Error in ==> multiframe at 91
stop(vid);

Error in ==> activevision at 11
multiframe(background, vid); %track movement across 3 frames with [1 -2 1]

>>

now my head really dizzy :question: :question:

Is it my image processing programming have problem or serial port programming
have problem?

Anyone can help me?

Edit: i’m using Matlab 2007

The serial parts of this code look fine to me. Clearing ser1 isn’t really necessary, but if you have the time it doesn’t hurt. Actually if you wanted to really speed things up (once ALL the other errors are taken care of) you might try moving fopen(ser1) and fclose(ser1) outside your main while loop. You could even put fclose(ser1) in your error handler.

But getting back to your question, I don’t know why it mentions ser in the error message, but I think the error you’re seeing now is related to your error handling function. When you catch an error, your error handler runs:

stop(vid);
delete(vid);
clear vid
noerror=0;

But since the error has been handled, the function continues to execute. Since noerror is now zero, the while loop finishes, and the lines after the while loop run:

stop(vid);
delete(vid);
clear vid

But since there was an error, vid has already been cleared! I would try changing your error handling function to be only:

noerror = 0;

After an error, the lines after the while loop will still execute.

-Adam

doesnt work either. is there more way for me to control the servo?

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

WOW you really know about matlab. And you know actually what i tried to do in image processing. :open_mouth: Salute to you.

What you do in multiframe.m fix the error. But servo didnt really follow the green* at centroid then after few second program stop by itself. Is this happen because of Pololu Format? I don’t get what you mean by this code:

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

I tried to put something like this:

  if (imageCenterX-targetPixelX < leftthresh)
                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<-leftthresh)
   		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

but the end i get the error using “catch” Did i do at correct way? Is everything aright at your side?

Matlab, how I loath you, let me count the ways…

No, I didn’t actually try to run the second bit of example code I wrote up, but I see the mistake I made.

In Matlab “else if” should be one word, so change it to “elseif”.

The best part is that “else” and “if” are both reserved words, so when you write “else if” they turn blue in the m-file editor and look like they’re correct. Well, actually they are grammatically correct, but they won’t do what you expect or want since they’re not one statement. It gets me every time!

-Adam

I have notice that before. For right threshold(rightthresh) should i start with if or elseif? It will give an error if start with elseif. If use if then at the end error for using catch . No way out.

Sorry, it sounds like you’re really close to getting this to work, but I don’t really understand what you mean in that last post. Maybe you could post your current code?

-Adam

Yes, only part pololu format left.

here new 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);
            servoposX=3000;
           
            imshow(newI);
            hold on;
            plot(mean(x),mean(y),'g*');
            hold off;
            if(imageCenterX-targetPixelX>leftthresh)
                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<-leftthresh)
                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
            if(imageCenterX-targetPixelX>rightthresh)
                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<-rightthresh)
                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
            if(imageCenterX-targetPixelX>downthresh)
                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<-downthresh)
                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
            if(imageCenterX-targetPixelX>upthresh)
                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<-upthresh)
                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
            end
           
            old2 = old1;
            old1 = newI;
        catch
            lasterr
            i=imax;
        end
    end
    fclose(ser1);
    delete(ser1);
    stop(vid);
    delete(vid);

when i run the program i get this error:
??? Error: File: C:\MATLAB7\work\Matlab2\multiframe.m Line: 104 Column: 9
Illegal use of reserved keyword “catch”.

In this code, all the “else if” statements should be “elseif” to work properly. Once you condense those, you’re left with an extra “end”. Once you get rid of that you should be good:

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);
			servoposX=3000;
		   
			imshow(newI);
			hold on;
			plot(mean(x),mean(y),'g*');
			hold off;
			if(imageCenterX-targetPixelX>leftthresh)
				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))]);
			elseif(imagecenterX-targetPixelX<-leftthresh)
				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

			if(imageCenterX-targetPixelX>rightthresh)
				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))]);
			elseif(imagecenterX-targetPixelX<-rightthresh)
				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
				
			if(imageCenterX-targetPixelX>downthresh)
				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))]);
			elseif(imagecenterX-targetPixelX<-downthresh)
				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
				
			if(imageCenterX-targetPixelX>upthresh)
				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))]);
			elseif(imagecenterX-targetPixelX<-upthresh)
				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

			old2 = old1;
			old1 = newI;
		catch
			lasterr
			i=imax;
		end
	end
	fclose(ser1);
	delete(ser1);
	stop(vid);
	delete(vid);

In case this wasn’t clear YOU need to assign values to imageCenterX (and you should have an ImageCenterY). They aren’t actual functions, I was just making up variable names that sounded like the values they should be assigned. Same goes for targetPixelX and targetPixelY. I think you want to use your avex and pavex values for these.

-Adam

lol, i thought that you change it all. ok i will look for the code again. Already 5.30a,m here, time gap i need to wait your reply earlier morning. :smiley: time to sleep. Hope i can get it right tomorrow. Thank Adam.

what i should define for bump?

This happen due to noise in the camera, much of the difference image is composed of small, uninteresting objects. This may cause significant errors when the function attempts to locate the center of the movement. All algorithm should run together(edge and colour) to eliminate the noise.

What I meant by pixels being addressed from a corner is that the pixel coordinate system that Matlab uses has it’s origin at a corner of the image, not the center. So, in a 160x120 image like you’re using now, the coordinates of the center pixel are (80,60). The position error of a target object in your image is the difference between that target’s pixel coordinates and the center pixel’s coordinates. That’s what this part of my pseudo-code was meant to handle:

if(imageCenterX-targetPixelX>threshold)

Woah, come to think of it, the more standard way to do that would be

if(targetPixelX-imageCenterX>threshold)

This way, if the target pixel you want to look at is (145,23), then the target pixel is 145-80=65 pixels from the center of the image. It will work either way, you just need to keep your directions straight one way or the other. I used a variable imageCenterX instead of just 80 because you may try images at different resolutions later.

The variable “bump” is how much you want to move a servo at any one time, and can be one of two things.

To start out, you probably want bump to be a small constant (small relative to the 5000 position range of the servo controller), lets say 100. Just thinking about the horizontal servo, if the target you want the camera to point at is left of center by more than your threshold, your code will bump the camera left a little and snap another frame (or multiple new frames if you’re doing motion tracking) to see where it is now. It should probably about equal to your threshold actually, so you’re sure not to overshoot the target in one move.

After you get that working, and any other problems like sign errors taken care of, you can start calculating bump each time you want to move the servos, based on where the target pixel is. Figure out how the ratio of servo units to camera pixels, lets call it horizontalK. Then, if the target pixel is x_error pixels from the center of the camera image, you want to turn the camera by bump=x_error*horizontalK. Then your camera should be pointing right at your target.

You’ll probably still want to have a threshold around the center so your camera isn’t twitchy all the time. And in general you might want to add delays to your code any time you command the servo controller so you don’t try to take another frame while the servo is still moving.

I hope all that helps!

-Adam

I follow all your advise, program seem send signal to servo controller( green light flash follow the moving object) but servo motor didnt move only green light flash. And after few second program stop run by itself green light off then yellow light come out. Look like matlab have disconnect communication with servo controller. Matlab need to restart again. I already try few method, change variable bump, use if(imageCenterX-targetPixelX>threshold) then change it again with if(targetPixelX-imageCenterX>threshold), I tried also to control only one servo in the end i got same result. One week i stuck at this part, programming code with no error but servo motor still didnt move follow the moving object. Adam help me a lots. Thank Adam. Anybody that know with image processing in matlab and familiar with Pololu mode please help me.

new 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);
            avex = round(avex);
            pavex = round(pavex);
            servoposX = 3000;
            bump = 100;
            
            imshow(newI);
            hold on;
            plot(mean(x),mean(y),'g*');
            hold off;
            if (avex - 80 < leftthresh)
                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))]);
                elseif(avex - 80 > - leftthresh)
                  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))]);
            elseif (avex - 80 > rightthresh)
               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))]);
               elseif(avex - 80 < - rightthresh)
                  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))]);
            elseif (pavex - 72 < downthresh)
               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))]);
               elseif(pavex - 72 > - downthresh)
                  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))]);
            elseif (pavex - 72 > upthresh)
               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))]);
               elseif(pavex - 72 < - upthresh)
                  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
           
            old2 = old1;
            old1 = newI;
        catch
            lasterr
            i=imax;
        end
    end
    fclose(ser1);
    delete(ser1);
    stop(vid);
    delete(vid);

You’re totally getting close here, and the green light blinking on your servo controller is a very good sign! I think I may have confused you a little though, so it’s time for another round of Matlab hacking.

The main problem with this version of the code is that you’re mixing two different coordinate frames/methods of error checking. I like how you calculate your thresholds, but if you’re going to establish them as pixel coordinates in the image, rather than distance from the center pixel, then you shouldn’t be subtracting the coordinates of the center pixel after all. You can do it one way or the other, but not both, so lets do it the way you were originally trying, since it makes more sense to you.

The second problem is that you’re checking way too many things, some of which don’t really make sense (the horizontal and vertical checks are all mixed together and duplicated, you always add bump and never subtract it). You should really only have two if/else cases for each frame:

If target is left of left threshold
move x-servo left (position=position-bump)
else if target is right of right threshold
move x-servo right (position=position+bump)
end

If target is above up threshold
move y-servo up (position=position-bump)
else if target is below down threshold
move y-servo down (position=position+bump)
end

I’m guessing at directions here, but you’ll have to work that out for your setup.

Another problem is that you give the servo position variable it’s initial value inside your loop, so position changes (bumps) can’t accumulate over multiple frames. You should assign your servo variables their starting position once, outside the main loop.

Finally, all your position commands are being sent to servo number 7, and I know you have two servos, but I’m not sure where they’re plugged in to the servo controller. I added two variables for the servo numbers, servoX and servoY. I’m assuming that servoX is plugged into the pins for servo nubmer 0, and servoY is plugged into the pins for servo number 1, so you may need to change that part of the code, or move your servo plugs. Also, to protect your servos from running into their mechanical stops, I added two new variables positionMin and positionMax. If you decide you want to later, you can reduce positionMin down to 500 and set positionMax up to 5500, but these are good limits to start with.

So, putting all these changes together, your code would look something like this:

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;

servoX=0;%PUT YOUR SERVO NUMBERS HERE
servoY=1;%AND HERE

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;
servoposX = 3000;
servoposY = 3000;
bump = 100;
positionMin=2000;
positionMax=4000;

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);
		avex = round(avex);
		pavex = round(pavex);

		imshow(newI);
		hold on;
		plot(mean(x),mean(y),'g*');
		hold off;
		if (avex < leftthresh)
			servoposX = servoposX - bump;
			if(servoposX < positionMin)
				servoposX = positionMin;
			end
			fwrite(ser1, [128, 1, 4, servoX, binvec2dec(bitget(servoposX,8:13)),binvec2dec(bitget(servoposX,1:7))]);
		elseif (avex > rightthresh)
			servoposX = servoposX + bump;
			if(servoposX > positionMax)
				servoposX = positionMax;
			end
			fwrite(ser1, [128, 1, 4, servoX, binvec2dec(bitget(servoposX,8:13)),binvec2dec(bitget(servoposX,1:7))]);
		end
		

		if (pavex < upthresh)
			servoposY = servoposY - bump;
			if(servoposY < positionMin)
				servoposY = positionMin;
			end
			fwrite(ser1, [128, 1, 4, servoY, binvec2dec(bitget(servoposY,8:13)),binvec2dec(bitget(servoposY,1:7))]);
		elseif(pavex > downthresh)
			servoposY = servoposY + bump;
			if(servoposY > positionMax)
				servoposY = positionMax;
			end
			fwrite(ser1, [128, 1, 4, servoY, binvec2dec(bitget(servoposY,8:13)),binvec2dec(bitget(servoposY,1:7))]);
		end

		old2 = old1;
		old1 = newI;
	catch
		lasterr
		i=imax;
	end
end
fclose(ser1);
delete(ser1);
stop(vid);
delete(vid);

The previous version of your code was sending position commands to servo number 7. What plug was your servo connected to? What are you using as a power source for your servos? Your code is sending out proper control bytes, so you should see some movement if the servos are powered and plugged in to the correct pins.

I know you’re running into a lot of trouble, but I bet you can get this working. Your motion tracking program seems to work very well, and I would have thought of that as the hard part!

-Adam

Ooops for previous multiframe.m i forgot to edit servo number for up and down. I use servo number 7 and 6. servo number 7 for horizontal axis and number 6 for vertical axis. power source use 9v at VIN-GND and 5v at servo power.

Your new version of multiframe running more better then before but the same issue
programming will stop just after few second, video tracking stop and servo controller disconnect. Right now i just running programming for multiframe and not all complete programming code(edge and colour algorithm). Now i think this servo part is the hardest.

Already try this servo setup(same with the one you give me) before just after i bought Pololu servo controller.

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);
fopen(ser1);

pos=3000;

for(servoNum=0:7)
   fwrite(ser1, [128, 1, 4, servoNum, binvec2dec(bitget(pos,8:13)),binvec2dec(bitget(pos,1:7))]);
end

fclose(ser1);
delete(ser1);

Both servo go to and hold its center position. Im also try another servo command that i download from here and everything work. But all that servo command written in VB. i think servo setup is ok just now left hardest part at matlab serial communication. :frowning: