Rexroth(力士乐)PLC与Labwindows CVI OPC通讯的实现

本文详细介绍了Rexroth PLC与CVI通过OPC进行通讯的全过程,包括OPC Server的安装与配置、OPC Configurator的使用、OPC Test Client的测试方法以及PLC端的配置与编程技巧。特别关注了变量表的配置和Labwindows CVI 2013下的编程实现。

OPC Server 安装

力士乐开发软件中已经集成了OPC Server的相关组件,只需要安装Indraworks里的communication 组件即可,当前我使用的版本是Indraworks 12v08,这里就不详细介绍安装方法了。
只是要注意一点:最好将电脑非Unicode设置成非中文,再安装,我碰到许多次出现Indraworks安装失败,或者在配置后测试 noconfig的状态。

OPC Server配置

OPC Configurator 配置

  1. 打开Rexroth>IndraLogic>OPC Configurator
    在这里插入图片描述
  2. 添加PLC, 如果是一个客户端选择 Single PLC,如果位多个可以右击append PLC在这里插入图片描述.在这里插入图片描述
  3. Edit创建通讯参数,如果已有Gateway可以直接点添加New…,如有没有先添加Gateway 选择TCP/IP
  4. 在这里插入图片描述在这里插入图片描述
  5. 添加PLC配置时,请选择TCP/IP(Level 2 Route)在这里插入图片描述

OPC Test Client 测试

如果想要确认新建的OPC Server运行状态如何,可以使用 OPC Test Client 程序。
Rexroth>Communication>OPC Test Client
在这里插入图片描述
选择IndraLogic.OPC在这里插入图片描述状态信息栏里显示运行状态
在这里插入图片描述
如果出现状态noconfig的状态,你的PLC是连接到你的服务器的,只是读不到你的配置文件,或者读不到 你的变量表。
遇到这个问题
1.首先确认你的电脑是否设置成了Unicode简体中文,可先将他设置成英文。
2.变量表是你的PLC编译后生成的.SDB文件。可以将他手动配置到你的Gateway Files里。

连接好PLC后可以通过添加Item 来确认变量是否可以遍历到
在这里插入图片描述

PLC端配置

新建变量
在这里插入图片描述Project>Option>Symbol Configuration>Configure symbol file 选中所有变量
在这里插入图片描述

CVI OPC通讯编程

当前使用的是Labwindows CVI 2013版本
从文件读取配置信号ini配置文件如下
[PLC_TO_IPC]
Num=16
;
[IPC_TO_PLC]
Num=25
;
[PO_0]
EN=“HeartBeat”
CN=“心跳信号”
GM=“HeartBeat”
URL=“opc://localhost/IndraLogic.OPC.02/PLC1:.stPLC.bPuls”
TYPE=111
SIZE=2
;
[PO_1]
EN=“DMC”
CN=“ID码”
GM=“DMC”
URL=“opc://localhost/IndraLogic.OPC.02/PLC1:.stPLC.chDMC”
TYPE=115
SIZE=50
;
[PO_2]
EN=“Mode”
CN=“模式”
GM=“Mode”
URL=“opc://localhost/IndraLogic.OPC.02/PLC1:.stPLC.iMode”
TYPE=102
SIZE=4
;

封装部分直接上源代码
当前只读取PLC 的四种类型。CodeSys下的 REAL,BOOL,INT,STRING

// Include files

#include "dataskt.h"
#include <ansi_c.h>
#include "inifile.h"
#include "PLCCom.h"

//==============================================================================
// Constants

#define GETURL(section,chvalue)   if(0>=Ini_GetPointerToRawString (handle,section,"URL",&chvalue)) return -1001;else      //get the url if wrong return -1;
#define GETTYPE(section,value)   if(0>=Ini_GetInt(handle,section,"TYPE",&value)) return -1002;else 				//get the valible type if wrong return -1;
#define GETSIZE(section,value)   if(0>=Ini_GetInt(handle,section,"SIZE",&value)) return -1005;else 				//get the valible type if wrong return -1; 
#define GETHANDLE(url,section,i)  if(0>DS_OpenEx(url,DSConst_ReadWriteAutoUpdate,NULL,NULL,DSConst_EventModel,1,&section)) return -1003000-i;else  //get the handle of the valible

#define CHECK_HANDLE(handle,i)	if(handle== 0)  return -1000000-10000*i;else
#define OPC_GETTYPE(handle,type,i)  if(0>DS_GetDataType(handle,&type,&uiSize,NULL)) return -2000000-10000*i;else
#define CHECK_TYPE(type,type2,i)   if(type2!=type) return -3000000-10000*i-type2;else 
#define ErrCheck(function,i)    if(function<0) return -4000000-10000*i;else
//==============================================================================
// Types

//==============================================================================
// Static global variables
static struct  SignalInfo stPLC[56];
static struct  SignalInfo stIPC[56]; 
int PLCNO=0;
int IPCNO=0;

//==============================================================================
// Static functions
enum Type
{
	T_BOOL=111,
	T_INT=102,
	T_REAL=104,
	T_STRING=115,

};

unsigned char *pPlcData;
unsigned char *pIpcData;


//==============================================================================
// Global variables

//==============================================================================
// Global functions
/*****************  initial  the url********************/
//RootPath  the root path of the program
//pPlcInfo plc 信息的结构体指针
//pIpcInfo ipc信息结构体指针
//success 返回0   失败返回负数
//               -1 FAIL TO GET URL
//               -2 FAIL TO GET THE HANDLE
//               -3 FAIL TO GET THE TYPE
//               -4 FAIL TO fIND THE FILE 
extern "C" __declspec(dllexport)int PLC_COM_Initial(char *RootPath,unsigned char *pPlcInfo , unsigned char *pIpcInfo)
{
	char path[225]="";
	char *chval;
	char temp[20]="";
	char *opcURLs;
	pPlcData=pPlcInfo;
	pIpcData=pIpcInfo;
	strcpy(path,RootPath);
	strcat(path,"\\Configuration\\PLCInterface.ini"); //文件路径获取
	IniText handle=Ini_New (0);
	if(0!=Ini_ReadFromFile(handle,path)) {Ini_Dispose(handle);return -1004;}
	
	if(0>=Ini_GetInt (handle,"PLC_TO_IPC","Num",&PLCNO)) return -1005;
	
	if(0>=Ini_GetInt (handle,"IPC_TO_PLC","Num",&IPCNO)) return -1006;
	
		
	unsigned int  uiType=0, uiSize=0; 
	//read the url for the config file
	for(int i=0; i<PLCNO; i++)
	{
		sprintf(temp,"PO_%d",i);
		GETURL(temp,chval);
		opcURLs=StrDup(chval);
		GETHANDLE(opcURLs,stPLC[i].iHandle,i);
		free(opcURLs); 
		GETTYPE(temp,stPLC[i].iType); 
		GETSIZE(temp,stPLC[i].iSize);
		OPC_GETTYPE(stPLC[i].iHandle,uiType,i);
		CHECK_TYPE(stPLC[i].iType,uiType,i) ;
	}
	
	for(int i=0; i<IPCNO; i++)
	{
		sprintf(temp,"IO_%d",i);
		GETURL(temp,chval);
		opcURLs=StrDup(chval);
		GETHANDLE(opcURLs,stIPC[i].iHandle,i);
		free(opcURLs); 
		GETTYPE(temp,stIPC[i].iType);
		GETSIZE(temp,stIPC[i].iSize);
		OPC_GETTYPE(stIPC[i].iHandle,uiType,i);
		CHECK_TYPE(stIPC[i].iType,uiType,i) ;
	}
	
	Ini_Dispose(handle);
	return 0;
}
/*****************  read the signal from plc********************/
//success 返回0   失败返回负数 
//               -1 FAIL CHECK THE HANDLE
//               -2 FAIL TO GET THE TYPE  
//               -3 FAIL TO CHECK THE TYPE
//               -4 FAIL TO GET THE VALUE
extern "C" __declspec(dllexport)int PLC_COM_Read()
{
	int index=0;
	unsigned int uiType=0;
	unsigned int uiSize=0;
		
	//plc to ipc signal receive
	for(int i=0; i<PLCNO; i++)
	{
		int *piVal=(int *)(pPlcData+index);
		short *psVal=(short *)(pPlcData+index);
		char *pcVal=(char *)(pPlcData+index);
		float *pfVal =(float *)(pPlcData+index);
		
		int iVal=0;
		short sVal=0;
		float fVal=0;
		CHECK_HANDLE(stPLC[i].iHandle,i);
		OPC_GETTYPE(stPLC[i].iHandle,uiType,i);
		switch(stPLC[i].iType)
		{
			case T_BOOL:
				ErrCheck(DS_GetDataValue(stPLC[i].iHandle,CAVT_SHORT, &sVal, uiSize+1, NULL,NULL),i);
				sVal=abs(sVal);
				*psVal=sVal;
				break;
			case T_INT:
				ErrCheck(DS_GetDataValue(stPLC[i].iHandle,CAVT_INT, &iVal, uiSize+1, NULL,NULL),i);
				*piVal=iVal;
				break;
			case T_STRING:
				ErrCheck(DS_GetDataValue(stPLC[i].iHandle,CAVT_CSTRING,pcVal, uiSize+1, NULL,NULL),i);
				break;
			case T_REAL:
				ErrCheck(DS_GetDataValue(stPLC[i].iHandle,CAVT_FLOAT, &fVal, uiSize+1, NULL,NULL),i);
				*pfVal=fVal;
				break; 
			default:
				return -600000-i*1000-stPLC[i].iType;
		}
		index+=stPLC[i].iSize; 
	}
	return 0;
}
/*****************  write the signal to plc ********************/
//success 返回0   失败返回负数 
//               -1 FAIL CHECK THE HANDLE
//               -2 FAIL TO GET THE TYPE  
//               -3 FAIL TO CHECK THE TYPE
//               -4 FAIL TO set THE VALUE
extern "C" __declspec(dllexport)int PLC_COM_Set()
{
	int index=0; 
	//ipc to plc signal receive
	for(int i=0; i<IPCNO; i++)
	{
		int *piVal=(int *)(pIpcData+index);
		short *psVal=(short *)(pIpcData+index);
		char *pcVal=(char *)(pIpcData+index);
		float *pfVal =(float *)(pIpcData+index);
		
		int iVal=0;
		short sVal=0;
		float fVal=0;
		CHECK_HANDLE(stIPC[i].iHandle,i);
		switch(stIPC[i].iType)
		{

			case T_BOOL:
				sVal=*psVal;
				ErrCheck(DS_SetDataValue (stIPC[i].iHandle,CAVT_SHORT, &sVal,0,0),i);
				break;
			case T_INT:
				iVal=*piVal;
				ErrCheck(DS_SetDataValue(stIPC[i].iHandle,CAVT_INT, &iVal, 0,0),i);
				break;
			case T_STRING:
				ErrCheck(DS_SetDataValue (stIPC[i].iHandle,CAVT_CSTRING, pcVal,0,0),i);
				break;
			case T_REAL:
				fVal=*pfVal;
				ErrCheck(DS_SetDataValue(stIPC[i].iHandle,CAVT_FLOAT, &fVal, 0,0),i);
				break;
			default:
				return -700000-i*1000-stIPC[i].iType;
		}
		index+=stIPC[i].iSize; 
	}
	return 0;
}

调用以上函数的方法

//此部分位初始化调用
int PLCInterface_Initial()
{
	int iRetVal=0;
	
	if(Initialed==0)
		iRetVal=PLC_COM_Initial(gPara.SWPath,(unsigned char*)&stPLC,(unsigned char*)&stIPC);
	if(iRetVal==0)
	{
		Initialed=1;
		stIPC.bIsReady=TRUE;
	}else
	{
		char temp[20]="";
		sprintf(temp,"Code:%d",iRetVal);
		MessageAlarm("1081",temp,gPara.ActLanguage); 
	}
	return iRetVal;
}
//此部分贴入定时器循环扫描
int PLC_IPC_Ctrol()
{
	static int bPulseEx=0;
	static double dTimerA=0,dTimerB=0;//timer count
	static char Trigger=0;
	static int ModeEx=-1;
	

	if(!Initialed) return 0; // 
	//READ AND WRITE
	int ret=PLC_COM_Read();
	if(0!=ret)
	{
		char temp[20]="";
		sprintf(temp,"RCode:%d",ret);
		MessageAlarm("1070",temp,gPara.ActLanguage);
		return 0;
	}
	ret=PLC_COM_Set();
	if(0!=ret)
	{
		char temp[20]="";
		sprintf(temp,"WCode:%d",ret);
		MessageAlarm("1070",temp,gPara.ActLanguage);
		return 0;
	}
}

至此,整个OPC通讯的实现就已完成。
划重点
DS_GetDataValue(stPLC[i].iHandle,CAVT_SHORT, &sVal, uiSize+1, NULL,NULL),i);
CAVT_SHORT 是指 在上位机程序变量的定义类型 而非PLC端变量的定义类型。
运行效果
在这里插入图片描述

为了查找与测绘遥感相关的SCI期刊列表,可以通过学术搜索引擎或访问特定的数据库来获得最新的信息。通常这些资源会定期更新以反映最新收录情况。 些常用的搜索方式包括: 查阅Web of Science (WOS) 数据库 这是最直接的方法之,因为Science Citation Index(SCI)正是由该数据库维护。可以在其中设置关键词为"remote sensing", "surveying and mapping" 或者更具体的主题术语,并选择仅显示被SCI索引的文章和期刊。 利用Google Scholar 虽然不是专门针对SCI期刊,但可以找到很多高影响力的测绘遥感类文章及其发表刊物的信息。从这里也可以了解到哪些是活跃且受认可的研究领域内的出版物。 参考Journal Citation Reports (JCR) 这是个评估科学和技术期刊影响力的重要工具。通过查看影响因子和其他指标,可以帮助确定哪些测绘遥感领域的期刊最具权威性并且属于SCI范畴。 咨询图书馆员或专业人士 大学或研究机构的专业人员能够提供指导和支持,帮助定位最适合需求的具体期刊名称及详情。 订阅行业通讯和服务 某些服务如Elsevier's Scopus也会报告关于各个学科顶级期刊的消息,保持关注可以获得及时的通知。 以下是几个知名的测绘遥感相关SCI期刊的例子: - Remote Sensing of Environment - IEEE Transactions on Geoscience and Remote Sensing - ISPRS Journal of Photogrammetry and Remote Sensing - International Journal of Applied Earth Observation and Geoinformation 请注意,实际的SCI期刊名单可能会随着时间而变化,因此建议总是使用最新的在线资源来进行确认。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Joey joy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值