Arduino中手写脉冲控制步进电机-2

2023-12-27 22:43:37

目录

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博客

文章来源:https://blog.csdn.net/panjinliang066333/article/details/135245502
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。