G代码英文名称G-code,也称RS-274或G指令,属于数控编程语言,用于计算机辅助制造中,广义来说G代码是数控程序中的指令,比如控制自动机床、铣床、CNC、3D打印机等的移动、进给、启动、停止等。可以实现快速定位,直线运动,弧线运动等。抽象的理解就是各种头(主轴、激光器、3D打印头等)的几何位置的移动,旋转,速度的变化,可以通过数控设备来控制,比如计算机。
狭义来说,G字开头的代码表示准备工作,将系统设置在某种预期的状态,而这种状态用后面的数字的标识,比如G00就是进入快速移动状态。
RS-485,又名TIA-485-A,ANSI/TIA/EIA-485或TIA/EIA-485,是由美国电子工业协会(EIA)在1983年批准的一种信号传输标准。它是一种定义平衡数字多点系统中的驱动器和接收器的电气特性的标准,该标准主要用于工业控制环境的通讯协议。RS-485是一种广泛应用于工业控制领域的通信标准,它的设计和实施考虑到了电磁干扰和信号传输的需求,确保即使在恶劣的环境条件下也能有效地传输信息。
简单的说,我们需要实现的就是以下流程:
首先输入G-code的一些命令给数控设备,其次数控设备将G-code按照应用层协议(如Modbus等)转化为报文,然后通过RS-485总线发送报文给电机的控制器,控制器接收到指令后再给电机发脉冲,最后电机接收到脉冲开始转动。
那么又该怎么去做这个流程呢,通过CNC软件的内置函数制作脚本是一种思路。我们不妨做一个简单的示例,抛砖引玉。
设备名称 | 数量 |
windows7及以上电脑 | 1台 |
USB-485转换器 | 1个 |
谱思PMC007Bx一体化步进电机 | 若干 |
PlanetCNC软件 | 1套 |
对应到具体的操作上可以分为两步:
1.将G-code命令将转化为PMC007Bx使用的Modbus—RTU指令。
2. 将指令发送给电机,电机就会执行对应的命令,并按照Modbus协议返回响应报文,计算机读取响应值,判断状态。
先来看一下第一步中用到的内置函数:
array_new() –这个是生成一个空数组
array_setdata(hnd,pos, data) –向数据中写入数据。hnd是句柄;pos起始位,程序里都是从头写,填0就好;data是需要发送数据。
array_crc16(hnd, pos, len) –计算modbus-rtu使用的16位的crc校验。hnd为需要计算校验的句柄,pos是起始位;同样填0就好;len为选取数据的长度,当写-1时,就会一直选取数据到倒数第一位,也就是选取所有数据。
同样的介绍一下串口通讯部分的函数:
serial_open(port,baudrate,bits,parity,stopbits,flowcontrol)–打开串口。port为计算机COM口名,字符串类型,比如COM5;baudrate,波特率,pmc007bx系列默认9600;bits位,填8;parity,奇偶校验,选择无校验,填0;stopbits,停止位,填1;flowcontrol,数据流控,填0。
serial_writearray(port,hnd) –通过已经打开的com口将数组中的数据发送到总线上。port,为已经打开的COM口名;hnd为数组句柄。
serial_readarray(port,hnd,size,timeout) –通过已经打开的com口读取接收的数据。
OnInit—这个函数代表当PlanetCNC运行后自动执行的一个函数,我们可以在其中调用serial_open(),这样软件打开就会自动开启COM口。
这是所有封装函数,放置在Expr_PMC007bx.txt文件中:
#OnInit
port = "COM14";
baudrate = 9600;
bits = 8;
parity = 0;
stopbits = 1;
flowcontrol = 0;
serial_open(port, baudrate, bits, parity, stopbits, flowcontrol);
#Modbus_Relay
debug('BEGIN #Modbus_Relay');
.addr = .arg1;
.fc = .arg2;
.relay_number_h = .arg3;
.relay_number_l = .arg4;
.relay_state_h = .arg5;
.relay_state_l = .arg6;
.resp_size = 16;
.payload = array_new();
array_setdata(.payload, 0, .addr, .fc, .relay_number_h, .relay_number_l, .relay_state_h, .relay_state_l);
.rc = exec(.payload, .resp_size, '#Modbus_Write_ReadData');
if(.rc != 0, exec(array_delete(.payload), return(-1)));
array_delete(.payload);
debug('END #Modbus_Relay');
#Modbus_Write_ReadData
debug(str(" ",2),'BEGIN #Modbus_Write_ReadData');
.payload = .arg1;
.resp_size = .arg2;
;COM port init
.rc = serial_open(port, baudrate, bits, parity, stopbits, flowcontrol);
if(.rc != 0, exec(debug('COM port not available'), return(-1)));
.addr = array_getdata(.payload, 0);
.fc = array_getdata(.payload, 1);
;crc16 calculation
.crc = array_crc16(.payload, 0, -1);
;set array data with crc
array_setdata16(.payload, -1, .crc);
;send array data
serial_writearray(port, .payload);
array_clear(.payload);
;--------------------------------------------------------------------------
;read array data
serial_readarray(port, .payload, 150);
array_printdata(.payload);
;check returned array data
.rc = exec(.payload, .addr, .fc, .resp_size, '#Check');
if (.rc, exec(debug('response check failed with error code: ', .rc), serial_close(port), return(-1)));
serial_close(port);
debug(str(" ",2),'END #Modbus_Write_ReadData');
return(0);
#Check
debug(str(" ",3),'BEGIN #Check');
.hnd = .arg1;
.addr = .arg2;
.fc = .arg3;
.size = .arg4;
;compare size with array size
if (.size != array_size(.hnd), return(-1));
;read crc1 from data
.crc1 = array_getdata16(.hnd, .size - 2);
;calc crc2 from data
.crc2 = array_crc16(.hnd, 0, .size - 2);
if(.crc1 != .crc2, return(-2));
debug(str(" ",4),'CRC OK: ', .crc2);
;compare addr with data from array
if(.addr != array_getdata(.hnd, 0), return(-3));
debug(str(" ",4),'Address OK: ', .addr);
;compare fc with data from array
if(.fc != array_getdata(.hnd, 1), return(-4));
debug(str(" ",4),'Function Code OK: ', .fc);
debug(str(" ",3),'END #Check');
return(0);
这是M03.gcode脚本文件中的代码
;M3 code,正转:
(expr, exec(0x1, 0x06, 0x60, 0x0c, 0x00, 0x20, "#Modbus_Relay"))
(expr, exec(0x1, 0x06, 0x60, 0x0d, 0x03, 0xe8, "#Modbus_Relay"))
(expr, exec(0x1, 0x06, 0x60, 0x03, 0x00, 0x00, "#Modbus_Relay"))
(expr, exec(0x1, 0x06, 0x60, 0x04, 0x7d, 0x00, "#Modbus_Relay"))
(expr, exec(0x1, 0x06, 0x60, 0x02, 0x00, 0x01, "#Modbus_Relay"))
(expr, exec(0x1, 0x06, 0x60, 0x05, 0x00, 0x00, "#Modbus_Relay"))
(expr, exec(0x1, 0x06, 0x60, 0x06, 0x7d, 0x00, "#Modbus_Relay"))
M3
将Expr_PMC007bx.txt放到.\PlanetCNC\Profiles\Default目录下,M3.gcode文件放到.\PlanetCNC\Profiles\Default\Scripts目录下,在软件中直接使用与.gcode指令同名的M指令(比如M5)就可以控制电机。这样就实现了通过g-code直接和RS-485总线控制步进电机。
以上就是一个最基础的通讯控制案例,其中可以优化的地方还非常的多。比如添加接收超时的重发机制,而不是直接进行下一条的发送;命令含义不同可以进行分类处理,而不是直接丢到流程里统一反复发送;使用状态机对实际流程中的事件进行分类判断,而不是简单的执行单一流程等等。