第1章 Kithara实时套件概述
1.1 概述
Kithara Software是一家德国的软件公司,专注于实时技术和嵌入式解决方案。
他们为Windows操作系统提供了Kithara RealTime Suite,这是一套实时扩展模块,使Windows能够实现硬实时任务和控制。
Kithara RealTime Suite提供了一系列的实时功能,包括实时调度器、硬实时驱动程序和实时通信机制。它可以将Windows操作系统转变为一个强大的实时平台,适用于许多应用领域,如机器人控制、生产自动化、测试和测量等。
除了实时功能,Kithara RealTime Suite还提供了其他特性,如实时数据采集、实时图形化用户界面、实时网络通信和实时控制器接口等。
Kithara RealTime Suite的使用需要对实时系统操作开发和配置有一定的技术要求。因此,如果您对Kithara软件产品感兴趣,建议您参考官方网站或与Kithara软件团队联系,以获取更详细的信息和支持。
1.2 主要功能
Kithara RealTime Suite是一套针对Windows操作系统的实时解决方案,它提供了实时性能和嵌入式开发所需的功能。以下是Kithara RealTime Suite的一些主要方案和功能:
-
实时控制:Kithara RealTime Suite可以将Windows操作系统转变为一个强大的实时控制平台。它提供一个实时调度器,使开发人员能够编写和执行硬实时任务,实现精确的控制。
-
实时通信:Kithara RealTime Suite支持实时通信机制,包括共享内存、实时IPC(进程间通信)、实时网络通信等,使不同任务之间可以高效地进行通信和数据交换。
-
实时数据采集和处理:Kithara RealTime Suite提供了实时数据采集的功能,使开发人员能够高速读取和处理传感器数据、信号等实时数据,并实时响应。
-
实时图形化用户界面:Kithara RealTime Suite支持实时图形化用户界面(GUI),使开发人员可以创建动态和交互式的实时用户界面,用于监控和操作实时控制系统。
-
实时网络通信:Kithara RealTime Suite提供了实时网络通信库,可以实现实时UDP和实时TCP通信,使实时控制系统可以与其他设备和系统进行实时数据交换和通信。
以上只是Kithara RealTime Suite提供的一些主要方案和功能,该解决方案还具有其他特性和工具,可根据具体应用的需求进行定制和配置。
1.3 Kithara实时套件软件架构
Kithara RealTime Suite是一个组合套件,提供了一系列功能和工具,用于在Windows操作系统上实时开发和控制应用程序。以下是Kithara RealTime Suite的软件架构的主要组件和层级:
-
实时内核(Real-time Kernel):实时内核是Kithara RealTime Suite的核心组件,它提供了基础的实时调度和任务处理功能。实时内核处理任务的优先级和调度,保证任务按照预定的时间和顺序执行,并提供了实时事件和中断处理机制。
-
实时驱动程序(Real-time Drivers):Kithara RealTime Suite包含了一些实时驱动程序,用于与硬件设备进行实时通信和控制。这些驱动程序可以与各种硬件接口和设备通信,如数据采集卡、传感器、执行器等。
-
实时通信库(Real-time Communication Libraries):Kithara RealTime Suite提供了一些实时通信库,用于实现实时数据交换和通信。这些库支持共享内存、实时IPC(进程间通信)、实时网络通信等机制,以便实时任务之间或与外部设备进行实时数据传输。
-
实时文件系统(Real-time File System):Kithara RealTime Suite提供了实时文件系统,可用于实时应用程序中的数据存储和访问。它可以确保实时读写操作的可靠性和实时性能。
-
实时图形化用户界面(Real-time GUI):Kithara RealTime Suite支持实时图形化用户界面的开发,开发人员可以使用这些工具创建动态和交互式的实时监控界面,用于实时控制系统的可视化和操作。
-
实时开发工具(Real-time Development Tools):Kithara RealTime Suite提供了一些实时开发工具,用于辅助实时应用程序的开发和调试。这些工具包括实时调度器分析器、实时事件追踪器和调试器等。
通过以上组件和层级,Kithara RealTime Suite提供了一个完整的软件架构,使开发人员能够在Windows操作系统上进行实时应用程序的开发、控制和监控。请注意,具体的架构和组件可根据实际应用需求进行定制和配置。
第2章 Kithara实时套件详解
2.1 实时操作系统如何与Windows操作系统一起工作
2.2 软实时与硬实时的区别
软实时(Soft Real-Time)和硬实时(Hard Real-Time)是实时系统中常用的两个概念,用于描述任务是否能够在预定的时间内得到满足。
软实时:指的是系统能够在大部分情况下满足任务的实时性要求,但在偶尔的情况下可能会有一些延迟或错过任务的截止时间。软实时系统的主要特点是性能的可预测性较差,对于时间要求并不是非常严格。在软实时系统中,错过任务的截止时间可能会导致性能下降或一些不可预测的情况发生,但不会对系统的稳定性产生严重影响。
硬实时:指的是系统必须能够在严格的时间约束下满足任务的实时性要求,任务的截止时间是绝对不能错过的。硬实时系统要求系统能够以确定性地、一致地和可预测性地响应任务,并确保任务的截止时间不会被延迟。在硬实时系统中,一旦任务的截止时间被错过,可能会导致系统失败、严重事故或其他严重后果。
简而言之,软实时系统在大部分情况下能满足实时性要求,但偶尔可能会有延迟,而硬实时系统则要求在严格的时间约束下绝不能错过任务的截止时间。
需要注意的是,软实时和硬实时并没有严格的界限,而是存在一个连续的实时性要求的范围。在实时系统设计中,需要根据具体应用的需求和性能要求来确定是选择软实时还是硬实时方案。
2.3 为什么使用Windows操作实时操作系统
2.4 Windows实时拓展Kithara
2.5 如何将kithara库添加到QT中使用
如何将kithara库添加到QT中使用_kithara 实时套件_kobesdu的博客-CSDN博客
1 将kithara安装目录D:\ProgramFiles\Kithara\RealTime Suite Demo 10\dev下的以上三个文件复制到新建的工程目录下
2 将以上的.h .cpp文件添加到工程中 此时 编译会报错 所以执行一下 qmake
3 在mainwindow.h里添加文件包含 #include<KrtsDemo.h>
4 此时编译会报错E:\QtProject\KitharaProj\kitharastudy\KRTStest\KRTStest\KrtsDemo.h:135: error:conflicting declaration 'typedef long long unsigned int ulong'
typedef unsigned __int64 ulong;
因此要把 ulong这个类型的定义替换掉
文件krtsdemo.h line 135 把ulong的typedefine替换成其他名字即可
————————————————
2.6 Kithara RTS进程与Qt应用程序间通信(共享内存)
Kithara RTS进程与Qt应用程序间通信(共享内存)_ks_opendriver_阿基米东的博客-CSDN博客
由于基于PC的控制系统在工业自动化生产领域得到了广泛的应用,而运行在PC的主流操作系统Windows本身并不是一个实时操作系统,这限制了PC在某些需要高实时性能控制系统的应用。针对该问题,通常的解决方法是为Windows增加一个可编程的实时子系统,而实现这种功能的软件被称为Windows实时拓展软件。而德国Kithara软件公司正是业界知名的Windows实时拓展软件专家,自1996年开始致力于Windows实时拓展软件的研发,其推出的模块化Windows实时拓展软件Kithara Realtime Suite(KRTS)不仅可以为安装Windows的PC提供优秀的实时性能,而且具有众多功能模块以辅助项目和产品的研发。目前国内外很多大公司都采用其产品,如BOSCH(博世)、SIEMENS(西门子)、ALSTOM(阿尔斯通)等公司。
简单来说,Kithara RTS是德国Kithara软件公司的一个产品,本质是一个Windows实时拓展程序,可以把Windows变成一个实时操作系统。此外Kithara RTS自身具有很多功能模块,如EtherCAT、CANopen、Profibus模块等,可以将Halcon、OpenCV直接载入到Kithara RTS的实时内核中执行。因此,Kithara RTS可以把PC变成现场控制系统,应用于运动控制系统中,如数控系统、机器人、自动化控制系统等。
我们知道,共享内存是程序之间进行数据交互的最基本的方式,而由于Windows和Kithara RTS本身为两个独立的系统,为了能够使两个不同系统之上的程序进行通信,那么就必须开辟一块内存区域用于数据共享。
由于每个应用都有独立的地址空间,所以一个进程一般不会访问其他程序的内存。另外,自己的程序一般不能访问内核内存,因为内核层的内存是受保护的。因此为了在不同应用层程序之间、应用层程序与内核层程序之间的实现快速数据交换,需要申请一块独立的物理内存,Kithara RTS中用于操作共享内存的功能在Base模块。
应用层程序和内核层程序可访问的内存地址空间是不同的,这两部分内存区域是独立的。因此,Kithara中关于共享内存的函数会同时指定两个不同的地址参数。
以下是Kithara RTS中提供的操作共享内存的APIs:
Shared memory
KS_createSharedMem (creates shared memory for data exchange)
KS_freeSharedMem (frees shared memory)
KS_getSharedMem (gives the current address of shared memory)
KS_readMem (reads from kernel memory)
KS_writeMem (writes to kernel memory)
KS_createSharedMemEx (creates shared memory for data exchange)
KS_freeSharedMemEx (frees shared memory)
KS_getSharedMemEx (gives the address of shared memory determined by current context)
KS_querySharedMemInfo (is not implemented yet)
下面以一个简单的示例说明如何使用Kithara RTS中的共享内存,以及Qt应用程序如何通过共享内存与Kithara实时任务通信。
Kithara工程相关配置略过,可以直接在Kithara安装目录中的smp目录下的示例工程中修改,这样就可以省去配置工作。下面是具体实现的源文件,我将它命名为periodicTimerTaskShm.cpp。
#include "..\_KitharaSmp\_KitharaSmp.h"
const char* pCustomerNumber = "DEMO";
//------ CallBackData ------
struct CallBackData {
int counter;
};
const int us = 10;
//----------------------------------------------------------------
// Ctrl + C handler
//----------------------------------------------------------------
bool stopFlag = false;
BOOL WINAPI _keyboardHandler(DWORD key)
{
if(key == CTRL_C_EVENT){
// 当Ctrl+C的时候发生的事情
outputTxt("< Ctrl + C > event happened.");
stopFlag = true;
return true;
}
return false;
}
//------ _callBackA ------
static Error __stdcall _callBackA(void* pArgs, void* pContext) {
CallBackData* pData = (CallBackData*)pArgs;
pData->counter++
return KS_OK;
}
//--------------------------------------------------------
// This is the main program
//--------------------------------------------------------
void runSample() {
Error ksError;
SetConsoleCtrlHandler(_keyboardHandler, TRUE); // 添加事件回调函数
ksError = KS_openDriver(pCustomerNumber);
if (ksError) {
outputErr(ksError, "KS_openDriver", "Maybe incorrect customer number?");
return;
}
//------------------------------------------------------
// Allocation of Sharedmem
//------------------------------------------------------
CallBackData* pAppPtr;
CallBackData* pSysPtr;
ksError = KS_createSharedMem(
(void**)&pAppPtr, // App Pointer
(void**)&pSysPtr, // Sys Pointer
"periodicTimerTaskShm2Qt", // Name
sizeof(CallBackData), // Size
KSF_ALTERNATIVE | KSF_CONTINUOUS); // Flags - KSF_ALTERNATIVE | KSF_CONTINUOUS
if (ksError != KS_OK) {
outputErr(ksError, "KS_createSharedMem", "Failed to allocate shared memory");
KS_closeDriver();
return;
}
// 也可以通过以下方法创建
/*
KSHandle hShmEx;
ksError = KS_createSharedMemEx(&hShmEx, "GSK_TaskTimerCycle2QtSHM", sizeof(CallBackData), KSF_ALTERNATIVE | KSF_CONTINUOUS);// Flags - KSF_ALTERNATIVE | KSF_CONTINUOUS
if(ksError != KS_OK) {
outputErr(ksError, "KS_createSharedMemEx", "Failed to allocate shared memory");
KS_closeDriver();
return ;
}
CallBackData *pShmExPtr;
ksError = KS_getSharedMemEx(hShmEx, (void **)&pShmExPtr, 0);
if(ksError != KS_OK) {
outputErr(ksError, "KS_getSharedMemEx", "Failed to get shared memory");
KS_closeDriver();
return ;
}
*/
pAppPtr->counter_ = 0;
//------------------------------------------------------
// Now we create the callbacks. The callback contains the KSF_DIRECT_EXEC: - execution on kernel level
//------------------------------------------------------
KSHandle hCallbackA;
ksError = KS_createCallBack(
&hCallbackA, // Address of callback handle
_callBackA, // Callback function
pSysPtr, // Reference parameter to the callback - pSysPtr
KSF_DIRECT_EXEC, // Flags
0); // Priority (only on user level)
if (ksError != KS_OK) {
outputErr(ksError, "KS_createCallBack", "Failed to create callback");
KS_closeDriver();
return;
}
ksError = KS_createTask(
&pAppPtr->hTaskA_, // Address of task handle
hCallbackA, // Callback handle
250, // Priority
KSF_DONT_START); // Dont start the task, a time will do that
if (ksError != KS_OK) {
outputErr(ksError, "KS_createTask", "Failed to create task");
KS_closeDriver();
return;
}
//------------------------------------------------------
// Create a timers with different periods. The signalisation objects are tasks in this case.
//
// Due to the creation of the timer A directly with a callback handle, the priority has the value 127.
// Timer B has the priority value 130, which is given when creating the task.
//
// Accepted flags are:
// KSF_REALTIME_EXEC: - the real-time kernel is to be used
// KSF_DONT_START: - don't start the timer (can be started later)
// KSF_ONE_SHOT: - signal timer only one time
//------------------------------------------------------
KSHandle hTimerA;
ksError = KS_createTimer(
&hTimerA, // Address of timer handle
1000 * us, // Timer period in 100-ns-units
pAppPtr->hTaskA_, // Task handle
KSF_REALTIME_EXEC); // Flags, here real-time execution
if (ksError != KS_OK) {
outputErr(ksError, "KS_createTimer", "Unable to create the timer!");
KS_closeDriver();
return;
}
// Do something
while(!stopFlag)
{
if (myKbhit()) {
int key = myGetch();
if (key == 'q' || key == 'Q')
break;
}
}
outputDec(pAppPtr->counter, "counter: ");
//outputDec(pShmExPtr ->counter, "counter: ");
waitTime(25 * ms);
//------------------------------------------------------
// Stop the timer
//------------------------------------------------------
ksError = KS_stopTimer(
hTimerA); // Timer handle
if (ksError != KS_OK)
outputErr(ksError, "KS_stopTimer", "Unable to stop the timer!");
//------------------------------------------------------
// Remove the timer
//------------------------------------------------------
ksError = KS_removeTimer(
hTimerA); // Timer handle
if (ksError != KS_OK)
outputErr(ksError, "KS_removeTimer", "Unable to remove timer");
//------------------------------------------------------
// Remove the callbacks
//------------------------------------------------------
ksError = KS_removeCallBack(
hCallbackA); // Callback handle
if (ksError != KS_OK)
outputErr(ksError, "KS_removeCallBack", "Unable to remove the callback!");
//------------------------------------------------------
// Remove the shared memory
//------------------------------------------------------
ksError = KS_freeSharedMem(
pAppPtr); // Application pointer
if (ksError != KS_OK)
outputErr(ksError, "KS_freeSharedMem", "Unable to remove shared memory!");
/*
ksError = KS_freeSharedMemEx(hShmEx, 0);
if (ksError != KS_OK) {
outputErr(ksError, "KS_freeSharedMemEx", "Unable to remove shared memory!");
}
*/
//------------------------------------------------------
// At last we have to close the driver to free any allocated resources.
//------------------------------------------------------
ksError = KS_closeDriver();
if (ksError != KS_OK)
outputErr(ksError, "KS_closeDriver", "Unable to close the driver!");
}
以下是Qt应用程序相关代码:
sharedMemoryTest.pro文件
需要添加两个库:KrtsDemo_x64.lib 和 KrtsDemo_vci.lib
#-------------------------------------------------
#
# Project created by QtCreator 2016-03-09T13:46:03
#
#-------------------------------------------------
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = sharedMemoryTest
TEMPLATE = app
LIBS += -L E:/workspace/Kithara/dev -lKrtsDemo_x64 -lKrtsDemo_vci
SOURCES += main.cpp\
mainwidget.cpp \
KitharaShm.c
HEADERS += mainwidget.h \
KitharaShm.h
main.cpp文件
#include "mainwidget.h"
#include <QApplication>
#define SHAREDMEMORY_GLOBALS
#include "KitharaShm.h"
// The name of kithara shared memory is: GSK_TaskTimerCycle2QtSHM
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
G_SharedMemoryInit();
MainWidget w;
w.show();
return a.exec();
}
mainwidget.h文件
#ifndef MAINWIDGET_H
#define MAINWIDGET_H
#include <QWidget>
#include <QLabel>
#include <QLineEdit>
#include <QTimer>
class MainWidget : public QWidget
{
Q_OBJECT
public:
MainWidget(QWidget *parent = 0);
~MainWidget();
private slots:
void appTimerOut();
private:
void createUI(void);
void layoutUI(void);
QLineEdit *lineEdit1;
QTimer *appTimer;
};
#endif // MAINWIDGET_H
mainwidget.cpp文件
#include "mainwidget.h"
#include <QFormLayout>
#include "KitharaShm.h"
#include <QDebug>
MainWidget::MainWidget(QWidget *parent)
: QWidget(parent)
{
setFixedSize(300, 200);
setWindowTitle(tr("SharedMemory2Kithara Test"));
createUI();
layoutUI();
appTimer = new QTimer(this);
connect(appTimer, SIGNAL(timeout()), this, SLOT(appTimerOut()));
appTimer->start(100);
}
MainWidget::~MainWidget()
{
G_SharedMemoryCleanup();
}
void MainWidget::createUI()
{
lineEdit1 = new QLineEdit;
lineEdit1->setReadOnly(true);
}
void MainWidget::layoutUI()
{
QFormLayout *mainLayout = new QFormLayout;
mainLayout->setContentsMargins(15, 30, 15, 30);
mainLayout->setSpacing(15);
mainLayout->addRow(tr("counter:"), lineEdit1);
this->setLayout(mainLayout);
}
void MainWidget::appTimerOut()
{
if(pShmExPtr == NULL)
{
qDebug("pShmExPtr is NULL.");
return ;
}
lineEdit1->setText(QString::number(pShmExPtr->counter));
}
KitharaShm.h文件
#ifndef KITHARASHM_H
#define KITHARASHM_H
#define KS_OK 0x00000000
#define KSF_ALTERNATIVE 0x00200000
#define KSF_CONTINUOUS 0x00010000
//------ Synonyms ------
typedef int Error;
typedef void * KSHandle;
#if defined(__cplusplus)
extern "C"
{
#endif
//------ Common functions ------
Error __stdcall KS_openDriver(
const char* customerNumber);
Error __stdcall KS_closeDriver(
void);
//------ Shared memory ------
Error __stdcall KS_createSharedMem(
void** ppAppPtr, void** ppSysPtr, const char* name, int size, int flags);
Error __stdcall KS_freeSharedMem(
void* pAppPtr);
Error __stdcall KS_getSharedMem(
void** ppPtr, const char* name);
Error __stdcall KS_readMem(
void* pBuffer, void* pAppPtr, int size, int offset);
Error __stdcall KS_writeMem(
const void* pBuffer, void* pAppPtr, int size, int offset);
Error __stdcall KS_createSharedMemEx(
KSHandle* phHandle, const char* name, int size, int flags);
Error __stdcall KS_freeSharedMemEx(
KSHandle hHandle, int flags);
Error __stdcall KS_getSharedMemEx(
KSHandle hHandle, void** pPtr, int flags);
/*
* 共享内存
*/
#ifdef SHAREDMEMORY_GLOBALS
#define SHAREDMEMORY_EXT
#else
#define SHAREDMEMORY_EXT extern
#endif
//------ CallBackData ------
typedef struct CallBackData {
int counter;
}CallBackData;
SHAREDMEMORY_EXT KSHandle hShmEx;
SHAREDMEMORY_EXT CallBackData *pShmExPtr;
int G_SharedMemoryInit();
void G_SharedMemoryCleanup();
#if defined(__cplusplus)
}
#endif
#endif // KITHARASHM_H
KitharaShm.c 文件
注意:Qt 应用程序也必须先调用 KS_openDriver() 才能使用共享内存。
#define SHAREDMEMORY_GLOBALS
#include "KitharaShm.h"
int G_SharedMemoryInit()
{
Error ksError = -1;
const char* pCustomerNumber = "DEMO";
ksError = KS_openDriver(pCustomerNumber); // Customer number
if (ksError) {
//
return;
}
ksError = KS_createSharedMemEx(&hShmEx, "periodicTimerTaskShm2Qt", sizeof(CallBackData), KSF_ALTERNATIVE | KSF_CONTINUOUS);
if(ksError != KS_OK) {
//
KS_closeDriver();
return ;
}
ksError = KS_getSharedMemEx(hShmEx, (void **)&pShmExPtr, 0);
if(ksError != KS_OK) {
//outputErr(ksError, "KS_getSharedMemEx", "Failed to get shared memory");
//KS_closeDriver();
//return ;
}
if(pShmExPtr == NULL)
{
G_SharedMemoryCleanup();
//
return 1;
}
return 0;
}
void G_SharedMemoryCleanup()
{
Error ksError = -1;
ksError = KS_freeSharedMemEx(hShmEx, 0);
if (ksError != KS_OK) {
//
}
ksError = KS_closeDriver();
if (ksError != KS_OK) {
//
}
}
#endif
————————————————