该方案引导大家如何设计或使用一款控制板来实现直流有刷电机的XY轴控制,水泵流量的控制,料盒的控制和自动下料控制。
1,设计的理念 在自动化控制中,我们用步进电机、伺服电机、无刷电机来实现各种运动控制,这些电机通常可以达到很精确的位移控制。但是其缺点也较为明显:电机和控制器的成本比较昂贵。 那么在一些对精度要求不高的地方是不是可以用简单的直流有刷电机来实现呢,当然也是可以的,这样可以节省大量的成本。 同时控制板可以支持Modbus RTU通信协议,这样通过串口就可以任意控制电机了,哈哈,是不是很好玩?
2,控制方案功能简介 该控制卡用于控制和驱动两路执行机构,其执行机构可以为带Hall编码器的直流电机、水泵流量控制系统、料盒自动下料机构等。用户可以通过Modbus RTU通信协议配置控制卡的两路中任意一路的运行模式、工作使能、转速和刹车。 控制卡可以独立配置两路中任意一路执行机构的工作模式:
a,线性往返模式,该模式需要带霍尔转速检测的直流减速电机作为执行机构。通过复位、校准、工作使能等操作,只要用户通过Modbus RTU写入目的寄存器数据,则执行机构自动运行到指定的目的位置。使系统达到类似步进电机的控制效果。该模式通常用于线性XYZ轴的控制,机械自动化的机械臂,自动控制,机器人,智能小车等应用。 b,脉冲检测模式,该模式驱动直流执行部件运行指定的脉冲数量后,然后停机。a) 如水泵流量控制系统,水泵作为执行电机,流量计的脉冲作为脉冲检测,当需要水泵流出300ml液体,则工作使能后,向目的寄存器写入300ml对应的脉冲数量后,则水泵在输出300ml液体后自动停机。b) 如料盒下料控制系统,带霍尔转速检测的直流减速电机作为执行机构和脉冲检测单元,当需要出料50g量,则工作使能后,向目的寄存器写入50g料对应的脉冲数量后,则系统输出50g物料后自动停机。 c,持续正转模式,该模式下工作使能后电机开始持续正转,直到工作模式禁止后才刹车停机。 d,持续反转模式,该模式下工作使能后电机开始持续反转,直到工作模式禁止后才刹车停机。
3,XY结构部件搭建 下图为XY轴的十字形图片,其主要由齿条,齿轮(1模20齿),拖链线槽,直流蜗杆电机(带霍尔编码器),接近开关,光轴滑块和上下底板组成,大家可以根据图示自行组装完成。其位置检测主要通过霍尔编码器的脉冲来实现。其运行精度达到1%以内。 4,料盒自动下料的结构搭建 下图为料盒自动控制的组装图片,其主要由料盒,转接齿,直流减速电机(带霍尔编码器),和下底板组成,大家可以根据图示自行组装完成。其下料的精度可以达到5%以内。 5,水泵流量自动控制的结构搭建 下图为水泵流量控制器的组装图片,其主要由小水泵,涡轮流量计,和X轴(将XY轴拆掉一个Y轴,简单吧)部件组成,大家可以根据图示自行组装完成。其流量与流量计的精度有关。 温馨提示,流量计应该安装到出水口,且远离出水口,避免水锤效应和气泡,因为这些都会影响流量计的精度。 6,原理图 好了,上面讲了一大堆没用的东西,现在上传关键的原理图,大家看好了。 电源部分: 电机驱动部分: Modbus RTU,485原理图 MCU外设,光耦隔离,接近传感器检测电路 7,软件代码-Modbus RTU部分读写代码
#include "main.h"
#include "M031Series.h"
void AnswerProcess(uint8_t cmd);
void WriteProcess(void);
void CmdDataProcess(void)
{
uint8_t offset=0;
uint8_t FrameLength=0;
union { uint16_t udat;uint8_t buf[2];}umid;
uint16_t GetCrc16=0;
if((command.RxTimeOutEnable==1)&(command.RxTimeOutCounter>FrameModbusTimerInterval))
{
for(offset=0;offset<64;offset++)command.RxBuf[offset]=0;
command.RxCount=0;
command.RxTimeOutEnable=0;
}
else if((command.RxBuf[0]==SysRegister.Address)&&(command.RxCount>7))
{
if(command.RxBuf[1]==CmdRead)
{
GetCrc16=GetCrcData(command.RxBuf,6);
umid.buf[0]=command.RxBuf[6];
umid.buf[1]=command.RxBuf[7];
if(umid.udat==GetCrc16)
{
umid.buf[0]=command.RxBuf[3];
umid.buf[1]=command.RxBuf[2];
command.StartAddress=umid.udat;
command.OpeRegisterNum=command.RxBuf[5];
AnswerProcess(CmdRead);
}
for(offset=0;offset<8;offset++)command.RxBuf[offset]=0;
command.RxCount=0;
command.RxTimeOutEnable=0;
}
else if(command.RxBuf[1]==CmdWrite)
{
command.OpeRegisterNum=command.RxBuf[5];
FrameLength=9+command.OpeRegisterNum*2;
if(command.RxCount>=FrameLength)
{
GetCrc16=GetCrcData(command.RxBuf,(FrameLength-2));
umid.buf[0]=command.RxBuf[FrameLength-2];
umid.buf[1]=command.RxBuf[FrameLength-1];
if(umid.udat==GetCrc16)
{
umid.buf[0]=command.RxBuf[3];
umid.buf[1]=command.RxBuf[2];
command.StartAddress=umid.udat;
WriteProcess();
AnswerProcess(CmdWrite);
}
for(offset=0;offset<64;offset++)command.RxBuf[offset]=0;
command.RxCount=0;
command.RxTimeOutEnable=0;
}
}
}
}
void AnswerProcess(uint8_t cmd)
{
uint8_t offset=0;
uint16_t i=0;
uint16_t CRC16=0;
RS485Mode(1);
if(cmd==CmdWrite)
{
for(offset=0;offset<6;offset++) command.TxBuf[offset]=command.RxBuf[offset];
CRC16=GetCrcData(command.TxBuf,offset);
command.TxBuf[offset++]=CRC16;
command.TxBuf[offset++]=CRC16>>8;
for(i=0;i<offset;i++)
{
UART0->DAT =command.TxBuf[i];
UART_WAIT_TX_EMPTY(UART0);
}
for(i=0;i<offset;i++)command.TxBuf[i]=0;
command.OpeRegisterNum=0;
command.StartAddress=0;
}
if(cmd==CmdRead)
{
command.TxBuf[offset++]=SysRegister.Address;
command.TxBuf[offset++]=CmdRead;
command.TxBuf[offset++]=command.OpeRegisterNum*2;
for(i=command.StartAddress;i<(command.StartAddress+command.OpeRegisterNum);i++)
{
switch(i)
{
case BaseAddress:
command.TxBuf[offset++]=0;
command.TxBuf[offset++]=SysRegister.Address;
break;
case BaseBandRate:
command.TxBuf[offset++]=0;
command.TxBuf[offset++]=SysRegister.BandRateConfig;
break;
case BaseCh1Offset:
command.TxBuf[offset++]=0;
command.TxBuf[offset++]=MotorControl.M1LinearErrorOffset;
break;
case BaseCh2Offset:
command.TxBuf[offset++]=0;
command.TxBuf[offset++]=MotorControl.M2LinearErrorOffset;
break;
case BaseCh1CurrentLocationHByte:
command.TxBuf[offset++]=MotorControl.M1CurrentBuffCount>>24;
command.TxBuf[offset++]=MotorControl.M1CurrentBuffCount>>16;
break;
case BaseCh1CurrentLocationLByte:
command.TxBuf[offset++]=MotorControl.M1CurrentBuffCount>>8;
command.TxBuf[offset++]=MotorControl.M1CurrentBuffCount;
break;
case BaseCh1DestinationLocationHByte:
command.TxBuf[offset++]=MotorControl.M1DestinationBuffCount>>24;
command.TxBuf[offset++]=MotorControl.M1DestinationBuffCount>>16;
break;
case BaseCh1DestinationLocationLByte:
command.TxBuf[offset++]=MotorControl.M1DestinationBuffCount>>8;
command.TxBuf[offset++]=MotorControl.M1DestinationBuffCount;
break;
case BaseCh1Speed:
command.TxBuf[offset++]=0;
command.TxBuf[offset++]=SysRegister.M1Speed;
break;
case BaseCh1RunMode:
command.TxBuf[offset++]=0;
command.TxBuf[offset++]=SysRegister.M1RunMode;
break;
case BaseCh1Filter:
command.TxBuf[offset++]=0;
command.TxBuf[offset++]=SysRegister.M1Filter;
break;
case BaseCh1ResetCmd:
command.TxBuf[offset++]=0;
command.TxBuf[offset++]=SysRegister.M1ResetCmd;
break;
case BaseCh1CalibrationDataHByte:
command.TxBuf[offset++]=MotorControl.M1CalibrationBuffCount>>24;
command.TxBuf[offset++]=MotorControl.M1CalibrationBuffCount>>16;
break;
case BaseCh1CalibrationDataLByte:
command.TxBuf[offset++]=MotorControl.M1CalibrationBuffCount>>8;
command.TxBuf[offset++]=MotorControl.M1CalibrationBuffCount;
break;
case BaseCh2CurrentLocationHByte:
command.TxBuf[offset++]=MotorControl.M2CurrentBuffCount>>24;
command.TxBuf[offset++]=MotorControl.M2CurrentBuffCount>>16;
break;
case BaseCh2CurrentLocationLByte:
command.TxBuf[offset++]=MotorControl.M2CurrentBuffCount>>8;
command.TxBuf[offset++]=MotorControl.M2CurrentBuffCount;
break;
case BaseCh2DestinationLocationHByte:
command.TxBuf[offset++]=MotorControl.M2DestinationBuffCount>>24;
command.TxBuf[offset++]=MotorControl.M2DestinationBuffCount>>16;
break;
case BaseCh2DestinationLocationLByte:
command.TxBuf[offset++]=MotorControl.M2DestinationBuffCount>>8;
command.TxBuf[offset++]=MotorControl.M2DestinationBuffCount;
break;
case BaseCh2Speed:
command.TxBuf[offset++]=0;
command.TxBuf[offset++]=SysRegister.M2Speed;
break;
case BaseCh2RunMode:
command.TxBuf[offset++]=0;
command.TxBuf[offset++]=SysRegister.M2RunMode;
break;
case BaseCh2ResetCmd:
command.TxBuf[offset++]=0;
command.TxBuf[offset++]=SysRegister.M2ResetCmd;
break;
case BaseCh2CalibrationDataHByte:
command.TxBuf[offset++]=MotorControl.M2CalibrationBuffCount>>24;
command.TxBuf[offset++]=MotorControl.M2CalibrationBuffCount>>16;
break;
case BaseCh2CalibrationDataLByte:
command.TxBuf[offset++]=MotorControl.M2CalibrationBuffCount>>8;
command.TxBuf[offset++]=MotorControl.M2CalibrationBuffCount;
break;
case BaseCh1MotorBusy:
command.TxBuf[offset++]=0;
command.TxBuf[offset++]=MotorControl.M1MotorRunStop;
break;
case BaseCh2MotorBusy:
command.TxBuf[offset++]=0;
command.TxBuf[offset++]=MotorControl.M2MotorRunStop;
break;
default:command.TxBuf[offset++]=0;command.TxBuf[offset++]=0;break;
}
}
CRC16=GetCrcData(command.TxBuf,offset);
command.TxBuf[offset++]=CRC16;
command.TxBuf[offset++]=CRC16>>8;
for(i=0;i<offset;i++)
{
UART0->DAT =command.TxBuf[i];
UART_WAIT_TX_EMPTY(UART0);
}
for(i=0;i<offset;i++)command.TxBuf[i]=0;
command.OpeRegisterNum=0;
command.StartAddress=0;
}
RS485Mode(0);
}
void WriteProcess(void)
{
uint8_t offset=0;
uint16_t i=0;
offset=7;
for(i=command.StartAddress;i<(command.StartAddress+command.OpeRegisterNum);i++)
{
switch(i)
{
case BaseAddress:
offset++;SysRegister.Address=command.RxBuf[offset++];
FlashNeedToUpdate=1;
break;
case BaseBandRate:
offset++;SysRegister.BandRateConfig=command.RxBuf[offset++];
FlashNeedToUpdate=1;
break;
case BaseCh1Filter:
offset++;
if(command.RxBuf[offset]<10) SysRegister.M1Filter=command.RxBuf[offset];
offset++;
FlashNeedToUpdate=1;
break;
case BaseCh1Offset:
MotorControl.M1LinearErrorOffset =command.RxBuf[offset++]<<8;
MotorControl.M1LinearErrorOffset|=command.RxBuf[offset++];
if(MotorControl.M1LinearErrorOffset>30) MotorControl.M1LinearErrorOffset=30;
else if(MotorControl.M1LinearErrorOffset<5)MotorControl.M1LinearErrorOffset=5;
FlashNeedToUpdate=1;
break;
case BaseCh2Offset:
MotorControl.M2LinearErrorOffset =command.RxBuf[offset++]<<8;
MotorControl.M2LinearErrorOffset|=command.RxBuf[offset++];
if(MotorControl.M2LinearErrorOffset>30) MotorControl.M2LinearErrorOffset=30;
else if(MotorControl.M2LinearErrorOffset<5)MotorControl.M2LinearErrorOffset=5;
FlashNeedToUpdate=1;
break;
case BaseCh1WriteDestinationLocation:
SysRegister.M1DestinationLocation=0;
SysRegister.M1DestinationLocation =command.RxBuf[offset++]<<8;
SysRegister.M1DestinationLocation|=command.RxBuf[offset++];
if(SysRegister.M1RunMode==LinearRunMode)
{
if(MotorControl.M1MotorRunStop==MotorStop)
{
MotorControl.M1DestinationBuffCount=
(SysRegister.M1DestinationLocation*MotorControl.M1CalibrationBuffCount)/1000;
}
else if(SysRegister.M1DestinationLocation>1000)
{
MotorControl.M1ResetOk=0;
MRunning(Motor1,100,Stop);
}
}
else if(SysRegister.M1RunMode==WaterFlowerRunMode)
{
MotorControl.M1CurrentBuffCount=0;
MotorControl.M1DestinationBuffCount=SysRegister.M1DestinationLocation;
SysRegister.M1DestinationLocation=0;
}
else MotorControl.M1DestinationBuffCount =SysRegister.M1DestinationLocation;
break;
case BaseCh2WriteDestinationLocation:
SysRegister.M2DestinationLocation=0;
SysRegister.M2DestinationLocation =command.RxBuf[offset++]<<8;
SysRegister.M2DestinationLocation|=command.RxBuf[offset++];
if(SysRegister.M2RunMode==LinearRunMode)
{
if(MotorControl.M2MotorRunStop==MotorStop)
{
MotorControl.M2DestinationBuffCount=
(SysRegister.M2DestinationLocation*MotorControl.M2CalibrationBuffCount)/1000;
}
else if(SysRegister.M2DestinationLocation>1000)
{
MotorControl.M2ResetOk=0;
MRunning(Motor2,100,Stop);
}
}
else if(SysRegister.M2RunMode==WaterFlowerRunMode)
{
MotorControl.M2CurrentBuffCount=0;
MotorControl.M2DestinationBuffCount=SysRegister.M2DestinationLocation;
SysRegister.M2DestinationLocation=0;
}
else MotorControl.M2DestinationBuffCount=SysRegister.M2DestinationLocation;
break;
case BaseCh1Speed:
offset++;SysRegister.M1Speed=command.RxBuf[offset++];
FlashNeedToUpdate=1;
break;
case BaseCh2Speed:
offset++;SysRegister.M2Speed=command.RxBuf[offset++];
FlashNeedToUpdate=1;
break;
case BaseCh1RunMode:
offset++;SysRegister.M1RunMode=command.RxBuf[offset++];
MotorControl.M1CurrentBuffCount=0;
MotorControl.M1DestinationBuffCount=0;
MotorControl.M1CalibrationBuffCount=0;
MRunning(Motor1,100,Stop);
FlashNeedToUpdate=1;
break;
case BaseCh2RunMode:
offset++;SysRegister.M2RunMode=command.RxBuf[offset++];
MotorControl.M2CurrentBuffCount=0;
MotorControl.M2DestinationBuffCount=0;
MotorControl.M2CalibrationBuffCount=0;
MRunning(Motor2,100,Stop);
FlashNeedToUpdate=1;
break;
case BaseCh1ResetCmd:
if(SysRegister.M1RunMode==LinearRunMode)
{
MRunning(Motor1,100,Stop);
offset++;SysRegister.M1ResetCmd=command.RxBuf[offset++];
SysRegister.M1CalibrationCmd=0;
}
else offset+=2;
break;
case BaseCh2ResetCmd:
if(SysRegister.M2RunMode==LinearRunMode)
{
MRunning(Motor2,100,Stop);
offset++;SysRegister.M2ResetCmd=command.RxBuf[offset++];
SysRegister.M2CalibrationCmd=0;
}
else offset+=2;
break;
case BaseCh1CalibrationCmd:
if((M1ResetPin==0)&&(SysRegister.M1RunMode==LinearRunMode)&&(MotorControl.M1MotorRunStop==MotorStop))
{
offset++;SysRegister.M1CalibrationCmd=command.RxBuf[offset++];
MotorControl.M1MovingIndex=0;
MotorControl.M1CurrentBuffCount=0;
MotorControl.M1DestinationBuffCount=0;
MotorControl.M1LinearErrorOffset=5;
}
else offset+=2;
break;
case BaseCh2CalibrationCmd:
if((M2ResetPin==0)&&(SysRegister.M2RunMode==LinearRunMode)&&(MotorControl.M2MotorRunStop==MotorStop))
{
offset++;SysRegister.M2CalibrationCmd=command.RxBuf[offset++];
MotorControl.M2MovingIndex=0;
MotorControl.M2CurrentBuffCount=0;
MotorControl.M2DestinationBuffCount=0;
MotorControl.M2LinearErrorOffset=5;
}
else offset+=2;
break;
default:offset+=2;;break;
}
}
}
8,软件代码-电机控制代码
#include <stdio.h>
#include "M031Series.h"
#include "main.h"
void delay_ms(uint16_t count)
{
uint32_t i=0;
uint16_t j=0;
for(j=0;j<count;j++)
{
for(i=0;i<200000;i++);
}
}
float offsetCalcult(uint8_t ch)
{
float moffset=0;
uint32_t full=0;
float error=0;
switch(ch)
{
case 1:error = MotorControl.M1LinearErrorOffset;full=MotorControl.M1CalibrationBuffCount;break;
case 2:error = MotorControl.M2LinearErrorOffset;full=MotorControl.M2CalibrationBuffCount;break;
default:break;
}
moffset=error/1000.0;
moffset=moffset*full;
return moffset;
}
void motorRuning(void)
{
static uint32_t m1speed=0;
static uint32_t m2speed=0;
float m1offset=0;
float m2offset=0;
switch(SysRegister.M1RunMode)
{
case LinearRunMode:
if(SysRegister.M1ResetCmd!=0)
{
if((M1ResetPin!=0)&&(MotorControl.M1Dir!=Reverse))
{
MRunning(Motor1,SysRegister.M1Speed,Reverse);
}
else if(M1ResetPin==0)
{
MRunning(Motor1,SysRegister.M1Speed,Stop);
SysRegister.M1ResetCmd=0;
MotorControl.M1CurrentBuffCount=0;
MotorControl.M1DestinationBuffCount=0;
MotorControl.M1ResetOk=1;
}
}
else if(SysRegister.M1CalibrationCmd!=0)
{
switch(MotorControl.M1MovingIndex)
{
case 0:
if(M1ResetPin==0)
{
MRunning(Motor1,SysRegister.M1Speed,Forward);
MotorControl.M1MovingIndex++;
MotorControl.M1CalibrationBuffCount=0;
}
else SysRegister.M1CalibrationCmd=0;
break;
case 1:
if(M1LimitPin==0)
{
MRunning(Motor1,SysRegister.M1Speed,Stop);
delay_ms(ChangedDirDelayCount);
FlashNeedToUpdate=1;
SysRegister.M1CalibrationCmd=0;
SysRegister.M1ResetCmd=1;
}
break;
default:break;
}
}
else if(MotorControl.M1ResetOk!=0)
{
m1offset=offsetCalcult(1);
if((MotorControl.M1CurrentBuffCount<(MotorControl.M1DestinationBuffCount-m1offset))
&&(MotorControl.M1DestinationBuffCount>m1offset))
{
if((MotorControl.M1Dir!=Forward)||(m1speed!=SysRegister.M1Speed))
{
m1speed=SysRegister.M1Speed;
MRunning(Motor1,SysRegister.M1Speed,Forward);
MotorControl.M1ZeroRunningToLimit=1;
}
}
else if(MotorControl.M1CurrentBuffCount>(MotorControl.M1DestinationBuffCount+MotorControl.M1LinearErrorOffset))
{
if((MotorControl.M1Dir!=Reverse)||(m1speed!=SysRegister.M1Speed))
{
m1speed=SysRegister.M1Speed;
MRunning(Motor1,SysRegister.M1Speed,Reverse);
MotorControl.M1ZeroRunningToLimit=0;
}
}
else if(MotorControl.M1Dir!=Stop)
{
MRunning(Motor1,100,Stop);
m1speed=0;
}
if(M1LimitPin==0)MotorControl.M1CurrentBuffCount=MotorControl.M1CalibrationBuffCount;
if(M1ResetPin==0)MotorControl.M1CurrentBuffCount=0;
}
break;
case ContinueForwardRunMode:
if((MotorControl.M1DestinationBuffCount!=0)&&((MotorControl.M1Dir!=Forward)||(m1speed!=SysRegister.M1Speed)))
{
m1speed=SysRegister.M1Speed;
MRunning(Motor1,SysRegister.M1Speed,Forward);
}
else if((MotorControl.M1DestinationBuffCount==0)&&(MotorControl.M1Dir!=Stop))
{
m1speed=0;
MRunning(Motor1,SysRegister.M1Speed,Stop);
}
break;
case ContinueReverseRunMode:
if((MotorControl.M1DestinationBuffCount!=0)&&((MotorControl.M1Dir!=Reverse)||(m1speed!=SysRegister.M1Speed)))
{
m1speed=SysRegister.M1Speed;
MRunning(Motor1,SysRegister.M1Speed,Reverse);
}
else if((MotorControl.M1DestinationBuffCount==0)&&(MotorControl.M1Dir!=Stop))
{
m1speed=0;
MRunning(Motor1,SysRegister.M1Speed,Stop);
}
break;
case WaterFlowerRunMode:
if((MotorControl.M1CurrentBuffCount<MotorControl.M1DestinationBuffCount)
&&((MotorControl.M1Dir!=Forward)||(m1speed!=SysRegister.M1Speed)))
{
m1speed=SysRegister.M1Speed;
MRunning(Motor1,SysRegister.M1Speed,Forward);
}
else if((MotorControl.M1CurrentBuffCount>=MotorControl.M1DestinationBuffCount)&&(MotorControl.M1Dir!=Stop))
{
MRunning(Motor1,SysRegister.M1Speed,Stop);
MotorControl.M1CurrentBuffCount=0;
MotorControl.M1DestinationBuffCount=0;
}
break;
default:break;
}
switch(SysRegister.M2RunMode)
{
case LinearRunMode:
if(SysRegister.M2ResetCmd!=0)
{
if((M2ResetPin!=0)&&(MotorControl.M2Dir!=Reverse))
{
MRunning(Motor2,SysRegister.M2Speed,Reverse);
}
else if(M2ResetPin==0)
{
MRunning(Motor2,SysRegister.M2Speed,Stop);
SysRegister.M2ResetCmd=0;
MotorControl.M2CurrentBuffCount=0;
MotorControl.M2DestinationBuffCount=0;
MotorControl.M2ResetOk=1;
}
}
else if(SysRegister.M2CalibrationCmd!=0)
{
switch(MotorControl.M2MovingIndex)
{
case 0:
if(M2ResetPin==0)
{
MRunning(Motor2,SysRegister.M2Speed,Forward);
MotorControl.M2MovingIndex=1;
MotorControl.M2CalibrationBuffCount=0;
}
else SysRegister.M2CalibrationCmd=0;
break;
case 1:
if(M2LimitPin==0)
{
MRunning(Motor2,SysRegister.M2Speed,Stop);
delay_ms(ChangedDirDelayCount);
FlashNeedToUpdate=1;
SysRegister.M2CalibrationCmd=0;
SysRegister.M2ResetCmd=1;
}
break;
default:break;
}
}
else if(MotorControl.M2ResetOk!=0)
{
m2offset=offsetCalcult(2);
if((MotorControl.M2CurrentBuffCount<(MotorControl.M2DestinationBuffCount-m2offset))
&&(MotorControl.M2DestinationBuffCount>m2offset))
{
if((MotorControl.M2Dir!=Forward)||(m2speed!=SysRegister.M2Speed))
{
m2speed=SysRegister.M2Speed;
MRunning(Motor2,SysRegister.M2Speed,Forward);
MotorControl.M2ZeroRunningToLimit=1;
}
}
else if(MotorControl.M2CurrentBuffCount>(MotorControl.M2DestinationBuffCount+MotorControl.M2LinearErrorOffset))
{
if((MotorControl.M2Dir!=Reverse)||(m2speed!=SysRegister.M2Speed))
{
m2speed=SysRegister.M2Speed;
MRunning(Motor2,SysRegister.M2Speed,Reverse);
MotorControl.M2ZeroRunningToLimit=0;
}
}
else if(MotorControl.M2Dir!=Stop)
{
MRunning(Motor2,100,Stop);
m2speed=0;
}
if(M2LimitPin==0)MotorControl.M2CurrentBuffCount=MotorControl.M2CalibrationBuffCount;
if(M2ResetPin==0)MotorControl.M2CurrentBuffCount=0;
}
break;
case ContinueForwardRunMode:
if((MotorControl.M2DestinationBuffCount!=0)&&((MotorControl.M2Dir!=Forward)||(m2speed!=SysRegister.M2Speed)))
{
m2speed=SysRegister.M2Speed;
MRunning(Motor2,SysRegister.M2Speed,Forward);
}
else if((MotorControl.M2DestinationBuffCount==0)&&(MotorControl.M2Dir!=Stop))
{
m2speed=0;
MRunning(Motor2,SysRegister.M2Speed,Stop);
}
break;
case ContinueReverseRunMode:
if((MotorControl.M2DestinationBuffCount!=0)&&((MotorControl.M2Dir!=Reverse)||(m2speed!=SysRegister.M2Speed)))
{
m2speed=SysRegister.M2Speed;
MRunning(Motor2,SysRegister.M2Speed,Reverse);
}
else if((MotorControl.M2DestinationBuffCount==0)&&(MotorControl.M2Dir!=Stop))
{
m2speed=0;
MRunning(Motor2,SysRegister.M2Speed,Stop);
}
break;
case WaterFlowerRunMode:
if((MotorControl.M2CurrentBuffCount<MotorControl.M2DestinationBuffCount)
&&((MotorControl.M2Dir!=Forward)||(m2speed!=SysRegister.M2Speed)))
{
m2speed=SysRegister.M2Speed;
MRunning(Motor2,SysRegister.M2Speed,Forward);
}
else if((MotorControl.M2CurrentBuffCount>=MotorControl.M2DestinationBuffCount)&&(MotorControl.M2Dir!=Stop))
{
MRunning(Motor2,SysRegister.M2Speed,Stop);
MotorControl.M2CurrentBuffCount=0;
MotorControl.M2DestinationBuffCount=0;
}
break;
default:break;
}
}
9,技术指标 10,运行模式介绍 该控制卡支持四种运行模式,用户可通过串口进行配置,四种模式分别为:线性往返运行模式,脉冲检测运行模式,持续正转,持续反转。 任何写运行模式寄存器后,以及在线性运行模式下Reset、Limit传感器位置变更或者更换电机后,均需要重新校准电机的行程,校准操作完成后进行系统复位,然后才可对电机进行运行使能操作。校准数据掉电存储重新上电后不需要重新校准。 由于方便量化,我们所有的校准操作都是设置为Reset传感器位置到Limit传感器位置对应于0-1000;即校准完成后0代表Reset传感器位置,1000代表Limit传感器位置,中间位置线性增减,在最佳运行区间为5%-95%之间。 持续正转、持续反转和脉冲模式不需要位置检测和Reset、Limit传感器,所以切换回这三个模式后不需要重新校准行程数据。 电机的运行速度可以通过转速寄存器进行设置,该速度值实时更新,不需要电机停机重启。 a,线性运行模式 线性运行常用在负载在Reset传感器和Limit传感器之间往返运行的应用中。最常见的如XY轴运行,机械臂,自动化生产线等,用户通过串口命令可以控制电机带动负载运行到用户期望的位置中。 该模式下需要用到Reset、Limit传感器和电机的Hall转速信号线,电机的线圈供电接口。其电路图请看附录B。 第一次配置时需要校准操作,配置步骤如下:
a, 搭建系统,其中包括霍尔传感器线缆连接,电机线缆连接,Reset和 Limit传感器线缆连接以及位置安装,设备必须保证电机复位时带动负载朝着Reset传感器的位置方向移动,否则可能出现检测不到Reset传感器造成机械冲突。 b, 上电,设置工作模式为线性往返模式,并查询是否设置成功 c, 设置好期望的复位电机速度值 d, 发送复位命令,等待复位完成 e, 发送校准命令,等待校准完成 f, 根据需要写入目的寄存器800,等待执行机构自动运行到800对应的位置(0-1000对应Reset传感器到Limit传感器位置) g, 通过读取目的寄存器数据D1、读取当前位置寄存器D2和校准数据寄存器Full,根据公差计算公式得出目前系统公差值Xd。Xd=(D1-D2)/Full。 h, 如果公差值Xd过大(超出1%),则可以适当的调整公差寄存器的数值,其可设置范围为5-30。
校准过的设备未改变工作模式和传感器位置则不需要重新校准,其配置步骤如下:
a, 系统上电 b, 发送复位命令,等待复位完成
c, 设置电机运行的速度值(如果之前设置的速度值不需要更改可跳过该项,速度值掉电保存) d, 通过写入目的寄存器数值,则电机带动负载运行到指定的位置
当需要紧急停机时,可写入大于1000的数值到通道的目的寄存器值,该通道执行机构紧急停机。如再执行需要先复位。
b,脉冲检测模式 脉冲检测模式的工作原理是向目的寄存器写数值N,则自动开始电机运行,当检测到的脉冲数量等于N时,系统刹车停机等待新的目的寄存器数据更新。
该模式主要用于知道脉冲数量量化的应用。如流量控制系统,M接口接水泵,涡轮流量计的脉冲接脉冲检测接口,当向目的寄存器写入脉冲数量(流量计通常是脉冲模式来量化液体的流量)后,水泵开始运行,当检测到的脉冲数量和目的寄存器写入的数量相同后系统停机,起到输出流量控制的作用。 如料盒下料自动控制系统,M接口接料盒电机,电机的霍尔信号接脉冲检测接口,当向目的寄存器写入脉冲数量(自动下料的原理通常是多少个脉冲对应多少克物料)后,料盒电机开始运行,当检测到的脉冲数量和目的寄存器写入的数量相同后系统停机,起到输出物料控制的作用。 该模式用到电机的Hall信号线或者涡轮流量计脉冲检测信号线,电机线圈供电接口,其电路图请看附录C 操作配置步骤如下:
a, 搭建系统,水泵或电机接到M接口,蜗轮流量计或其他类型的脉冲检测信号或电机霍尔信号接到脉冲检测接口。 b, 上电 c, 写工作模式寄存器设置为脉冲检测模式并查询是否设置成功(该寄存器掉电存储,重新上电不需要重复设置)。 d, 向目的寄存器写入需要运行的脉冲数量,当检测到的脉冲数量与目的寄存器写入的脉冲数量相同后停机,等待下次目的寄存器的更新写入。 如果需要紧急停机时,向相应通道的目的寄存器写入0,则相应通道紧急制动停机。
c,持续正转运行,持续反转运行
这两个模式类似,不同的是一个正方向旋转,一个反方向旋转。该运行模式下,通过写入相应目的寄存器非零值,启动电机(方向参照工作模式设置),写入相应目的寄存器0后停机 由于两个工作模式只有工作和停机,所以只用到电机的线圈接口。其电路图请看附录D 配置和操作步骤
a, 搭建系统,将电机的电源线连接到控制卡
b, 配置工作模式为持续正转(反转)运行模式(该寄存器掉电存储,重新上电后不需要重新设置,可跳过该步骤)。
c, 向相应目的寄存器写入非零值,此时电机将按照规定的方向旋转
d, 向相应目的寄存器写入0,则电机停机
10,多机通信 该控制卡作为Modbus RTU从机,支持多机星形连接,使您的系统用一个板子即可实现所有自动化控制功能,其连接方式请参考附录E。
11,技术支持:淘宝店铺小二货之家
12,模块链接: https://item.taobao.com/item.htm?spm=a2oq0.12575281.0.0.50111deb2L9JDD&ft=t&id=662358314934
|