Controlling stepper motor using raspberry pi and Matlab - matlab

We are trying to rotate stepper motor (Nema23 57HS22-A) in specific number of steps using raspberry pi 3 and digital stepping driver DM556 using Matlab.
We managed to rotate the stepper motor in specific number of steps (3000 steps in this code) with the following python code:
Pin 29 is connected to the PUL+ of the DM556 which rotate the stepper motor every time it changes from 'LOW' to 'HIGH'.
Pin 31 is connected to DIR+ which decide the direction of the stepper motor's rotation.
Pin 32 is connected to ENA+ which enable the stepper motor at 'LOW'.
PUL-,DIR-,ENA- connected to GND (not in the code).
this code will rotate the stepper motor 3000 steps to one side and 3000 steps to the other side in endless loop.
Import RPi.GPIO as GPIO
Import time
GPIO.setmode(GPIO.BOARD)
GPIO.setup(29,GPIO.out) // GPIO 5
GPIO.setup(31,GPIO.out) // GPIO 6
GPIO.setup(32,GPIO.out) // GPIO 12
GPIO.output(32.GPIO.LOW)
While True:
GPIO.output(31,GPIO.HIGH)
For i in range(0,3000):
GPIO.output(29,GPIO.HIGH)
Time.sleep(0.0005)
GPIO.output(29,GPIO.LOW)
Time.sleep(0.0005)
GPIO.output(31,GPIO.LOW)
For i in range(0,3000):
GPIO.output(29,GPIO.HIGH)
Time.sleep(0.0005)
GPIO.output(29,GPIO.LOW)
Time.sleep(0.0005)
We try to convert this code to matlab and we wrote this code which didn't rotate the motor:
clear all; close all; clc;
rpi1 = raspi('192.168.67.187','pi','raspberry');
pul_x = 5;
dir_x = 6;
ena_x = 12;
configurePin(rpi1,pul_x,'DigitalOutput');
configurePin(rpi1,dir_x,'DigitalOutput');
configurePin(rpi1,ena_x,'DigitalOutput');
writeDigitalPin(rpi1,pul_x,1);
writeDigitalPin(rpi1,dir_x,0);
writeDigitalPin(rpi1,ena_x,0);
for i = 1:200
writeDigitalPin(rpi1,pul_x,1);
pause(0.001);
writeDigitalPin(rpi1,pul_x,0);
pause(0.001);
end
We succeed to rotate the stepper motor with this matlab code but without a specific number of steps:
clear all; close all; clc;
rpi1 = raspi('192.168.67.187','pi','raspberry');
pul_x = 5;
dir_x = 6;
ena_x = 12;
configurePin(rpi1,pul_x,'PWM');
configurePin(rpi1,dir_x,'DigitalOutput');
configurePin(rpi1,ena_x,'DigitalOutput');
writeDigitalPin(rpi1,dir_x,0);
writeDigitalPin(rpi1,ena_x,1);
writePWMDutyCycle(rpi1, pul_x, 0.5);
writePWMFrequency(rpi1, pul_x, 1000);
for i = 1:200
writeDigitalPin(rpi1,ena_x,0);
end
writeDigitalPin(rpi1,ena_x,1);
We trying to fix the 2nd code to make the stepper motor move, but we'll be glad to hear any other suggestion to rotate the stepper motor in specific number of steps.
Thanks in advance.
EDIT:
We found that the second code we posted actually works, but the problem is that the command writeDigitalPin takes too much time (20 msec) and therefor the stepper motor moving too slow to see.
Is there any other function or way to reduce the time in order to make the motor run faster?

To control a servo motor you can use servo obj and the writePosition() function available in Raspberry Pi supportpackage.
r = raspi;
servoControlPin = 29;
s = servo(r,servoControlPin);
for i = 1:3000
position = (180*i)/3000
writePosition(s,position);
end
Please refer the doc page of servo to know more about how to configure minimum/maximum pulse duration.

Related

Calculate acceleration from data points

I have a servo motor, and this servo motor I would like to make it follow a "motion pattern" as closely as possible, and use the same value for acceleration and deceleration.
The attach picture illustrates the "motion pattern" (Y = velocity, X = Time)
motion pattern:
accelerates 0m/s to 0.100m/s.
constant velocity 0.100m/s for 4 sec.
decelerates to negative ?m/s.
accelerates to 0m/s, and motor position = 0.
How can i calculate the acceleration and deceleration?
What i have tried so far is:
Time = (total time - constant velocity time) 10 - 4 = 6sec.
Distances = (total distances - constant velocity distances ) 1 - 0.4 = 0.6meter.
acceleration = (2 * distances / (time^2) 2 * 0.6 / sqr(6) = 0.0333m/s.
But with this acceleration it over shoots in the negative direction by 500mm.
Take a look at the PLC Open motion function blocks, for example the MC_MoveRelative and the MC_MoveContinuesRelative block:
(Beckhoff documentation)
As Sergey already stated you can use those blocks to create a motion profile by entering all the parameters you need and integrating the blocks in a step chain.

Control two servo motors simultaneously using raspberry pi

I am new to Raspberry pi. Currently I am doing a project and I am using raspberry pi 3 model B. My servos are SG90 micro servos. I want to run two servos simultaneously. And also in a way that they are synchronize. Up to now I have managed to run the two servo using 11 and 13 pins. Here is my current code
import RPi.GPIO as GPIO
import time
l = 0
r = 0
lServoPin = 11
rServoPin = 13
GPIO.setmode(GPIO.BOARD)
GPIO.setup(lServoPin, GPIO.OUT)
GPIO.setup(rServoPin, GPIO.OUT)
lPwm = GPIO.PWM(lServoPin, 50)
rPwm = GPIO.PWM(rServoPin, 50)
lPwm.start(5)
rPwm.start(5)
while(l < 5):
for i in range(45, 135):
position = 1./18.*(i)+2
lPwm.ChangeDutyCycle(position)
time.sleep(0.005)
for i in range(135, 45, -1):
position = 1./18.*(i)+2
lPwm.ChangeDutyCycle(position)
time.sleep(0.005)
l = l + 1
lPwm.stop()
while(r < 5):
for i in range(135, 45, -1):
position = 1./18.*(i)+2
rPwm.ChangeDutyCycle(position)
time.sleep(0.005)
for i in range(45, 135):
position = 1./18.*(i)+2
rPwm.ChangeDutyCycle(position)
time.sleep(0.005)
r = r + 1
rPwm.stop()
GPIO.cleanup()
Above code only run servos one after the other. What am I doing wrong here??
Could someone suggest me a way to run two synchronized servos simultaneously.
Thank you very much in advance!!!
What you're doing is, you're running 2 loops. 1 for left motor and 1 for right motor. If you want to run them together, you need to put both these motors in one loop.
Try this code:
x=0
while(x<5):
for i in range(45, 135):
positionl = 1./18.*(i)+2
positionr = 1./18.*(180-i)+2
lPwm.ChangeDutyCycle(positionl)
rPwm.ChangeDutyCycle(positionr)
time.sleep(0.005)
for i in range(135, 45, -1):
positionl = 1./18.*(i)+2
positionr = 1./18.*(180-i)+2
lPwm.ChangeDutyCycle(positionl)
rPwm.ChangeDutyCycle(positionr)
time.sleep(0.005)
x = x + 1
lPwm.stop()
rPwm.stop()
GPIO.cleanup()
Hope this helps

Flicker frequencies in PTB

I'm trying to present a 4Hz flickering stimuli in PsychToolbox for 5 seconds followed by a 500Hz tone. Does anyone have an idea of how to do this? I've been using the vbl or screen refresh rate to calculate the flicker frequency but I'm not sure if I'm on the right track at all. I also have no idea how to present an auditory stimuli in PTB (I tried the sound function already). Any help is greatly appreciated!
I'm not sure about sound presentation in PTB (I've never done it), but you seem to be on the right track for the flicker frequency.
The way I do it is to determine the screen refresh rate, divide the total length of time you want the stimulus presented by this refresh rate (this will give you the number of frames that will be drawn during this time), and then have a frame counter that increases by 1 after every flip. You can then use this frame counter to switch commands on or off.
A minimal example (randomly changes the background colour at 4Hz for 5 seconds):
[w, wRect]=Screen('OpenWindow', 0);
MaxTime = 5; %Set maximum time for all stimuli to be presented in seconds
Hz = 4; %Set Hz for stimulus flicker
Screen('Flip',w);
Frametime=Screen('GetFlipInterval',w); %Find refresh rate in seconds
FramesPerFull = round(5/Frametime); % Number of frames for all stimuli
FramesPerStim = round((1/Hz)/Frametime); %Number of frames for each stimulus
StartT = GetSecs; %Measure start time of session
Framecounter = 0; %Frame counter begins at 0
while 1
if Framecounter==FramesPerFull
break; %End session
end
if ~mod(Framecounter,FramesPerStim)
randomcolour = rand(1, 3)*255; %Change background stimulus colour
end
Screen('FillRect', w, randomcolour, wRect);
Screen('Flip',w);
Framecounter = Framecounter + 1; %Increase frame counter
end
EndT = GetSecs; %Measure end time of session
Screen('CloseAll');
EndT - StartT %Shows full length of time all stimuli were presented
The timing precision will depend on your particular refresh rate.
Hope this helps!

Warp images using motion maps generated by opticalFlowLKDoG (Matlab 2015A)

This question is based on a modified Matlab code from the online documentation for the optical flow system objects in version 2015a as appears in opticalFlowLK class
clc; clearvars; close all;
inputVid = VideoReader('viptraffic.avi');
opticFlow = opticalFlowLKDoG('NumFrames',3);
inputVid.currentTime = 2;
k = 1;
while inputVid.currentTime<=2 + 1/inputVid.FrameRate
frameRGB{k} = readFrame(inputVid);
frameGray{k} = rgb2gray(frameRGB{k});
flow{k} = estimateFlow(opticFlow,frameGray{k});
k = k+1;
end
By looking at flow{2}.Vx and flow{2}.Vy I get the motion maps U and V that describe the motion from frameGray{1} to frameGray{2}.
Iwant to use flow{2}.Vx and flow{2}.Vy directly on the data in frameGray{1} in order to warp frameGray{1} to appear visually similar to frameGray{2}.
I tried this code:
[x, y] = meshgrid(1:size(frameGray{1},2), 1:size(frameGray{1},1));
frameGray1Warped = interp2(double(frameGray{1}) , x-flow{2}.Vx , y-flow{2}.Vy);
But it doesn't seem to do much at all except ruin the image quality (but the objects don't display any real motion towards their locations in frameGray{2}.
I added 3 images showing the 2 original frames followed by frame 1 warped using the motion field to appear similar to frame 2:
It can be seen easily that frame 1 warped to 2 is essentially frame 1 with degraded quality but the cars haven't moved at all. That is - the location of the cars is the same: look at the car closest to the camera with respect to the road separation line near it; it's virtually the same in frame 1 and frame 1 warped to 2, but is quite different in frame 2.

least squares fitting to a 3 dimensional data set

I am working on video stabilisation ( making shaky videos non-shaky) using matlab.
One of the steps is to find a smooth camera path given the unstable camera path.
The unstable camera path is one which gives the jittering or shake to the video.
I have camera path specified using camera position which is a 3d-data.
camera path - (cx,cy,cz);
As i plot in matlab, i can visually see the shakiness of the camera motion.
So now i require a least squares fitting to be done on the camera path specified by(cx,cy,cz);
I came across polyfit() which does fitting for 2-dimensional data.
But what i need is a 3-d smooth curve fit to the shaky curve.
Thanks in advance.
Couldn't you just fit three separate 1d curves for cx(t), cy(t), cz(t)?
BTW: I think what you need is a Kalman filter, not a polynomial fit to the camera path. But I'm not sure if matlab has builtin support for that.
Approach using least square fit:
t = (1:0.1:5)';
% model
px = [ 5 2 1 ];
x = polyval(px,t);
py = [ -2 1 1 ];
y = polyval(py,t);
pz = [ 1 20 1 ];
z = polyval(pz,t);
% plot model
figure
plot3(x,y,z)
hold all
% simulate measurement
xMeasured = x+2*(rand(length(x),1)-0.5);
yMeasured = y+2*(rand(length(y),1)-0.5);
zMeasured = z+2*(rand(length(z),1)-0.5);
% plot simulated measurements
plot3(xMeasured, yMeasured, zMeasured,'or')
hold off
grid on
% least squares fit
A = [t.^2, t, t./t];
pxEstimated = A\xMeasured;
pyEstimated = A\yMeasured;
pzEstimated = A\zMeasured;
Let me be grateful to stackoverflow.com first of all and then my thanks to zellus and nikie who had started me thinking about the problem more. So now I have reached the solution which follows zellus approach and as nikie pointed out I used parameter 't' .
cx, cy,cz are the coordinates in 3d space and in my case they are all 343x1 doubles
My final code is shown below which fits the 3d data set:
t = linspace(1,343,343)';
load cx.mat;
load cy.mat;
load cz.mat;
plot3(cx, cy, cz,'r'),title('source Camera Path');
hold all
A = [t.^2, t, t./t];
fx = A\cx;
fy = A\cy;
fz = A\cz;
Xev = polyval(fx,t);
Yev = polyval(fy,t);
Zev = polyval(fz,t);
plot3(Xev,Yev,Zev,'+b'),title('Fitting Line');
I look forward to more interesting discussions on StackOverflow with great helpful people.