Simulink模型和Maxon EPOS4驱动器在倍福TwinCAT中接口文件的编写
概要
笔者水平有限,以下说明中若有错误欢迎指正!
笔者近期需要配置EPOS4驱动器和倍福TwinCAT的接口映射,本文主要介绍Simulink模型如何导入TwinCAT中作为PLC任务、Simulink模型输入输出与驱动器的接口文件如何编写以及接口文件代码编写所需的基础知识(CANopen总线、DSP402协议),如需浏览代码可直接跳转至最后,代码中有足够的注释,若有不懂的地方可再浏览前面的基础知识和参考链接。笔者有12个驱动器需要做映射,Simulink模型中的输入量为电机转速和电机转角,输出为电机力矩。
写接口前的准备
前提:已正确配置TE1400模块,可以顺利导出Simulink模型到TwinCAT中,如何配置及导出模型参考上篇文章1,若希望Simulink模型作为一个控制器模型被PLC条件调用,即只有触发了输入条件才可以执行Simulink模型,回到Simulink模型,在Configuration中找到CallBy,设置为Module:
按照之前的文章设置System target file为TwinCAT.tlc,设置求解器为固定步长,设置好步长,之后对这个模型进行重新编译生成模型:
点击reload重新上载模型,把新的模型添加到TcCOM:
在解决方案管理器中在PLC处点击右键添加新项:
选择Standard PLC Project,命名并选择保存位置:

在新建的PLC下的project处右键,选择Import PLCopenXML:

找到刚才Simulink编译导出的C++文件夹中的PlcOpenPOUs.xml文件,点击打开:

直接点击OK即可:

编程基础
以下部分参考资料链接在最后,如果哪里有不懂建议阅读原书/原文档,推荐阅读《EtherCAT:工业以太网应用技术》2,CANopen轻松入门笔记3,DSP402驱动协议4。
若想进一步了解可参考EPOS4 Application Notes5,EPOS4 Communication Guide6,EPOS4 Firmware Specification7,EPOS4 Firmware Version «Readme»8,【Maxon驱动器与TwinCAT接口基础】EtherCAT通讯简介9。
设备控制状态机
伺服驱动器需要依据CiA 402描述的设备子协议进行控制,主站控制器通过修改6040h控制字(Control Word)来操作伺服驱动器的运行状态,同时通过读6041h状态字(Status Word)来获取驱动器的当前状态。
状态机描述了控制器的状态以及主机的控制方式,是CiA 402伺服驱动器应用协议运行的基础,如下图所示:
状态机的各状态说明见下表:
状态名称 | 说明 |
---|---|
未准备好接通电源 (Not Ready to Switch On) | 控制器上电后,伺服驱动器进行初始化过程,在初始化未完成前,一直处于本状态 |
不可接通电源 (Switch On Disabled) | 伺服驱动器初始化完成 |
准备好接通电源 (Ready to Switch On) | 控制电已上,动力电使能开关关闭,电机无力矩 |
已开始供电 (Switched on) | 动力电已上,电机无力矩,伺服驱动器已做好按配置功能控制电机的准备 |
可操作 (Operation Enable) | 伺服驱动器按配置功能控制电机,电机有力矩输出 |
急停状态 (Quick Stop Activ) | 伺服驱动器按照设定停机 |
出错反应 (Fault Reaction Activ) | 驱动器内部报警,并按设定的运行方式停机,电机有力矩输出 |
出错 (Fault) | 报警状态,电机无力矩 |
状态转换由驱动器中的内部事件或主站通过控制字发出的命令引起:
状态转换序号 | From To | 驱动器内部事件/从主站接收控制字 | 动作 |
---|---|---|---|
0 | 开始 ⇒ \Rightarrow ⇒未准备好接通电源 | 驱动器复位(Reset) | 驱动器自检/自初始化 |
1 | 未准备好接通电源 ⇒ \Rightarrow ⇒不可接通电源 | 驱动器自检/自初始化成功 | 激活通讯 |
2 | 不可接通电源 ⇒ \Rightarrow ⇒准备好接通电源 | “Shutdown”指令 | 无 |
3 | 准备好接通电源 ⇒ \Rightarrow ⇒已开始供电 | “Switch on”指令 | 上动力电 |
4 | 已开始供电 ⇒ \Rightarrow ⇒可操作 | “Enable Operation”指令 | 驱动操作使能 |
5 | 可操作 ⇒ \Rightarrow ⇒已开始供电 | “Disable Operation”指令 | 驱动操作去使能 |
6 | 已开始供电 ⇒ \Rightarrow ⇒准备好接通电源 | “Shutdown”指令 | 关动力电 |
7 | 准备好接通电源 ⇒ \Rightarrow ⇒不可接通电源 | “Quick Stop”和“Disable Voltage”指令 | 无 |
8 | 可操作 ⇒ \Rightarrow ⇒准备好接通电源 | “Shutdown”指令 | 立即关闭动力电,若无抱闸,电机可自由旋转 |
9 | 可操作 ⇒ \Rightarrow ⇒不可接通电源 | “Disable Voltage”指令 | 同上 |
10 | 已开始供电 ⇒ \Rightarrow ⇒不可接通电源 | “Quick Stop”或“Disable Voltage”指令 | 同上 |
11 | 可操作 ⇒ \Rightarrow ⇒急停状态 | “Quick Stop”指令 | 执行急停功能 |
12 | 急停状态 ⇒ \Rightarrow ⇒不可接通电源 | 急停完成或“Disable Voltage”指令 | 关动力电 |
13 | 所有状态 ⇒ \Rightarrow ⇒出错反应 | 驱动器中发生错误 | 执行故障反应功能 |
14 | 出错反应 ⇒ \Rightarrow ⇒出错 | 出错反应完成 | 驱动操作去使能 |
15 | 出错 ⇒ \Rightarrow ⇒未准备好接通电源 | “Fault Reset”指令 | 离开故障状态后,控制字的“Fault Reset”位必须由主站清除 |
16 | 急停状态 ⇒ \Rightarrow ⇒可操作 | “Enable Operation”指令 | 驱动操作使能 |
只要有报警状态出现,状态机将自动进入“出错”状态。控制器上电后,伺服驱动器将进行初始化,当初始化完成后,状态机自动切换到“不可接通电源”状态。
6040h控制字(ControlWord)
控制字为16位,其中位0~3和位7构成了状态机跳转的控制字指令,各种跳转条件见下表,x代表任意:
指令 | 位7 故障复位 | 位3 使能运行 | 位2 快速停机 | 位1 使能电源 | 位0 接通电源 | 控制字 位7~位0 | 对应转换 |
---|---|---|---|---|---|---|---|
Fault Reset | 1 | x | x | x | x | 1xxxxxxx | 15 |
Shutdown | 0 | x | 1 | 1 | 0 | 0xxxx110 | 2,6,8 |
Switch on | 0 | 0 | 1 | 1 | 1 | 0xxx0111 | 3 |
Enable Operation | 0 | 1 | 1 | 1 | 1 | 0xxx1111 | 4,16 |
Disable Operation | 0 | 0 | 1 | 1 | 1 | 0xxx0111 | 5 |
Quick Stop | 0 | x | 0 | 1 | x | 0xxxx01x | 7,10,11 |
Disable Voltage | 0 | x | x | 0 | x | 0xxxxx0x | 7,9,10,12 |
6041h状态字(StatusWord)
状态字为16位,其中位0~3和位5、6代表了伺服驱动器状态机所处的状态,定义见下表,x代表任意:
状态 | 位6 (Switch On Disabled) | 位5 (Quick Stop Activ) | 位3 (Fault) | 位2 (Operation Enable) | 位1 (Switched on) | 位0 (Ready to Switch On) | 状态字 位6~位0 |
---|---|---|---|---|---|---|---|
未准备好接通电源 (Not Ready to Switch On) | 0 | x | 0 | 0 | 0 | 0 | 0xx0000 |
不可接通电源 (Switch On Disabled) | 1 | x | 0 | 0 | 0 | 0 | 1xx0000 |
准备好接通电源 (Ready to Switch On) | 0 | 1 | 0 | 0 | 0 | 1 | 01x0001 |
已开始供电 (Switched on) | 0 | 1 | 0 | 0 | 1 | 1 | 01x0011 |
可操作 (Operation Enable) | 0 | 1 | 0 | 1 | 1 | 1 | 01x0111 |
急停状态 (Quick Stop Activ) | 0 | 0 | 0 | 1 | 1 | 1 | 00x0111 |
出错反应 (Fault Reaction Activ) | 0 | x | 1 | 1 | 1 | 1 | 0xx1111 |
出错 (Fault) | 0 | x | 1 | 0 | 0 | 0 | 0xx1000 |
数据类型
数据类型 | 数据描述 | 数值区间 | 占据位数 |
---|---|---|---|
BOOL | 布尔值 | {0,1}(FALSE/TRUE) | 8(理论1位,实际1字节9) |
SINT | 有符号短整数 | -128~127 | 8 |
INT | 有符号整数 | -32768~32767 | 16 |
DINT | 有符号整数 | − 2 32 − 1 -2^{32}-1 −232−1~ 2 32 − 1 2^{32}-1 232−1 | 32 |
UINT | 无符号整数 | 0~65535 | 16 |
REAL | 32位浮点数 | − 3.4 × 1 0 38 -3.4\times 10^{38} −3.4×1038~ 3.4 × 1 0 38 3.4\times 10^{38} 3.4×1038 | 32 |
LREAL | 64位浮点数 | − 1.8 × 1 0 308 -1.8\times 10^{308} −1.8×10308~ 1.8 ∗ 1 0 308 1.8*10^{308} 1.8∗10308 | 64 |
编写接口程序
由于CSDN不支持Structured Text语言高亮,想看代码高亮可自行下载VSCode-ST语言插件。首先声明程序中用到的常量,常量在系统初始化完成后,只能进行读操作,不能赋值:
PROGRAM MAIN
VAR CONSTANT //定义常量
PI : REAL:=3.141592653;
END_VAR
在TcCOM中加载的模型上双击查看模型的Object ID:
对于模型接口功能块进行变量声明,在oid中输入TcCOM中模型的object ID:
VAR
fb_test : FB_testSimulinkModel(oid:=16#01010010);
END_VAR
随后在程序中就可以调用相应的method进行模型调用,并且也可以直接访问到输入输出等参数进行赋值。
最后分配模型的Task为PlcTask(必须和所调用的PLC的Task一致):
最终接口程序
PROGRAM MAIN
//程序说明
//将12个电机分为4组,每组3个电机;从根部到底部为1~4组,第1组为ECi52,28Nm;第2~4组为ECi40,18Nm;
//修改System_Enable的数值可以指令使能第几组电机
//修改EnableJointFlag的数值可以指令使能第几个电机
//SystemReadyCount变量统计每一组中电机使能成功的数量
//修改modechange的值调整电机的控制方式,0:速度环;1:电流环
//速度环时,修改Label的值可直接通过手柄操控各电机运动,1~4对应第1~4组电机,按键映射见下
VAR CONSTANT
PI : REAL:=3.141592653; //声明常量数值
END_VAR
VAR
fb_test : FB_testSimulinkModel(oid:=16#01010010);
input:BOOL:=TRUE; //条件调用PLC,input为真,使能模型
(****** Enable command ******)
System_Enable : ARRAY [1..4] OF BOOL:=[1,1,1,1]; //12个电机分为4组,每一组的使能标志
EnableJointFlag : ARRAY [1..4, 1..3] OF BOOL := [ //输入标志,指示是否尝试使能电机
[1, 1, 1],
[1, 1, 1],
[1, 1, 1],
[1, 1, 1]
];
Enable_Succeed : ARRAY [1..4, 1..3] OF BOOL; //输出标志,指示电机是否成功进入操作使能状态
StatusWord : ARRAY [1..4, 1..3] OF UINT; //12个驱动器的状态字组合成二维数组
ControlWord : ARRAY [1..4, 1..3] OF UINT; //12个驱动器的控制字组合成二维数组
SystemReadyCount1 : INT:=0; //统计第1组电机使能成功数量
SystemReadyCount2 : INT:=0; //统计第2组电机使能成功数量
SystemReadyCount3 : INT:=0; //统计第3组电机使能成功数量
SystemReadyCount4 : INT:=0; //统计第4组电机使能成功数量
ActualVelocity : ARRAY[1..4, 1..3] OF LREAL; //12个电机输出端编码器反馈角速度(rad/s)
ActualPosition : ARRAY[1..4, 1..3] OF LREAL; //12个电机输出端编码器反馈角度(rad)
TargetVelocity : ARRAY[1..3] OF DINT; //D速度环单独调整每组电机输出端期望角速度(pulses/s)
// 从根部到端部分为第1~4组,第1组为ECi52,28Nm;第2~4组为ECi40,18Nm
Label : INT:=0; //控制单独动哪一组关节
group : INT; //计数变量,第group组电机,每组3个
i : INT; //计数变量,每组第i个电机
MotorReductionRatio : INT:= 100; //电机齿轮箱减速比
modechange : INT:= 0; //modechange切换电机控制方式,0:速度环;1:电流环
// 绝对编码器初始位置
Position_Initial1 : ARRAY[1..6] OF DINT:=[0,0,0,0,0,0];
Position_Initial2 : ARRAY[1..6] OF DINT:=[0,0,0,0,0,0];
Position_Initial3 : ARRAY[1..6] OF DINT:=[0,0,0,0,0,0];
Position_Initial4 : ARRAY[1..6] OF DINT:=[0,0,0,0,0,0];
// 手柄各键的变量映射
Key1 :DINT; // Y 键
Key2 :DINT; // B 键
Key3 :DINT; // A 键
Key4 :DINT; // X 键
Key5 :DINT; // LB 键
Key6 :DINT; // RB 键
L1 :DINT; // LT 键
L2 :DINT; // BACK 键
R1 :DINT; // T 键
R2 :DINT; // START 键
END_VAR
VAR_INPUT
接收驱动器的输入
Statusword_1 AT %I*: ARRAY[1..3] OF UINT;
StatusWord_2 AT %I*: ARRAY[1..3] OF UINT;
StatusWord_3 AT %I*: ARRAY[1..3] OF UINT;
StatusWord_4 AT %I*: ARRAY[1..3] OF UINT;
ActualVelocity1 AT %I*: ARRAY[1..3] OF DINT; // unit: Inc/s 每秒脉冲数
ActualVelocity2 AT %I*: ARRAY[1..3] OF DINT; // unit: Inc/s 每秒脉冲数
ActualVelocity3 AT %I*: ARRAY[1..3] OF DINT; // unit: Inc/s 每秒脉冲数
ActualVelocity4 AT %I*: ARRAY[1..3] OF DINT; // unit: Inc/s 每秒脉冲数
ActualPosition1 AT %I*: ARRAY[1..3] OF DINT; // unit: Inc 脉冲数
ActualPosition2 AT %I*: ARRAY[1..3] OF DINT; // unit: Inc 脉冲数
ActualPosition3 AT %I*: ARRAY[1..3] OF DINT; // unit: Inc 脉冲数
ActualPosition4 AT %I*: ARRAY[1..3] OF DINT; // unit: Inc 脉冲数
TorqueActualValue1 AT %I*: ARRAY[1..3] OF INT; // unit: 28/1000 N*m
TorqueActualValue2 AT %I*: ARRAY[1..3] OF INT; // unit: 16/1000 N*m
TorqueActualValue3 AT %I*: ARRAY[1..3] OF INT; // unit: 16/1000 N*m
TorqueActualValue4 AT %I*: ARRAY[1..3] OF INT; // unit: 16/1000 N*m
END_VAR
VAR_OUTPUT
向驱动器输出目标值
ControlWord_1 AT %Q*: ARRAY[1..3] OF UINT;
ControlWord_2 AT %Q*: ARRAY[1..3] OF UINT;
ControlWord_3 AT %Q*: ARRAY[1..3] OF UINT;
ControlWord_4 AT %Q*: ARRAY[1..3] OF UINT;
TargetVelocity1 AT %Q*: ARRAY[1..3] OF DINT; // unit: 1000rpm
TargetVelocity2 AT %Q*: ARRAY[1..3] OF DINT; // unit: 1000rpm
TargetVelocity3 AT %Q*: ARRAY[1..3] OF DINT; // unit: 1000rpm
TargetVelocity4 AT %Q*: ARRAY[1..3] OF DINT; // unit: 1000rpm
ModeOfOperation1 AT %Q*: ARRAY[1..3] OF SINT; // 9:速度环,10:力矩环
ModeOfOperation2 AT %Q*: ARRAY[1..3] OF SINT;
ModeOfOperation3 AT %Q*: ARRAY[1..3] OF SINT;
ModeOfOperation4 AT %Q*: ARRAY[1..3] OF SINT;
TargetTorque1 AT %Q*: ARRAY[1..3] OF INT:=[0,0,0,0,0,0]; // unit: 28/1000 N*m
TargetTorque2 AT %Q*: ARRAY[1..3] OF INT:=[0,0,0,0,0,0]; // unit: 16/1000 N*m
TargetTorque3 AT %Q*: ARRAY[1..3] OF INT:=[0,0,0,0,0,0]; // unit: 16/1000 N*m
TargetTorque4 AT %Q*: ARRAY[1..3] OF INT:=[0,0,0,0,0,0]; // unit: 16/1000 N*m
END_VAR
//变量声明结束
//逻辑计算开始
IF input THEN
fb_test.Execute(); //input为真,则调用之前定义的功能块实例(Simulink模型)
END_IF
(******分成4组,每组3个电机******)
FOR i:=1 TO 3 BY 1 DO
StatusWord[1, i] := StatusWord_1[i]; //将驱动器输入的状态字写入StatusWord二维数组中
StatusWord[2, i] := StatusWord_2[i];
StatusWord[3, i] := StatusWord_3[i];
StatusWord[4, i] := StatusWord_4[i];
END_FOR
//读状态字,根据状态字发控制字,使能电机
FOR group := 1 TO 4 BY 1 DO //遍历四组电机
FOR i := 1 TO 3 BY 1 DO //每一组从1到3遍历
IF System_Enable[group] = 1 THEN //检验第一组作为整个系统是否使能
IF (EnableJointFlag[group,i]) THEN //检验第一组中每个电机是否使能
//状态字和2#1001111按位与操作,校验状态字的位7、位3、位2、位1、位0,根据当前状态和状态转换条件发送控制字
//检验状态字是否为Fault状态(2#0xx1000)
IF (StatusWord[group, i] AND (2#1001111))=2#0001000 THEN
ControlWord[group, i]:=2#10000000; //若为Fault状态,则Reset Fault,控制字2#1xxxxxx
END_IF
//检验状态字是否为Switch On Disabled状态(2#1xx0000)
IF (StatusWord[group, i] AND (2#1001111))=2#1000000 THEN
Controlword[group, i]:=2#00000110; //若为Switch On Disabled状态,则Shutdown,控制字2#0xxxx110
Enable_Succeed[group, i]:=FALSE; //使能标志为FALSE
END_IF
//状态字和2#1101111按位与操作,校验状态字的位7、位6、位3、位2、位1、位0,根据当前状态和状态转换条件发送控制字
//检验状态字是否为Ready to Switch On状态(2#01x0001)
IF (StatusWord[group, i] AND (2#1101111))=2#0100001 THEN
ControlWord[group, i]:=2#00000111; //若为Ready to Switch On状态,则Switch On,控制字(2#0xxx0111)
END_IF
//检验状态字是否为Switched On状态(2#01x0011)
IF (StatusWord[group, i] AND (2#1101111))=2#0100011 THEN
ControlWord[group, i]:=2#00001111; //若为Switched On状态,则Enable Operation,控制字(2#0xxx1111)
END_IF
//检验状态字是否为Operation Enable状态(2#01x0111)
IF (StatusWord[group, i] AND (2#1101111))=2#0100111 THEN
Enable_Succeed[group, i]:=TRUE; //使能成功,标志为TRUE
END_IF
ELSE
ControlWord[group, i]:=2#00000110; //电机使能标志为0,即EnableJointFlag_1[i1]=0,则Shutdown,控制字2#0xxxx110
END_IF
END_IF
END_FOR
END_FOR
FOR i:=1 TO 3 BY 1 DO
ControlWord_1[i] := ControlWord[1, i]; //将ControlWord二维数组按对应关系写入各组控制字中输出
ControlWord_2[i] := ControlWord[2, i];
ControlWord_3[i] := ControlWord[3, i];
ControlWord_4[i] := ControlWord[4, i];
END_FOR
//统计每组电机中使能成功的电机数量
FOR i:=1 TO 3 BY 1 DO
IF Enable_Succeed[1, i]=TRUE THEN
SystemReadyCount1 := SystemReadyCount1+1;
END_IF
IF Enable_Succeed[2, i]=TRUE THEN
SystemReadyCount2 := SystemReadyCount2+1;
END_IF
IF Enable_Succeed[3, i]=TRUE THEN
SystemReadyCount3 := SystemReadyCount3+1;
END_IF
IF Enable_Succeed[4, i]=TRUE THEN
SystemReadyCount4 := SystemReadyCount4+1;
END_IF
END_FOR
// 以下为手柄控制接口,调节单组电机,Key1对应Y键,Key2对应B键,Key3对应A键
IF (R2=1) THEN //对应手柄Start键按下,各电机正向转动
IF (Key1=1) THEN //Y键按下,电机1正转
TargetVelocity[1]:=200000;
ELSE
TargetVelocity[1]:=0;
END_IF
IF (Key2=1) THEN //B键按下,电机2正转
TargetVelocity[2]:=200000;
ELSE
TargetVelocity[2]:=0;
END_IF
IF (Key3=1) THEN //A键按下,电机3正转
TargetVelocity[3]:=200000;
ELSE
TargetVelocity[3]:=0;
END_IF
ELSE //对应手柄Start键未按下,各电机反向转动
IF (Key1=1) THEN //Y键按下,电机1反转
TargetVelocity[1]:=-200000;
ELSE
TargetVelocity[1]:=0;
END_IF
IF (Key2=1) THEN //B键按下,电机2反转
TargetVelocity[2]:=-200000;
ELSE
TargetVelocity[2]:=0;
END_IF
IF (Key3=1) THEN //A键按下,电机3反转
TargetVelocity[3]:=-200000;
ELSE
TargetVelocity[3]:=0;
END_IF
END_IF
// 通过修改Label值,调节第Label组电机
IF (Label = 1) OR (Label = 2) OR (Label = 3) OR (Label = 4) THEN
CASE Label OF
1: // 设置TargetVelocity1
TargetVelocity1 := TargetVelocity;
2: // 设置TargetVelocity2
TargetVelocity2 := TargetVelocity;
3: // 设置TargetVelocity3
TargetVelocity3 := TargetVelocity;
4: // 设置TargetVelocity4
TargetVelocity4 := TargetVelocity;
END_CASE;
END_IF;
// 1为电流环,0位速度环
IF modechange=1 THEN
FOR i:=1 TO 3 BY 1 DO
ModeOfOperation1[i]:=10;
ModeOfOperation2[i]:=10;
ModeOfOperation3[i]:=10;
ModeOfOperation4[i]:=10;
END_FOR
ELSE
FOR i:=1 TO 3 BY 1 DO
ModeOfOperation1[i]:=9;
ModeOfOperation2[i]:=9;
ModeOfOperation3[i]:=9;
ModeOfOperation4[i]:=9;
END_FOR
END_IF
// 速度单位转换:每秒脉冲数 --> rad/s,单圈19位编码器,每转2^19=524288个脉冲,转数乘2*PI转换为rad,除以减速比得到输出端速度
// 角度单位转换:脉冲数 --> rad,单圈19位编码器,每转2^19=524288个脉冲,转数乘2*PI转换为rad,减速比只影响角速度,角度无须除以减速比
FOR i:=1 TO 3 DO //遍历每组的三个电机
ActualVelocity[1, i] := DINT_TO_LREAL(ActualVelocity1[i])/524288*2*PI/MotorReductionRatio;
ActualVelocity[2, i] := DINT_TO_LREAL(ActualVelocity2[i])/524288*2*PI/MotorReductionRatio;
ActualVelocity[3, i] := DINT_TO_LREAL(ActualVelocity3[i])/524288*2*PI/MotorReductionRatio;
ActualVelocity[4, i] := DINT_TO_LREAL(ActualVelocity4[i])/524288*2*PI/MotorReductionRatio;
ActualPosition[1, i] := DINT_TO_LREAL(ActualPosition1[i]-Position_Initial1[i])/524288*2*PI;
ActualPosition[2, i] := DINT_TO_LREAL(ActualPosition2[i]-Position_Initial2[i])/524288*2*PI;
ActualPosition[3, i] := DINT_TO_LREAL(ActualPosition3[i]-Position_Initial3[i])/524288*2*PI;
ActualPosition[4, i] := DINT_TO_LREAL(ActualPosition4[i]-Position_Initial4[i])/524288*2*PI;
END_FOR
// 角速度(rad/s)赋值给Simulink模型的输入,在TwinCAT3中手动设置映射
fb_test.stInput.velocity1_1 := ActualVelocity[1, 1];
fb_test.stInput.velocity1_2 := ActualVelocity[1, 2];
fb_test.stInput.velocity1_3 := ActualVelocity[1, 3];
fb_test.stInput.velocity2_1 := ActualVelocity[2, 1];
fb_test.stInput.velocity2_2 := ActualVelocity[2, 2];
fb_test.stInput.velocity2_3 := ActualVelocity[2, 3];
fb_test.stInput.velocity3_1 := ActualVelocity[3, 1];
fb_test.stInput.velocity3_2 := ActualVelocity[3, 2];
fb_test.stInput.velocity3_3 := ActualVelocity[3, 3];
fb_test.stInput.velocity4_1 := ActualVelocity[4, 1];
fb_test.stInput.velocity4_2 := ActualVelocity[4, 2];
fb_test.stInput.velocity4_3 := ActualVelocity[4, 3];
// 角度(rad)赋值给Simulink模型的输入,在TwinCAT3中手动设置映射
fb_test.stInput.position1_1 := ActualPosition[1, 1];
fb_test.stInput.position1_2 := ActualPosition[1, 2];
fb_test.stInput.position1_3 := ActualPosition[1, 3];
fb_test.stInput.position2_1 := ActualPosition[2, 1];
fb_test.stInput.position2_2 := ActualPosition[2, 2];
fb_test.stInput.position2_3 := ActualPosition[2, 3];
fb_test.stInput.position3_1 := ActualPosition[3, 1];
fb_test.stInput.position3_2 := ActualPosition[3, 2];
fb_test.stInput.position3_3 := ActualPosition[3, 3];
fb_test.stInput.position4_1 := ActualPosition[4, 1];
fb_test.stInput.position4_2 := ActualPosition[4, 2];
fb_test.stInput.position4_3 := ActualPosition[4, 3];
//转矩单位转换,将Simulink模型中输出的转矩(N*m)转换为电机转矩(千分之一额定转矩)
// ECi40-36V 输出端额定转矩16N*m,ECi52-36V 额定转矩28N*m
TargetTorque1[1]:=LREAL_TO_INT(fb_test.stOutput.torque1_1/28*1000);
TargetTorque1[2]:=LREAL_TO_INT(fb_test.stOutput.torque1_2/28*1000);
TargetTorque1[3]:=LREAL_TO_INT(fb_test.stOutput.torque1_3/28*1000);
TargetTorque2[1]:=LREAL_TO_INT(fb_test.stOutput.torque2_1/16*1000);
TargetTorque2[2]:=LREAL_TO_INT(fb_test.stOutput.torque2_2/16*1000);
TargetTorque2[3]:=LREAL_TO_INT(fb_test.stOutput.torque2_3/16*1000);
TargetTorque3[1]:=LREAL_TO_INT(fb_test.stOutput.torque3_1/16*1000);
TargetTorque3[2]:=LREAL_TO_INT(fb_test.stOutput.torque3_2/16*1000);
TargetTorque3[3]:=LREAL_TO_INT(fb_test.stOutput.torque3_3/16*1000);
TargetTorque4[1]:=LREAL_TO_INT(fb_test.stOutput.torque4_1/16*1000);
TargetTorque4[2]:=LREAL_TO_INT(fb_test.stOutput.torque4_2/16*1000);
TargetTorque4[3]:=LREAL_TO_INT(fb_test.stOutput.torque4_3/16*1000);
倍福TE1400组件安装指南:https://blog.csdn.net/weixin_43807835/article/details/140323746 ↩︎
《EtherCAT 工业以太网控制技术》(豆瓣):https://book.douban.com/subject/35077018/ ↩︎
《CANopen轻松入门笔记》:https://pan.quark.cn/s/eaf6869011b6 ↩︎
dsp402协议(英文原版):https://pan.quark.cn/s/a3db4d87ac0f ↩︎
EPOS4 Application Notes:https://pan.quark.cn/s/a257526dcecc ↩︎
EPOS4 Communication Guide:https://pan.quark.cn/s/5951eaf2047a ↩︎
EPOS4 Firmware Spacification:https://pan.quark.cn/s/8c44e6abb4d0 ↩︎
EPOS4 Firmware Version 《Readme》:https://pan.quark.cn/s/8c44e6abb4d0 ↩︎
为什么C语言中bool型变量占用一个字节:https://blog.csdn.net/LANGQING12345/article/details/40623241 ↩︎ ↩︎