Embedded/RaspberryPI

Raspberry Pi CM4에 ModbusTCP Server 실행해 보기 - 4편(ModbusTCP server와 유량센서와 연동)

변화의 물결1 2024. 12. 6. 16:03

 

 

안녕하세요.

 

실제로 연동하는 프로그램을 만들어 보려고 합니다.

 

 이전 ModbusTCP내용과 PulseCount를 잘 조합하면 될 것으로 생각했습니다.

그런데 가상환경에서 RPi.GPIO의 add_event_detect() 함수를 사용하면 이벤트를 받아서 처리할 수가 없었습니다.

 

 

 

이전 내용을 참고하시면 pigpio 라이브러리 사용하는 방법을 다시 찾아서 확인하였습니다.

최종적로 ModbusTCP와 pigpio를 이용해서 작업을 마무리할 수 있었습니다.

 


 

1. 코드 구성 확인

 

소스코드를 보기 전게 간단하게 맥락을 설명하면 아래와 같습니다. 

 

1) 필요한 라이브러리 및 모듈

 

pyModbusTCP: ModbusTCP 서버를 구현하기 위한 라이브러리

pigpio: GPIO 핀에서 센서 데이터를 안정적으로 읽어오기 위한 라이브러리

time: 시간 계산 및 흐름 제어

 

2) 유량 센서 설정

 

FLOW_SENSOR_PIN: 유량 센서가 연결된 라즈베리파이의 GPIO 핀 번호

PULSES_PER_LITER: 유량 센서가 1리터 유량당 발생시키는 펄스 수

 

3) 펄스 카운트와 유량 계산

 

count_pulse(): 센서에서 감지한 펄스를 카운트

get_flow_rate(): 펄스를 이용해 유량(L/min)을 계산

  

4) ModbusTCP 서버 구현

 

 ModbusServer: ModbusTCP 서버 생성

서버는 유량 데이터를 Holding Register 주소 0번에 저장하며, 2자리 소수점은 정수 형태로 변환하여 저장

 

5) 메인 실행 흐름

 

Pigpio 초기화 및 센서 설정

ModbusTCP 서버 시작

루프에서 매초마다 유량을 계산하고 Modbus 레지스터에 값을 업데이트

 

 

2.  ModbusTCP와 Flow 센서 연동 전체 코드

 

$ vim flow.py 해서 아래 코드 작성

 

#!/bin/python

from pyModbusTCP.server import ModbusServer
import time
import pigpio


# 센서 설정
FLOW_SENSOR_PIN = 17  # Sensor GPIO Pin number
PULSES_PER_LITER = 595  # 595 pulses generated in 1L valume

# 변수 초기화
pulse_count = 0
start_time = time.time()

# Create an instance of ModbusServer
server = ModbusServer("192.168.0.59", 1503, no_block=True)


# callback function of detected pulse
def count_pulse(gpio, level, tick):
    global pulse_count
    pulse_count += 1

# Flow calcuation function
def get_flow_rate():
    global pulse_count, start_time
    end_time = time.time()
    elapsed_time = end_time - start_time

    # flow calculation (L/min)
    flow_rate = (pulse_count / PULSES_PER_LITER) * (60 / elapsed_time)


    # count and time init
    start_time = time.time()
    pulse_count = 0

    return flow_rate



if __name__ == "__main__":
    # pigpio init
    pi = pigpio.pi()
    if not pi.connected:
        print("The daemon is not running. Run the daemon.The daemon is not running. Run the daemon.: 'sudo pigpiod'")
        exit(1)

    # FLOW_SENSOR_PIN settings and registering callback functions
    pi.set_mode(FLOW_SENSOR_PIN, pigpio.INPUT)
    pi.set_pull_up_down(FLOW_SENSOR_PIN, pigpio.PUD_UP)
    cb = pi.callback(FLOW_SENSOR_PIN, pigpio.FALLING_EDGE, count_pulse)

    try:
        print("Start server...")
        server.start()
        print("Server is online")
        state = [0]
        while True:

            # call flow calculation function
            flow_rate = get_flow_rate()

            # Set value to Holding Register address 0
            server.data_bank.set_holding_registers(0, [int(flow_rate * 100)])  # save as integer type(maintain 2 decimal places)
            print(f"Flow Rate Updated: {flow_rate:.2f} L/min")
            time.sleep(1)

    except Exception as e:
        print(f"Error occurred: {e}")
        print("Shutdown server ...")
        server.stop()
        cb.cancel()
        pi.stop()
        print("Server is offline")

 

 

 

3. 실행 확인

 

pigpiod 데몬을 먼저 실행하고 이전에 설정한 가상환경을 실행한 후 소스를 실행합니다.

 

$ sudo pigpiod
$ source ~/virtualEnv/bin/activate
$ python flow.py

 

 

 

ModbusTCP에서도 정상적으로 연결되는지 확인하기 위해서 ModbusTCP Client(KiMons)를 사용해서 연결합니다.

포트는 이전에 사용하는 것으로 작동하고 1503으로 변경했습니다. Read Definition에서 Function은 03(Read Holding Registers)으로 설정한 후 읽으면 수치값이 변화하는 것을 알 수 있습니다.

 

 

 

4. 추가 진행해야 것들

 

 이것으로 간단하게 유량측정값을 ModbusTCP를 이용해서 전달하는 것을 확인하였습니다.

 

 그러나 위의 내용은 단순히 연동 작업이 가능한 것을 확인한 것이고, 실제로 사용하기 위해서는 코드 최적화 및 스레드를 사용한 Wirte 연동 및 예외처리... 자동실행을 위한 셀스크립트 등 작업을 해주어야 안정성 및 가치가 높아질 것입니다.

 

 

감사합니다.

 

 

반응형