本文主要讲述CODESYS Runtime具体的移植过程,分别从硬件、软件方面分别进行阐述,抛砖引玉,让大家有个大体的了解。

1. 移植步骤

  1. 搭建硬件环境,如x86板子
  2. 移植操作系统,如实时Linux
  3. 移植Qt库并设置环境变量
  4. 移植CODESYS Runtime

2. 具体操作步骤

2.1 搭建硬件环境,如x86板子

基于x86平台的控制器在机器人行业的应用场景较为广泛,如Intel的Atom(凌动)、Celeron(赛扬)。x86 CPU主要有以下特点:主频高、性能强、浮点运算快。若不想自己设计硬件,免去各种硬件测试和验证,可考虑购买台湾研华、威强、富士康等公司的x86工控机。若对成本比较敏感,可考虑国内的如苏州创必达、成都阿普奇等。

国内大部分的机器人公司采用核心板+底板的方式设计自主控制器,核心板采购,自己设计底板来满足控制器接口需求。

2.2 移植操作系统、如实时Linux

CODESYS Runtime支持多种操作系统,如Linux、Windows/RTE、VxWorks等。因Windows/RTE和Vxworks操作系统有License费用,对于国内的企业来说,免费的Linux成了不二之选。

Linux官网发布的源码虽支持抢占,但并非实时操作系统。想要把非实时的Linux实时化,主要有以下3种打实时补丁的方式,




codesys runtime 部署到开发板 codesys runtime费用_优先级


若想使用免费的实时Linux操作系统,只能采用Linux+PREEMPT_RT方案。虽然Linux+PREEMPT_RT相对于VxWorks而言,实时性能一般,其任务延时一般小于30us,但完全可以满足机器人控制器的要求。

从Linux官网下载linux-3.18.91内核源码(linux-3.18.91.tar.xz)和其对应的PREEMPT_RT实时补丁(patch-3.18.91-rt98.patch.xz)。当然,也可以移植其它版本的linux源码。

内核源码网址:https://mirrors.edge.kernel.org/pub/linux/kernel/v3.x/

实时补丁网址:https://mirrors.edge.kernel.org/pub/linux/kernel/projects/rt/3.18/

这里说一下实时补丁,PREEMPT_RT实时补丁由匈牙利天才程序员Ingo Molnar设计,完全开源。Ingo Molnar还开发了进程调度器:完全公平调度器(Completely Fair Scheduler),该调度器自linux-2.6.23沿用至今。该实时补丁实时实现技术主要包括以下几个方面,

1) 中断线程化

中断是异步的、是优先级最高的特殊任务,可以抢占任何进程;并且linux在调用中断处理函数时是关闭本地CPU上的全局中断的,若系统有严重的网络和IO负载,中断将非常频繁。上述两点会引起CODESYS实时进程被中断抢占或关闭全局中断后,实时任务长时间得不到执行,导致实时任务出现很大延时和抖动,变得毫无实时性可言。

中断线程化后,将真正的中断处理函数作为内核线程运行并且赋予特定的实时优先级(SCHED_FIFO, MAX_USER_RT_PRIO/2),使真正的中断处理函数运行在进程上下文,中断产生后运行于中断上下文的中断处理函数只是唤醒被线程化的真正的中断处理函数线程。因关中断的时间非常短,再将实时任务优先级设置的比中断线程高,这样实时任务可以作为最高优先级的执行单元来运行,即使在系统高负载下仍能保证实时性。

需要注意的是,并非所有的中断都被线程化了,具有IRQF_NO_THREAD标志的中断不会被线程化,比如系统时钟中断(Tick)、级联中断。

2) 互斥锁(rtmutex)取代自旋锁

自旋锁和互斥锁都用于保护临界资源。两者的区别在于它们对请求持有锁的进程的处理方式。自旋锁会导致请求获取锁的进程一直死等,直到其它进程释放锁。互斥锁会将请求获取锁的进程放到等待队列中,直到其它进程释放锁再唤醒等待队列中的进程。

内核中使用了大量的自旋锁,自旋锁会禁止内核抢占,还可能关闭本地中断,它们将严重影响着系统的实时性。PREEMPT_RT实时补丁使用互斥锁代替自旋锁,原来的自旋锁用原生自旋锁(raw_spinlock_t)替换。尽管互斥锁代替自旋锁会造成性能上的损失,但这些损失可以避免自旋锁造成的延时,完全可以接受。

3) 优先级继承

互斥锁取代自旋锁,必然会造成优先级翻转(Priority Inversion)的情况。即由于多进程共享资源,具有高优先权的进程被低优先级进程阻塞,反而使中等优先级的进程先于高优先级的进程执行。解决优先级翻转问题通常采用优先级继承策略,即高优先权的进程被低优先级进程阻塞时,临时提高低优先级进程的优先级与高优先级进程相同,待被提高优先级进程执行完毕恢复其原来的优先级。至此,高优先级进程不再被阻塞,中等优先级进程不会抢占高优先级进程。

只打上PREEMPT_RT实时补丁还远远不够,还需配置以下内核选项,

a. 设置CPU频率调节策略为performance方式


codesys runtime 部署到开发板 codesys runtime费用_自旋锁_02


CPU频率调节即我们常说的睿频技术,根据场合和需求的不同有不同是策略。linux内核支持5种策略,

a) performance:性能模式,将CPU频率固定工作在其支持的最高运行频率上。

b) powersave:省电模式,将CPU频率固定工作在其支持的最低运行频率上。

c) userspace:用户模式,CPU频率由用户决定,用户通过提供的接口进行配置。

d) ondemand:平衡模式,CPU频率根据负载不同在最大和最小频率间自动调整。

e) conservative:保守模式,CPU频率根据负载不同渐变式调整。

b. 设置抢占模式为完全抢占


codesys runtime 部署到开发板 codesys runtime费用_自旋锁_03


linux内核支持5种抢占模式,

a) No Forced Preemption (Server):不支持抢占

b) Voluntary Kernel Preemption (Desktop):支持被抢占

c) Preemptible Kernel (Low-Latency Desktop):支持低延迟被抢占

d) Preemptible Kernel (Basic RT):满足基本实时系统抢占

e) Fully Preemptible Kernel (RT):支持完全抢占,抢占点多于d项

完成上面内核配置后,编译Linux内核源码(make bzImage -j2),编译完成后,将bzImage镜像文件拷贝到控制器板子上。

上电启动,使用Linux官网提供的rt-tests工具测试实时系统实时性,下图是我在Intel Celeron J1900处理器上测试结果,任务最大延时小于30us,满足控制器实时性需求。


codesys runtime 部署到开发板 codesys runtime费用_linux_04


2.3 移植Qt库并设置环境变量

任何公司购买CODESYS Runtime时,CODESYS方不仅要求购买方提供GCC编译器或GCC交叉编译器,还需提供编译好的Qt4库,因为Runtime默认包括TargetVisu License,TargetVisu的运行依赖Qt库。Runtime具体包括哪些License可查阅开发包中的3S_INFO.txt文件。

若控制器不涉及本地界面开发,如显控一体机,可直接将编译好的Qt库拷贝到根文件系统的/lib/i386-linux-gnu目录或/usr/lib目录,不需设置环境变量。

若控制器设计本地界面开发,可参考后续文章。

2.4 移植CODESYS Runtime

开始移植前,我们先了解一下CODESY Runtime开发包目录结构,


codesys runtime 部署到开发板 codesys runtime费用_linux_05


下面开始移植工作,我们将用到上表中红色字体目录的部分文件,分别为Configuration目录下的3S.dat文件以及Platforms/Linux/Bin目录下的codesyscontrol和CODESYSControl.cfg文件。将上述三个文件拷贝到控制器,更改codesyscontrol为可执行,运行之,启动成功后的打印信息如下所示,


codesys runtime 部署到开发板 codesys runtime费用_linux_06


在CODESYS IDE中新建工程,扫描控制器。若扫描成功,如下所示,恭喜你,万里长征终于迈出了坚实的一步。


codesys runtime 部署到开发板 codesys runtime费用_添加控制器 提示找到不到上下文_07


3. 移植总结

上面的移植教程只是起到提纲挈领作用,其实还有大量的工作需要我们完善,

a) 针对x86平台,Linux的实时性能还可以继续提高,最好能把任务延时控制在20us以内;

b) 应该对codesyscontrol可执行程序做加密处理,防止被别有用心的人利用;

c) 需完善CODESYSControl.cfg配置文件,如设置工程下载目录、配置扫描到控制器名称等;

d) 开发自定义的Component和IoDrv,丰富控制器功能。