MATLAB help

Ok so with my polariser project… where i’m using two servos to rotate 2 polarisers to create the desired orientation of polarisation i’m trying to use matlab to control it.

I’m a bit of a noob when it comes to programming so some help would be great :slight_smile:

this is the code i’m using to control the servos in pololu mode.

port = 'COM3'; 

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); 
fwrite(ser1, [128, 1, 4, 7, a, b]);
fwrite(ser1, [128, 1, 4, 6, c, d]);


fclose(ser1); 
delete(ser1);

now for my question…
how do i make it so that if i wanted to position a servo to 3000 i could simply define a single variable instead of defining a=30 and b=00?

thanks in advance :slight_smile:

Oh, its worse than that, for Pololu mode you can’t just split the number in half, you have to split it into it’s low seven bytes and its high six bytes. So basically:

Dec: 3000 = Bin 101110111000

a=0b00010111
b=0b00111000

I haven’t played with bitwise logic in Matlab before, but I’ll take a look this afternoon.

-Adam

I just discovered two nice new (to me) functions in Matlab, bitget() and binvec2dec(). You can use bitget to create an array out of your selection of the binary bits of a number, then binvec2ec to turn just those bits back into a number.

So, if your position command is X (500<=X<=5500), using your variables of a for the high byte and b for the low byte:

a=binvec2dec(bitget(x,8:13)); b=binvec2dec(bitget(x,1:7));
And you should be set. Technically you could say bitget(x,8:16) for a (or bitget(x,8:infinity)), but since 5500 is the highest number you’re expecting, and its binary representation has 13 bits, 8:13 is sufficient.

Gotta run to class now, but I’ll check if the whole thing outputs right when I get back.

-Adam

Works like a charm. I made it into an m-file “moveServo.m” which you can call as a function:

function moveServo(s,x)
%moveServo(s,x) for Pololu serial servo controllers, using Pololu mode
%(remember to remove the blue mode-selection jumper!) absolute position
%command #4. You may need to edit the port variable in this file to match
%your com port.
%
%s=servo number
%x=absolute position, 500<=x<=5500

port = 'COM3';%Edit to your com port number

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);
fwrite(ser1, [128, 1, 4, s, binvec2dec(bitget(x,8:13)), binvec2dec(bitget(x,1:7))]);

fclose(ser1);
delete(ser1);

Or you can download the m-file here.

There’s quite a delay (~.25 seconds) between issuing the command and the servo moving, I’m guessing it’s the com-port opening/closing bits. You could always move those out of the function and only call them once at the beginning and end of your work.

So, what servos did you end up getting?

-Adam

Thanks Adam,

You are always so very quick and helpful :slight_smile:

i tried out several servos… first of all some cheapo ‘micro’ no-brand servos and they could only do about ~130 degrees then i tried a hitec hs-55 which could do 180degrees + but in a really strange way, it works normally for about 160 degrees then for the last 30 or so degrees until the end stop the deadband seems to increase (i think the pot isn’t very good at the periphery) so even changing the position value by about 10 drives the servo the remaining 30 degrees and remains insensitive to numbers inbetween. So i just ended up with hitec hs-311’s for now… i’ll try to explore other micro sized servos later i guess.

i’m sure there will be more questions to come but thanks again so far :slight_smile:

Ok time for another question :slight_smile:

so with this part of the above code

fopen(ser1); 
fwrite(ser1, [128, 1, 4, s, binvec2dec(bitget(x,8:13)), binvec2dec(bitget(x,1:7))]);

I have made the neccessary equations so that i can specify an angle and amount of polarisation which translates to get a value ‘x’ which is in the range of 500 to 5500 the problem is that x is too exact and will be 3234.234432 or some other non-integer. I thought about using ‘round(x)’ to get ‘x’ to the nearest whole number but is there a better way in matlab to somehow cast x as an integer?

The short answer is that I would either wrap x in a round function both places it appears in the output line, or put “x=round(x)” just above it.

Matlab is really flaky with the data types, so I try not to use them. When you assign a value to x, you can implicitly cast it as an integer with some initial value like this: x=uint16(17.3)

Then when you do math with x, the result will always be an integer. The type is overridden the next time you assign a value to x, like say, x=17.3.

The u in uint is for unsigned, which x has to be for bitget to work. For some reason though, the vector returned by bitget then has an extra bit at the end, and isn’t recognized by binvec2dec as a binary vector (which it still is)!

So the short answer is that Matlab is crazy! It will apply bitget to a non-specific floating point type number if it happens to be an integer, but not to a signed integer type number, even when it happens to be positive. CRAZY! Yeah, just use round.

I was about to post a question about this, but apparently there are more of us out there using MATLAB with the Pololu controllers!

Thanks for posting this, Adam. Saved me a bunch of trial and error work!

Oh, one thing to note: the binvec2dec() function is in the DAQ toolbox.

~Sharad

Thanks to Adam, I’ve been able to position the servos in MATLA using the absolute positioning. However, what if I want to use the 7-bit (command 2) or 8-bit (command 3) settings?

I’ve been trying code like this, but it’s not working quite as I’d expect (code fragment below)

any ideas?

Many thanks,
Sharad


% specify position and range values
pos = 2000;
range = 15;

% set up the settings byte
bvec = bitget(0, 1:8);
bvec(1) = 0;
bvec(2) = 1;
bvec(3) = 0;
bvec(4:8) = bitget(range, 1:5);
rdata1 = binvec2dec(bvec)
fwrite(serobj, [128, 1, 0, 0, rdata1]);

% now set the position
pbin1 = bitget(pos, 8)
pbin2 = bitget(pos, 1:7)
pdata1 = binvec2dec(pbin1)
pdata2 = binvec2dec(pbin2)
fwrite(serobj, [128, 1, 3, 0, data1, data2])

Hello,

Why do you want to use the 7-bit and 8-bit commands? Those are intended for microcontrollers with limited processing power; when using a PC, your should use absolute mode and internally do remapping for neutral and range.

- Jan

Well, I was a little misguided in my thinking - I was thinking that if the range was reduced, I would get better positioning resolution. The real solution was to use a different motor, which seems to be working.

Thanks!

~Sharad

I am using your code in matlab as you have it posted.
I am using com 3. The board works with the pololu interface,
But when I run this code I get the error:
“Undefined function or method ‘binvec2dec’ for input arguments of type ‘double’”

Any one out there who can guide me towards success??

I had this problem at one stage as well, it’s been a while since i’ve played with this controller but I think the problem was that the value you perform binvec2dec on must be a whole number. I got around this by using the round function as in my posts above.

Hope that helps.

Thanks for the quick reply!
What I have done is taken the code posted up above, and made a .m file out of it and ran the file.
I then took your suggestion to make x a whole number using the round function.
Were are you getting / declaring your x?
If you have any old code saved that I could see I would greatly appreciate it.
You could email it to me as an attachment if that makes it any easier.
Thank you for the help!

No problems,

x is the variable I used to define the position of my servo and should be between 500 and 5500 (these are the values that the servo controller understands).

I derived my x from an equation declared earlier in the code to translate an amount ofpolarisation to a specific angle for the polarisers the servos were attached to.
Not really sure where i’ve put the code but I can try to find it.

If you describe your project here maybe we can point you in the right direction with your code.

Good luck :slight_smile: