目录
1、前言
2、时间-位移关系计算
3、Matlab计算时间和位置数据
(1)Matlab程序
(2)Arduino程序
4、Matlab生成Arduino电机正反转程序语句
(1)Arduino程序
(2)Matlab 命令行方式生成Arduino步进电机正反转程序语句
①正转命令行
②反转命令行
(3)Matlab GUI方式生成Arduino步进电机正反转程序语句
5、下载链接
1、前言
Arduino中手写脉冲控制步进电机-1-CSDN博客 接上一节继续。上一节是实现步进电机恒速运转,要实现电机变速运动需要对脉冲延时函数进行调整。本节主要讲解电机固定位置往复运动、速度以曲线方式运行。
2、时间-位移关系计算
步进电机时间-位移关系拟合三角函数。从Cos函数曲线上采样、取很多个点,取样点越细电机运行就越圆滑。
思路:对于一个 时间-位移 三角函数,每隔相同的时长(称为单元时长)取一次位移值,计算相邻
两次位移的距离(的绝对值),再计算对应的脉冲步数的delay时长
1、距离固定后,脉冲步数固定。
2、由于单元时长固定,因此每步的脉冲时长(脉冲频率)也是固定的。但是不同单元的脉冲频率不同
3、即固定单元时长,但不固定单元内步数,因此单元的脉冲频率也不固定
类似于这样,然后使电机的时间-位移关系,满足相邻红星的时间-位移关系即可。
3、Matlab计算时间和位置数据
(1)Matlab程序
运行的.m脚本程序
%% 1.步进电机PWM计算代码
clc
clear
close all
%% 原始值
A=40.64; %振幅*2,两倍振幅,即伸缩杆的移动范围。电机1600脉冲转一圈,40.64=1600*。0.254
MBJL=0.0254; %每步距离,电机固定参数(与细分数有关)
T=2; %三角函数的周期2秒,即2秒执行完给定的脉冲数
T=T*1000*1000; %换算为微秒
SN=A/MBJL; %StepNumber,三角函数一个周期内的脉冲步数,振幅固定后SN即固定
TPSN=T/SN; %TimePerStep,每步的时长的平均值
UN=20; %UnitNumber,一个周期平均分割的单元总数
%函数
x=2*pi/SN:2*pi/SN:2*pi; %自变量
y=func(x,A); %函数
% %函数:脉冲数-位移图
% figure(1)
% plot(1:SN,y,'b.','markersize',15,'LineWidth',1)
% xlabel('脉冲数')
% ylabel('位移/mm')
% ZT=30;%字体30号
% set(gca,'FontSize',ZT);
% aaa=2;
% set(gcf,'unit','centimeters','position',[2 2 16*aaa 9*aaa]);
% set(gca,"FontName","宋体","FontSize",ZT,"LineWidth",2);
%
% %目标函数图(理想函数图)
% figure(2)
% plot((1:SN)*TPSN,y,'b.','markersize',15,'LineWidth',1)
% xlabel('时间/微秒')
% ylabel('位移/mm')
% ZT=30;%字体30号
% set(gca,'FontSize',ZT);
% aaa=2;
% set(gcf,'unit','centimeters','position',[2 2 16*aaa 9*aaa]);
% set(gca,"FontName","宋体","FontSize",ZT,"LineWidth",2);
%%
NN=1:SN/UN:SN; %平均分割的脉冲坐标
NN(length(NN)+1)=SN;
x0=zeros(1,length(NN));
for i=1:length(NN)
x0(1,i)=x(NN(1,i)); %平均分割的脉冲坐标对应的x坐标
end
y0=func(x0,A); %x坐标对应的位移
y01=y0(1:(length(NN)-1));
y02=y0(2:(length(NN)));
y00=y02-y01;
%求解
MCZS=abs(y00/0.0254); %一个单元内的脉冲总数
MCZS=round(MCZS);
PJBC=(T/UN)./MCZS; %每单元的平均步长,微秒,脉冲总数需要四舍五入
PJBC=round(PJBC);
%结果
Result_mc=MCZS;
Result_bc=PJBC;
%% 还原函数图
MCZS000=y00/0.0254; %一个单元内的脉冲总数
MCZS000=round(MCZS000);
x1=MCZS000*MBJL;
JLJL=zeros(1,UN); %积累距离,mm
for i=1:UN
JLJL(i)=sum(x1(1:i));
end
x2=MCZS.*PJBC;
JLSJ=zeros(1,UN); %积累时间,微秒
for i=1:UN
JLSJ(i)=sum(x2(1:i));
end
figure(3)
plot((1:SN)*TPSN,y,'b.-','markersize',5,'LineWidth',5)
hold on
plot(JLSJ,JLJL+abs(min(JLJL)),'r*-','markersize',10,'LineWidth',2)
xlabel('时间/微秒')
ylabel('位移/mm')
legend('理想时间位移函数','还原时间位移关系')
ZT=30;%字体30号
set(gca,'FontSize',ZT);
aaa=2;
set(gcf,'unit','centimeters','position',[2 2 16*aaa 9*aaa]);
set(gca,"FontName","宋体","FontSize",ZT,"LineWidth",2);
func函数。保存位func.m脚本程序。
function y=func(x,A)
y=A/2*cos(x)+A/2;
(2)计算结果
将计算的数据带到Arduino程序中
(2)Arduino程序
#define STEPPIN 7 //脉冲位为7
#define DIRPIN 6 //方向位为6
#define bushu 1600 //脉冲步数 1600个脉冲转一圈()
void setup() {
pinMode(STEPPIN, OUTPUT);
pinMode(DIRPIN, OUTPUT);
Serial.begin(9600);
}
//循环
void loop()
{
//不论电机初始位置如何,使电机超量程运动,以达到复位效果
//1.正转一圈
Serial.println("Forward Begins"); //串口监视器输出引号内容
digitalWrite(DIRPIN, HIGH); //方向引脚高电位,正转
// 正向转(1001步)
for (int x = 0; x < bushu+1; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(500); //Microseconds是微秒
digitalWrite(STEPPIN, LOW);
delayMicroseconds(500); //Microseconds是微秒
}
Serial.println("Forward Ends"); //串口监视器输出引号内容
delay(1000); // 暂停1秒
//2.逆转1圈
Serial.println("Backward Begins"); //串口监视器输出引号内容
digitalWrite(DIRPIN, LOW); //方向引脚低电位,逆转
// 反向转(bushu脉冲)
for (int x = 0; x < bushu+1; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(500); //Microseconds是微秒
digitalWrite(STEPPIN, LOW);
delayMicroseconds(500); //Microseconds是微秒
}
Serial.println("Backward Ends"); //串口监视器输出引号内容
delay(1000); //暂停1秒
//3.
Serial.println("Forward Begins"); //串口监视器输出引号内容
digitalWrite(DIRPIN, HIGH); //方向引脚高电位,正转
// 正向转
for (int x = 0; x < 40; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(2500);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(2500);
}
for (int x = 0; x < 115; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(870);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(870);
}
for (int x = 0; x < 178; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(562);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(562);
}
for (int x = 0; x < 223; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(448);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(448);
}
for (int x = 0; x < 247; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(405);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(405);
}
for (int x = 0; x < 247; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(405);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(405);
}
for (int x = 0; x < 223; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(448);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(448);
}
for (int x = 0; x < 176; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(568);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(568);
}
for (int x = 0; x < 113; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(885);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(885);
}
for (int x = 0; x < 38; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(2632);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(2632);
}
delay(1000); //暂停1秒
//4.
Serial.println("Backward Begins");//串口监视器输出引号内容
digitalWrite(DIRPIN, LOW);//方向引脚低电位,逆转
// 正向转
for (int x = 0; x < 40; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(2500);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(2500);
}
for (int x = 0; x < 115; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(870);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(870);
}
for (int x = 0; x < 178; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(562);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(562);
}
for (int x = 0; x < 223; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(448);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(448);
}
for (int x = 0; x < 247; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(405);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(405);
}
for (int x = 0; x < 247; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(405);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(405);
}
for (int x = 0; x < 223; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(448);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(448);
}
for (int x = 0; x < 176; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(568);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(568);
}
for (int x = 0; x < 113; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(885);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(885);
}
for (int x = 0; x < 38; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(2632);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(2632);
}
delay(1000); //暂停1秒
}
4、Matlab生成Arduino电机正反转程序语句
(1)Arduino程序
循环程序中,1和2是恒速方式运行。3和4是曲线方式正反转,使用Matlab生成的语句和数据。Matlab生成的程序语句直接复制到3和4中。
#define STEPPIN 7 //脉冲位为7
#define DIRPIN 6 //方向位为6
#define bushu 1600 //脉冲步数 1600个脉冲转一圈()
void setup() {
pinMode(STEPPIN, OUTPUT);
pinMode(DIRPIN, OUTPUT);
Serial.begin(9600);
}
//循环
void loop()
{
//不论电机初始位置如何,使电机超量程运动,以达到复位效果
//1.正转一圈
Serial.println("Forward Begins"); //串口监视器输出引号内容
digitalWrite(DIRPIN, HIGH); //方向引脚高电位,正转
// 正向转(1001步)
for (int x = 0; x < bushu+1; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(500); //Microseconds是微秒
digitalWrite(STEPPIN, LOW);
delayMicroseconds(500); //Microseconds是微秒
}
Serial.println("Forward Ends"); //串口监视器输出引号内容
delay(1000); // 暂停1秒
//2.逆转1圈
Serial.println("Backward Begins"); //串口监视器输出引号内容
digitalWrite(DIRPIN, LOW); //方向引脚低电位,逆转
// 反向转(bushu脉冲)
for (int x = 0; x < bushu+1; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(500); //Microseconds是微秒
digitalWrite(STEPPIN, LOW);
delayMicroseconds(500); //Microseconds是微秒
}
Serial.println("Backward Ends"); //串口监视器输出引号内容
delay(1000); //暂停1秒
//3、曲线方式正转一圈
Serial.println("Forward Begins"); //串口监视器输出引号内容
digitalWrite(DIRPIN, HIGH); //方向引脚高电位,正转
// 正向转
for (int x = 0; x <40; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(5000);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(5000);
}
for (int x = 0; x <115; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(1739);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(1739);
}
for (int x = 0; x <178; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(1124);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(1124);
}
for (int x = 0; x <223; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(897);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(897);
}
for (int x = 0; x <247; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(810);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(810);
}
for (int x = 0; x <247; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(810);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(810);
}
for (int x = 0; x <223; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(897);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(897);
}
for (int x = 0; x <176; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(1136);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(1136);
}
for (int x = 0; x <113; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(1770);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(1770);
}
for (int x = 0; x <38; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(5263);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(5263);
}
delay(1000); //鏆傚仠1绉?
//4、曲线方式正转一圈
Serial.println("Backward Begins");//串口监视器输出引号内容
digitalWrite(DIRPIN, LOW);//方向引脚低电位,逆转
// 反向转
for (int x = 0; x <40; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(5000);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(5000);
}
for (int x = 0; x <115; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(1739);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(1739);
}
for (int x = 0; x <178; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(1124);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(1124);
}
for (int x = 0; x <223; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(897);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(897);
}
for (int x = 0; x <247; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(810);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(810);
}
for (int x = 0; x <247; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(810);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(810);
}
for (int x = 0; x <223; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(897);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(897);
}
for (int x = 0; x <176; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(1136);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(1136);
}
for (int x = 0; x <113; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(1770);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(1770);
}
for (int x = 0; x <38; x ++) {
digitalWrite(STEPPIN, HIGH);
delayMicroseconds(5263);
digitalWrite(STEPPIN, LOW);
delayMicroseconds(5263);
}
delay(1000); //延时1秒?
}
(2)Matlab 命令行方式生成Arduino步进电机正反转程序语句
在前面Matlab程序计算出来时间、脉冲步数数据后,将计算结果一个一个写到程序语句中。这样操作非常的慢和低效,可以使用Matlab命令行来操作。
①正转命令行
%% 2.自动化语句生成代码(1)正向转
clc
Result_bc_str=num2str(Result_bc(1));
Result_mc_str=num2str(Result_mc(1));
%% 正向转
for iii=1:length(Result_bc)/2
%记录步数
s11=' for (int x = 0; x <';
s21=num2str(Result_mc(iii));
s31='; x ++) {';
s1 = strcat(s11,s21,s31);
%记录delay时长
s12=' delayMicroseconds(';
s22=num2str(Result_bc(iii));
s32=');';
s2 = strcat(s12,s22,s32);
%合成语句
disp([s1 newline ' digitalWrite(STEPPIN, HIGH);' newline s2 newline ' digitalWrite(STEPPIN, LOW);' newline s2 newline ' }'])
end
disp([' delay(1000); //暂停1秒' newline
生成程序语句替换到Arduino第三段正转控制中
②反转命令行
%% 2.自动化语句生成代码(2)逆向转
clc
Result_bc_str=num2str(Result_bc(1));
Result_mc_str=num2str(Result_mc(1));
%% 正向转
for iii=length(Result_bc)/2+1:length(Result_bc)
%记录步数
s11=' for (int x = 0; x <';
s21=num2str(Result_mc(iii));
s31='; x ++) {';
s1 = strcat(s11,s21,s31);
%记录delay时长
s12=' delayMicroseconds(';
s22=num2str(Result_bc(iii));
s32=');';
s2 = strcat(s12,s22,s32);
%合成语句
disp([s1 newline ' digitalWrite(STEPPIN, HIGH);' newline s2 newline ' digitalWrite(STEPPIN, LOW);' newline s2 newline ' }'])
end
disp([' delay(1000); //暂停1秒' newline])
生成的程序复制到Arduino中
(3)Matlab GUI方式生成Arduino步进电机正反转程序语句
GUI通过.m脚本程序运行生成。脚本程序见下载链接
5、下载链接
https://download.csdn.net/download/panjinliang066333/88670374
参考博客
【Arduino步进电机】【5.1】PWM代码(1)_arduino pwm 步进电机-CSDN博客