FANUC CNCとイーサネット通信してカスタムマクロ変数値を読み出すPythonプログラムの作成

,

概要

FANUC CNCのイーサネットは、FOCAS2と言うプロトコルで通信します。ここでは、Pythonを使用してFANUC CNCとパソコンをイーサネットで接続してカスタムマクロ変数値を読み出すプログラムの製作方法に関して記します。
尚、本記事とサンプルプログラムは、FANUCの取説等を参考にして筆者が独自に作成した物でFANUCが公式に発表している物ではありません。記載誤りやサンプルプログラムのバグ等に関してはご容赦お願いいたします。

カスタムマクロ変数に関して

FANUC CNCはG言語でカスタムマクロ機能があります。カスタムマクロで使用する変数をカスタムマクロ変数と呼びます。カスタムマクロ変数は#の後に数字を書いたもので表1のような種類があります。

変数役割解説
#1~#33ローカル変数カスタムマクロ内でローカルに使用される変数
#100~#199
#500~#999
#98000~#98499
コモン変数メインプログラム、サブプログラム等共通で使用される変数
表1.カスタムマクロ変数

カスタムマクロ変数を使用したプログラム例を示します。
#1=10.0
#2=100.0
G01 X#1 Y#2 F200.0

FOCAS2ライブラリに関して

FANUC CNCとイーサネット接続するソフトウェアを製作するには、FANUCから供給されるFOCAS2 LibraryのAPIを使用します。このAPIはC言語の関数です。FOCAS2 LibraryにはDLLやサンプルコードやドキュメント等の関連ファイルが入っています。

カスタムマクロ変数値を読み出すために使用するAPI

FANUC CNCからイーサネット接続でカスタムマクロ変数値を読み出すために使用するAPIは以下の通りです。(FOCAS2 Libraryの取説より)

関数名用途説明
cnc_allclibhndl3()ライブラリハンドルの取得(Ethernet用)ライブラリハンドルを取得し、指定されたIPアドレスに接続します
cnc_freelibhndl()ライブラリハンドルの解放ライブラリで使用するライブラリハンドルを解放します
cnc_rdmacro()カスタムマクロ変数のリード指定された番号のカスタムマクロ変数を読み出します。
表2.カスタムマクロ変数値を読み出すのに必要なAPI

cnc_allclibhndl3()

【関数宣言】
#include "fwlib32.h" or "fwlib64.h"
FWLIBAPI short WINAPI cnc_allclibhndl3(const char *ipaddr, unsigned short port, long timeout, unsigned short *FlibHndl);

【引数】
ipaddr
 接続するCNCのIPアドレス、またはホスト名を示す文字列を指定します。(例"192.168.0.1")
port
 FOCAS2/Ethernet(TCP)機能のポート番号を指定します。
timeout
 タイムアウトの秒数を指定します。0を指定すると、タイムアウト処理が無効化されて、無限に待つようになります。
FlibHndl
 ライブラリハンドルを格納する変数へのポインタです。

【戻り値】
EW_SOCKET (-16)
 ソケット通信エラー。
 CNCの電源、イーサネットボード、イーサネットケーブルを確認して下さい。
EW_NODLL (-15)
 機能別DLLが存在しません。
EW_HANDLE (-8)
 ハンドル取得に失敗しました。

cnc_freelibhndl()

【関数宣言】
#include "fwlib32.h" or "fwlib64.h"
FWLIBAPI short WINAPI cnc_freelibhndl(unsigned short FlibHndl);

【引数】
FlibHndl
 解放するライブラリハンドルを指定します。

【戻り値】
 成功するとEW_OK (0)を返し、エラーの場合はEW_OK以外の値を返します。

cnc_rdmacro()

#include "fwlib32.h" or "fwlib64.h"
FWLIBAPI short WINAPI cnc_rdmacro(unsigned short FlibHndl, short number, short length, ODBM *macro);
【引数】
FlibHndl
 ライブラリハンドルです。
number
 リードするカスタムマクロ変数の番号を指定します。
length
 データブロック長を指定します。必ず10 (ODBM構造体のサイズ)を指定します。
macro
 カスタムマクロ変数を返すODBM構造体へのポインタです。ODBM構造体は次の通りです。
    typedef struct odbm {
        short datano;    //カスタムマクロ変数番号
        short dummy;     //未使用
        long mcr_val;    //カスタムマクロ変数値
        short dec_val;   //少数点以下桁数
    }ODBM;

【戻り値】
EW_LENGTH (2)
 データブロック長の誤り
EW_NUMBER (3)
 データ番号の誤り
EW_NOOPT (6)
 オプションなし。CNCにカスタムマクロ機能が必要です。
 

PythonからFOCAS2のAPIを使用するために作成したDLL

PythonからFOCAS2 LibraryのAPIを呼び出すのに引数等のやり取りが煩雑なので、全て整数形(int)の引数で呼び出し、戻り値も整数(int)の変換関数のDLLを作成しました。開発ツールソフトとしてはVisual Studio 2022を使用しC++言語で作成しました。
また、PythonはAnaconda3(64bit)を使用しました。この場合FANUC CNCと接続するDLLを作成するためには、FANUCのFOCAS2 Libraryに含まれるFwlib64.libとFwlib64.hファイルを使用します。32bitの場合はFwlib32.libとFwlib32.hを使用します。
以下にDLLを作成する手順を示します。

1.Visual Studio 2022を起動します。

2.「新しいプロジェクト作成(N)」をクリックします。

3.「ダイナミックリンクライブラリ(DLL)」を選択して「次へ(N)」をクリックします。

4.「プロジェクト名(J)」を入力して、「作成(C)」をクリックします。ここではプロジェクト名を「FanucComDll64」としました。

5.以下画面が表示されたら、ソリューションエクスプローラーの「ソースファイル」を右クリックします。

6.「追加(D)」→「モジュール(M)」をクリックします。

7.「C++ファイル(.cpp)」を選択して、「名前(N):」を入力して「追加(A)」をクリックします。ここでは名前(N)は「dllProgram.cpp」としました。

8.dllProgram.cppが作成されますので、DLLのソースコードを入力します。ソースコードに関しては後項で説明します。

9.DLLのソースコードをコンパイルするためには、FOCAS2 LibraryのFwlib64.hとFwlib64.libが必要なのでこれらのファイルをdllProgram.cppが有るのと同じフォルダ(……\FanucComDll64\FanucComDll64)にコピーします。

10.ソリューションエクスプローラーの「ヘッダーファイル」を右クリックして「追加(D)」→「既存の項目(G)」をクリックします。

11.先ほどコピーしたFwlib64.hを選択して「追加(A)」をクリックします。

12.以下のようにソリューションエクスプローラーの「ヘッダファイル」にFwlib64.hが追加されたのを確認します。

13.ソリューションエクスプローラーの「リソースファイル」を右クリックした後、「追加(D)」をクリックします。

14.「追加(D)」→「既存の項目(G)」をクリックします。

15.先ほどコピーしたFwlib64.libを選択して「追加(A)」をクリックします。

16.以下のようにソリューションエクスプローラーの「リソースファイル」にFwlib64.libが追加されたのを確認します。

17.「ビルド(B)」→「ソリューションのビルド(B)」をクリックしてDLLのビルドを行います。

18.ビルドを実行すると新たにx64フォルダが作成されます。

19.デバッグ時は、….FanucComDll64\x64\Debugフォルダの中のFanucComDll64.dllが作成されたDLLファイルです。このDLLファイルはPythonのソースコードファイルと同じフォルダに置く必要があります。

作成したDLLに関して

PythonからFOCAS2 LibraryのAPIを呼び出すのに引数等のやり取りが煩雑なので、全て整数形(int)の引数で呼び出し、戻り値も整数(int)の変換関数のDLLを作成しました。これらの関数はPythonから受け取った整数型の引数を、FOCAS2 LibraryのそれぞれのAPIの引数の形に変換して呼び出しています。作成したDLL関数の説明を表3に示します。

関数名解説
イーサネット接続
fcnc_allclibhndl3(ip1, ip2, ip3, ip4, portP, timeoutP)
引数(全てint)
ip1~ip4: インタネットアドレス値
インタネットアドレス 192.168.0.1の場合は
ip1=192, ip2=168, ip3=0, ip4=1を設定
portP: ポート番号
timeoutP: タイムアウト時間(秒単位)

戻り値(int)
>=0: ライブラリハンドル値 (イーサネット接続時の識別値)
<0: 異常コード
イーサネット切断
fcnc_freelibhndl(FlibHndlPara)
引数(int)
FlibHndlPara: ライブラリハンドル値 (fcnc_allclibhndl3関数の戻り値)

戻り値(int)
結果: 0:正常、 0以外:異常
カスタムマクロ変数値読込
fcnc_rdmacro_trg(FlibHndlPara, number)
引数(全てint)
FlibHndlPara: ライブラリハンドル値(fcnc_allclibhndl3関数の戻り値)
number: カスタムマクロ変数番号

戻り値(int)
結果: 0:正常、0以外:異常コード
fcnc_rdmacro_mcr_val()戻り値(int) カスタムマクロ変数値
fcnc_rdmacro_trg()関数を実行した後にfcnc_rdmacro_mcr_val()関数を実行すると戻り値としてカスタムマクロ変数の変数値(整数値)が得られます。
fcnc_rdmacro_dec_val戻り値(int) カスタムマクロ変数の少数点以下の桁数
fcnc_rdmacro_trg()関数を実行した後にfcnc_rdmacro_dec_val()関数を実行すると戻り値としてカスタムマクロ変数の少数点以下の桁数が得られます。
表3.作成したDLLの関数

作成したDLLのソースコード

以下にPythonからFOCAS2 Libraryを呼び出すために作成したDLLのソースコードを示します。
プログラムはC++言語で書かれていますが、全ての関数をextern “C”で囲むことによってC言語として扱われています。(C++言語だとコンパイル後に関数の名前が異なってしまうことがあるため)
各関数の頭に付けた__declspec(dllexport)は、関数が外部から参照出来るように付けるキーワードです。
簡単にするためPythonからの引数は全て整数型(int)でもらい、それをFOCAS2 LibraryのAPIの引数に合うように変換しています。関数の戻り値も全て整数型(int)としています。

// Python 用FANUCイーサネット接続用DLL
//--------------------------------------------------------------------
// FANUC FOCAS2ライブラリの中で必要なファイル
//		32bit Python用
//			Fwlib32.lib
//			Fwlib32.h
//		64bit Python用
//			Fwlib64.lib
//			Fwlib64.h
//--------------------------------------------------------------------
#include "pch.h"
#include "stdio.h"
#include "Fwlib64.h"

//共通データ
int mcr_val_mem = 0;    //マクロ変数読み込み時の値の記憶メモリ
int dec_val_mem = 0;	//マクロ変数読み込み時の少数点位置記憶メモリ

extern "C" {

	//------------------------------------------------------------
	// FANUCとのインターネット接続実施関数
	//	引数
	//		int ip1:	IPアドレスの1番目の数値
	//		int ip2:        IPアドレスの2番目の数値
	//		int ip3:	IPアドレスの3番目の数値
	//		int ip4:	IPアドレスの4番目の数値
	//		int portP:	ポート番号
	//		int timeoutP:	タイムアウト時間(msec)
	//
	//	リターン値   >=0: ライブラリハンドル値
	//                    <0: エラー発生
	//		     -16:ソケット通信エラー
	//		     -15:機種別DLLが存在しません
	//		      -8:ハンドルの取得に失敗しました
	//-------------------------------------------------------------
	__declspec(dllexport) int fcnc_allclibhndl3(int ip1, int ip2, int ip3, int ip4, int portP, int timeoutP)
	{
		short result = 100;
		int errorNo = 0;
		unsigned short FlibHndl = 0;	//FANUC接続ハンドル
		int FlibHndlResult = 0;		//return用接続ハンドル値
		unsigned short port;
		long timeout;

		port = (unsigned short)portP;
		timeout = (long)timeoutP;

		char c_ip1[100];	//ipアドレスの1番目の数字文字列配列
		char c_ip2[30];		//ipアドレスの2番目の数字文字列配列
		char c_ip3[30];		//ipアドレスの3番目の数字文字列配列
		char c_ip4[30];		//ipアドレスの4番目の数字文字列配列
		char c_dot[] = ".";	//"."文字列

		//int を文字列に変換する
		sprintf_s(c_ip1, 100, "%d", ip1);
		sprintf_s(c_ip2, 30, "%d", ip2);
		sprintf_s(c_ip3, 30, "%d", ip3);
		sprintf_s(c_ip4, 30, "%d", ip4);

		//文字列を連結してIPアドレス文字列にする
		strcat_s(c_ip1, 100, c_dot);
		strcat_s(c_ip1, 100, c_ip2);
		strcat_s(c_ip1, 100, c_dot);
		strcat_s(c_ip1, 100, c_ip3);
		strcat_s(c_ip1, 100, c_dot);
		strcat_s(c_ip1, 100, c_ip4);

		printf(c_ip1);

		result = cnc_allclibhndl3(c_ip1, port, timeout, &FlibHndl); //FANUC API関数実行
		
		if (result == 0)	//エラー無?
		{
			//エラー無の時はハンドル値を返す
			FlibHndlResult = (int)FlibHndl;
			FlibHndlResult = FlibHndlResult & 0x0000ffff;
			return FlibHndlResult;
		}
		else
		{
			//エラー発生時はエラー値(<0)を返す
			return (int)result;
		}
	}

	//--------------------------------------------------------------------
	// FANUCとのインサーネット切断関数
	//	引数
	//		int FlibHndlPara:	ライブラリハンドル値
	//
	//	リターン値   0: OK !=0:エラーコード
	//---------------------------------------------------------------------
	__declspec(dllexport) int fcnc_freelibhndl(int FlibHndlPara)
	{
		short result = 100;
		unsigned short FlibHndl = 0;	//FANUC接続ハンドル

		FlibHndl = (unsigned short)FlibHndlPara;

		result = cnc_freelibhndl(FlibHndl); //FANUC API関数実行
				
		return (int)result;
	}

	//-------------------------------------------------------------------
	//		FANUCのマクロデータ読込トリガ実施
	//	引数
	//		int FlibHndlPara:	ライブラリハンドル値
    // (fcnc_allclibhndl3()で取得)
	//		int number:		読み出すマクロ変数番号
	//
	//	リターン値	0: Ok,
	//				2:ブロックデータ長誤り,
	//				3:データ番号誤り
	//				6:オプション無
	//---------------------------------------------------------------------
	__declspec(dllexport) int fcnc_rdmacro_trg(int FlibHndlPara, int number)
	{
		short result = 100;
		unsigned short FlibHndl = 0;	//FANUC接続ハンドル
		ODBM macro;
		short s_number;

		FlibHndl = (unsigned short)FlibHndlPara;
		s_number = (short)number;

		result = cnc_rdmacro(FlibHndl, s_number, 10, &macro);	//FANUC API関数実行

		mcr_val_mem = (int)macro.mcr_val;	//カスタムマクロ変数値
		dec_val_mem = (int)macro.dec_val;	//少数点以下桁数

		return (int)result;
	}

	//----------------------------------------------------------
	//fcnc_rdmacro_trg()実施後のカスタムマクロ変数値を読み出す関数
	//	リターン値  カスタムマクロ変数値
	//----------------------------------------------------------
	__declspec(dllexport) int fcnc_rdmacro_mcr_val()
	{
		return(mcr_val_mem);
	}


	//----------------------------------------------------------
	//fcnc_rdmacro_trg()実施後の少数点以下の桁数を読み出す関数
	//	リターン値  カスタムマクロ変数の小数点以下の桁数
	//----------------------------------------------------------
	__declspec(dllexport) int fcnc_rdmacro_dec_val()
	{
		return(dec_val_mem);
	}
}

Pythonプログラムに必要なDLL

FANUC CNCとイーサネット通信してカスタムマクロ変数を読み出すPythonプログラムに必要なDLLは、新たに作成した FanucComDll64.dllとFOCAS2 Libraryの Fwlib64.dllとfwlib64.dllです。これらのDLLをPythonのソースコードファイルと同じフォルダに置きます。

FANUC CNCからカスタムマクロ変数値を読み出すPythonプログラム

作成したDLLを使用してFANUC CNCからカスタムマクロ変数値を読み出すPythonプログラムを以下に示します。PythonからDLLのC++の関数をimportしたctypesの機能を使用して呼び出しています。
cdll.LoadLibrary(‘./FanucComDll64.dll’)で作成したDLLを呼び出しています。
argtypesを使用して呼び出す関数の引数型を指定しています。
restypeを使用して呼び出す関数の戻り値の型を指定しています。
カスタムマクロ変数値は整数のデータ値と小数点以下の桁数の形で読み出されます。

from ctypes import cdll
import ctypes

#FANUC CNCイーサネット接続用DLLを読み出す(64bit用)
F_dll = cdll.LoadLibrary('./FanucComDll64.dll') 

#FANUC CNCとイーサネット接続する
F_dll.fcnc_allclibhndl3.argtypes=(ctypes.c_int,ctypes.c_int,ctypes.c_int,ctypes.c_int,ctypes.c_int,ctypes.c_int)
F_dll.fcnc_allclibhndl3.restype=ctypes.c_int
FlibHndl = F_dll.fcnc_allclibhndl3(192, 168, 0, 1, 8193, 20)
print('FlibHndl=', FlibHndl)

#カスタムマクロ変数(#503)を読み出す
F_dll.fcnc_rdmacro_trg.argtypes=(ctypes.c_int,ctypes.c_int)
F_dll.fcnc_rdmacro_trg.restype=ctypes.c_int
result = F_dll.fcnc_rdmacro_trg(FlibHndl, 503)
if result == 0:     #正常終了?
    F_dll.fcnc_rdmacro_mcr_val.restype=ctypes.c_int
    mcr_val = F_dll.fcnc_rdmacro_mcr_val()  #マクロデータ値読出し
    
    F_dll.fcnc_rdmacro_dec_val.restype=ctypes.c_int
    dec_val = F_dll.fcnc_rdmacro_dec_val()  #少数点以下の桁数読出し
    
    print('rdmacro result=', result)
    print('mcr_val=', mcr_val)  #マクロデータ値表示
    print('dec_val=', dec_val)  #少数点以下の桁数表示
else:
    print('rdmacro result=', result)

#イーサネット切断する
F_dll.fcnc_freelibhndl.argtypes=(ctypes.c_int,)
F_dll.fcnc_freelibhndl.restype=ctypes.c_int
result = F_dll.fcnc_freelibhndl(FlibHndl)
print('disconnect result=',result)

最後に

以上で、FANUC CNCとイーサネット接続しカスタムマクロ変数値を読み出すPythonプログラムの説明を終わります。思わぬミスや考え違いがあるかもしれませんがご容赦お願いいたします。


PAGE TOP