質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

保存

保存(save)とは、特定のファイルを、ハードディスク等の外部記憶装置に記録する行為を指します。

検索

検索は、あるデータの集まりの中から 目的のデータを見つけ出すことです。

ネットワーク

ネットワークとは、複数のコンピューター間を接続する技術です。インターネットが最も主流なネットワークの形態で、TCP/IP・HTTP・DNSなどの様々なプロトコルや、ルータやサーバーなどの様々な機器の上に成り立っています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

6178閲覧

[エラー:WinError 10048] PythonでPLCデータを取得

ppss

総合スコア40

ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

保存

保存(save)とは、特定のファイルを、ハードディスク等の外部記憶装置に記録する行為を指します。

検索

検索は、あるデータの集まりの中から 目的のデータを見つけ出すことです。

ネットワーク

ネットワークとは、複数のコンピューター間を接続する技術です。インターネットが最も主流なネットワークの形態で、TCP/IP・HTTP・DNSなどの様々なプロトコルや、ルータやサーバーなどの様々な機器の上に成り立っています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/10/01 02:39

編集2021/10/04 05:56

Pythonプログラムで PLCのデータメモリの値を取得し
CSVファイルで保存するというコードを書いています。

★前提
PLCとPCをイーサネットで接続している
PLCデータメモリ【D1000】は【1】か【2】が格納されるようラダーを作成している。
1と2に変化するタイミングは1日2回(午前1回 午後1回)
1が格納されていてトリガーが入ると5分間 2が格納される その後また1が格納される仕様。

★プログラム概要
Pythonプログラムでは
PLC データメモリ【D1000】の値を常に取得し
D1000値が【2】になった時に【D0~D99】の値をCSV出力する
CSV出力後も D1000の値を常に取得し続ける

D0~D99 値取得タイムラグ 5分以内に取得できれば問題ないです。

というプログラムを作成したいです。

★困っている部分
「CSV出力後も D1000の値を常に取得し続ける」
という部分がうまくいきません
接続し続けていると 何かをきっかけに(?)
以下のエラーが発生します。

【後追記】※接続スタートから決まって 40秒後に以下のエラーが発生することが判明しました。

**例外が発生しました: OSError
[WinError 10048] 通常、各ソケット アドレスに対してプロトコル、ネットワーク アドレス、またはポートのどれか 1 つのみを使用できます。
**

実際のコードは以下の通りです。
どの部分を変更するべきでしょうか?
また調べる際の 検索ワード等 何かヒントを頂けると幸いです。
何卒よろしくお願い致します。

Python

1コード 2# プログラムの概要  データメモリの値をCSVファイルとして保存 3# データ保存の概要  PCの任意のフォルダ内に 日付フォルダを作成し 1.CSVというCSVファイルを作成 4 5import logging 6import os 7import socket 8import csv 9import time 10import codecs 11import datetime 12import tkinter.messagebox as mb 13import pandas as pd 14import traceback 15import sys 16 17# ・・・・・・・・・・・・・・・保存先を決めるプログラム・・・・・・・・・・・・・・・・・・・・・・・・・ 18# 今日の日付を取得 todayとする  (フォルダ名に使用) 19 20today = datetime.date.today() 21 22#  dir_name 日付フォルダを作成するフォルダのパス 23dir_name ='C:/Users/テスト/' 24 25#  os.makedirs フォルダを作成////// 26os.makedirs(dir_name + str(today),exist_ok=True) 27#  save_dir  はCSVファイルを保存するフォルダのパス 28save_dir = 'C:/Users/テスト/'+ str(today) + "/" 29# ・・・・・・・・・・・・・・・保存先を決めるプログラム・・・・・・・・・完・・・・・・・・・・・・・・・・ 30 31 32# ・・・・・・・・・・・・・PLC接続先指定・・・・・・・・・・・・・・・・・・・・・・・・ 33 # PLCのIPアドレス  Port番号 34host_ip = '192.168.30.100' 35host_port = 8501 36# ・・・・・・・・・・・・・PLC接続先指定・・・・・・・・・・・・・完・・・・・・・・・・・ 37 38 39# ・・・・・・16ビットを読み込む時の関数・・・・・・・・・・・・・・・・・・・・・・・・・・・・・ 40def readDM_16int(adrs): 41 #PLCへの接続 42 logging.basicConfig(level=logging.DEBUG, format='%(threadName)s: %(message)s') 43 logging.debug('start') 44 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 45 client.connect((host_ip ,host_port)) # サーバーに接続 46 comand = f"RD DM{adrs}.U\r" 47 ascii_comand = client.send(comand.encode("ascii")) 48 #以下PLCから返ってきたresponceを任意の形に変換 49 response = client.recv(16) 50 response = response.decode("UTF-8") 51 response = response.replace("\n","") 52 response = response[:5] 53 return response 54# ・・・・・・16ビットを読み込む時の関数・・・・・・・・完・・・・・・・・・・・・・・・・・・・・・ 55 56 57 58# csvファイル(1.csv・・・・・・・・・・・・・・・・・・・ 59def to_csv_1(data_list): 60 with open(save_dir + '1.csv', 'a',encoding='utf-8', newline='') as f: 61 writer = csv.writer(f) 62 writer.writerow(data_list) 63# csvファイル・・・・・完・・・・・・・・・・・・・・ 64 65 66 67# まとめ関数 D//////////////////////////////// 68def D(statr,end,interval): 69 data_list = [] 70 for no in range(statr,end,interval): 71 DM = "DM" + str(no) 72 DM_res = readDM_16int(no) 73 dm = DM_res.strip() 74 data_lists = data_list.append(dm) 75 to_csv_1(data_list) 76# まとめ関数 D///////////////////////完///////// 77 78 79# D1000を監視 1 何もしない 2 CSV出力 80TF = False 81while True: 82 83 if readDM_16int(1000) == "00002" and TF == False: 84 D(0,100,1) 85 TF = True 86 elif readDM_16int(1000) == "00001": 87 TF = False 88 pass 89 else: 90 pass 91

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ソケットをクローズする処理が抜けていますので

python

1response = client.recv(16) 2client.close()

とするか、with文を使って

python

1with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client: 2 client.connect((host_ip ,host_port)) 3 comand = f"RD DM{adrs}.U\r" 4 ascii_comand = client.send(comand.encode("ascii")) 5 response = client.recv(16)

とする必要があると思います。

D0~D99は連続したメモリのようですので、ひとつひとつソケットで繋ぎ直して取得するのではなく、連続したデータを読み取るコマンド (RDS) を使用した方が良いのではないでしょうか。
参考:

TF というフラグを置くことによって、D1000の値が1から2に変化した時のみD0~D99の値を取得しているようですが、この1から2への変化はどの程度頻繁に起こるものなのでしょうか。また1から2への変化した後にD0~D99の値を取得するまでのタイムラグはどの程度許容されるものなのでしょうか。
というのも現在のコードですとCPUとI/Oの性能が許す限り連続してD1000の値を取得し続けているので、そこまで頻繁に監視する必要があるのかという疑問です。

readDM_16int関数の中でlogging.basicConfig(level=logging.DEBUG, format='%(threadName)s: %(message)s')を実行していますが、モジュールのトップレベルで1回のみ行えば十分です。ソケット接続にはまったく関係ない処理です。
logging自体、現在のコードではlogging.debug('start')でしか使用されていませんので、loggingを使って何をするという明確な意志がないのであれば、これらのコードは削除すべきと思います。

投稿2021/10/02 01:08

etherbeg

総合スコア1195

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ppss

2021/10/03 23:54

ご回答ありがとうございます。 D1000の値について 1と2に変化するタイミングは1日2回です(午前1回 午後1回)。 ずっと1が格納されていてトリガーが入ると5分間 2が格納される仕様になっています。 D0~D99 値取得タイムラグについて 5分以内に取得できれば問題ないです。 おっしゃる通り ここまで頻繁に監視する必要はないかと思いますので ご指導いただいた内容を踏まえ、コードを書き直してみたいと思います。 ご丁寧に添削して頂き誠にありがとうございます。
guest

0

自己解決

Python

1コード 2 if readDM_16int(1000) == "00002" and TF == False: 3 D(0,100,1) 4 TF = True 5 time.sleep(1) 6 elif readDM_16int(1000) == "00001": 7 TF = False 8 time.sleep(1) 9 pass 10 else: 11 time.sleep(1) 12 pass

上記の通り
【time.sleep】を使い一度 PLCとの通信を切断することでうまくいった。

投稿2021/10/11 02:50

ppss

総合スコア40

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問