MODBUS-RTU 구현 시 주의 사항

2021. 5. 21. 08:08 컴퓨터/프로그래밍

MODBUS-RTU 경험담

MODBUS-RTU 프로그램을 작성하면서 겪었던 경험담을 올립니다. 좀 당황스러운 일인데, 경험에 따라 생각이 다를 수 있어서 반드시 이래야 한다는 것은 아니지만, rs485 라인에 MODBUS-RTU 통신을 하는 분께 도움이 되지 않을까 해서 올립니다.

사건의 발단은 말 많고 탈 많은 rs485 통신 때문입니다. rs485 통신은 현장에 따라 희비가 극명합니다. 똑같은 시스템을 설치하는데도 어느 곳은 오전에 시작해서 오전에 끝나는데, 어떤 곳은 밤늦게까지 속을 썩입니다. rs485 통신은 장거리 통신이 가능하고 노이즈에 강하지만, 어디까지나 rs232와 비교해서입니다.

rs485 통신을 이론으로만 따졌다가는 고생을 많이 하게 되는데요, 노이즈에 강한 통신이어도 현장에서는 통신에 악영향을 끼치는 요소가 수두룩 합니다. 커다란 변압기 옆을 지나가기도 하고, 벽 사이로 보이지 않는 고압 전력선 옆이나 천정에 얼퀴설퀴 깔린 전선 위로 어쩔 수 없이 배선하다 보면 통신이 되었다가 안 되었다가 널뛰기를 합니다.

이런 이유로 MODBUS-RTU가 아니어도 rs485 통신 프로그램에서는 통신 상태를 확인할 수 있는 방법이나 데이터가 필요합니다.

회사에서 개발할 때는 잘 되던 장치가 현장에서는 뜻대로 안 되고 매우 둔 하게 움직인다면 그 원인을 찾아야 하는데, 잘 만들어진 로그 데이터는 정말 큰 도움이 됩니다. 로그 파일을 대충 흝어 보아도 통신 상태가 어떤지 쉽게 알 수 있도록 작성했다면 엉뚱한 곳에서 시간 낭비하는 수고를 덜 수 있는데요, 로그에 제어 결과만 남겼다면 로그 사이에 시간을 직접 계산하지 않는 이상 통신 상태를 확인하기 어렵습니다. 이렇게 로그 코딩을 했다면 차라리 로그에 저장된 데이터가 많지 않는 것이 도움이 됩니다. 왜일까요?

응답 Slave ID가 다르면 버려?

모 업체의 장비에 들어가는 MODBUS-RTU 통신 보드를 개발한 적이 있는데, 어느 날 담당자가 로그 파일을 들고 왔습니다. 로그 파일을 보니 몇 시간 간격으로 통신 불량이 생긴다고 따지네요. 온종일 조용하다가도 어느 날은 새벽에, 또 어떤 날은 낮에 몰려서 발생하기도 한다는 것이죠.

그 장비는 가전제품과는 비교할 수 없을 정도로 큰 전력을 사용해서 당연히 rs485 통신 보드가 영향을 받으므로 통신이 불량할 수 있다고 설명해 주었습니다. 그러나 황당한 것은 그다음 질문이었습니다.

분: rs485에 물린 장치는 딱 한 대입니다. 그래서 ID는 1번뿐입니다.
저: 네.
분: 로그에 찍힌 에러 내용을 보면 수신 ID가 0입니다. 이게 어떻게 된 것인가요?
저: 네? 뭐가 잘못되었습니까?
분: 아니, ID가 1번뿐인데 0번 자료를 왜 로그에 남기나요?

즉, 통신 보드가 제어하는 장치는 딱 한 대이고 그 장치의 국번 즉, Slave ID가 1번인데, 수신된 데이터의 Slave ID가 1이 아니면 무시해야 하는 것 아니냐면서, 이렇게 로그에 남기니 자기네 장치에 문제가 있는 것처럼 보인다는 것입니다.

순간 당황해서 어떻게 설명해 주어야 좋을지 모르겠더군요. 그때는 장황하게 설명했습니다만, 그분이 돌아간 다음에도 기분이 상해서 되새김질을 하다 보니 아래와 같이 간단히 이해시킬 수 있지 않았나 싶습니다.

저: Slave ID 1번으로 요청했는데 응답이 0번으로 오면 정상인가요? 에러인가요?
분: 에러입니다.
저: 에러이면 로그에 남겨야 하나요? 버려야 하나요?

rs485 통신을 위한 로그 파일의 중요성

따지러 온 분은 rs485 통신에 대해 잘 몰라서 그럴 수도 있겠다 싶지만, 여러 개발자와 일하다 보면 로그에 남기지 않고 버리는 분들이 있습니다. 심하게는 응답을 받지 못했을 때도 로그에 남기지 않습니다. 아마도 짧은 시간에 계속해서 통신하기 때문에 로그가 과도하게 쌓이는 것이 걱정이 되어 일부러 안 할 수도 있습니다.

그러나 요청한 Slave ID가 아닌 엉뚱한 데이터가 오는 것과 응답이 오지 않는 것도 중용한 데이터입니다. 반드시 로그에 남겨야 합니다. 이렇게 로그에 남기는 이유는 통신 라인 상태와 제어 장치의 이상 여부를 알 수 있기 때문입니다.

통신 패킷 불량이나 응답을 받지 못한 것을 로그에 남기지 않는다면 모두 성공한 데이터만 남습니다. 이렇게 성공 데이터만 로그에 남기도록 했는데, 현장 통신 상황이 매우 불량한 해서 로그를 열어 보니 내용이 별로 없다면 이유는 두 가지입니다.

  • 나의 프로그램이 계속 죽다·살다를 반복하거나
  • 통신이 불량한 것입니다.
  • 아니면, 제어 대상 장치에 큰 오류가 있던지요.

만일 통신 불량 자료를 저장하지 않았다면 차라리 로그 데이터가 없는 것이 빠르게 의심할 수 있습니다!

통신이 안 되니 제어에 대한 자료도 없는 것이고 이유는 앞서 3가지일 것입니다. 그러나 통신 불량이 어쩌다 띄엄띄엄 주기적으로 발생하면 로그만으로는 문제의 원인을 예측하기가 매우 어렵습니다. 로그 파일을 열어보니 주르륵 쌓인 것이 많아서 잘 작동하고 있는 것처럼 보이거든요. 아니면 수많은 로그를 스크롤해 가며 시간 차이를 확인해야 합니다.

통신 라인을 찍어 보니...

문제를 제기한 업체에서 오실로스코프로 찍어서 확인해 보니 MODBUS 통신 보드에서 MODBUS 패킷을 전송했지만, 장치에서 응답을 하지 않아서 다시 MODBUS 패킷을 전송하는 찰나에 장치에서 응답 데이터를 보내는 바람에 깨진 것이었습니다. 응답 대기 시간이 충분히 길었는데도 어떤 상황에서는 장치의 응답이 너무 느렸던 것이죠. 결국 응답 대기 시간을 두 배로 늘려서 해결했습니다. 어쩐지 모든 통신 불량의 Slave ID가 0번으로 와서 이상하다 했습니다.

만일 로그에 통신 에러를 남기지 않았다면 이런 문제가 있었다는 것을 알 수나 있었을까요?

로그 파일에서 특정 로그만 쉽게 찾는 방법

로그 파일을 하루마다 하나씩 만든다고 해도 상황에 따라서 데이터가 매우 많을 수 있습니다. 장비별 작동·상태와 제어 요청·응답 등의 내용과 함께 에러 로그가 섞여 있을 텐데요, 어제 하루 중에 얼마나 통신 에러가 발생했는지 확인하려면 어떻게 해야 할까요? 문자열 찾기 기능으로 계속 찾기에는 너무 힘이 듭니다.

이렇게 문자열로 찾기보다는 한 번에 대충 에러가 어떻게 발생하는지 알 수 있습니다. 바로 비주얼 스튜디오를 사용하는 것입니다.

▲ 비주얼 스튜디오 코드에서는 편집기 오른쪽에 내용 전체를 보여 주는 작은 윈도가 있습니다. 편집기에서 특정 문자열을 마우스 더블 클릭으로 선택하면 같은 문자열의 위치를 우측에 작은 윈도우에 보여 줍니다. 즉, 통신 에러 코드만 선택했다면 대충 하루에 언제 에러가 발생했는지, 얼마나 자주 발생하는지를 한눈에 알 수 있는 것이죠.

libmodbus 라이브러리 추천

MODBUS 얘기가 나온 김에 코드 구현에 대해서도 말씀드리겠습니다. 개발자마다 의견이 다르겠지만, MODBUS 프로토콜을 구현하는 것은 그렇게 어려운 일이 아닙니다. 그러나 직접 구현하기보다는 libmodbus 라이브러리를 권합니다. 모든 코드는 내가 다 작성해야 직성이 풀리는 개발자가 있습니다. 지식에 대한 욕심도 있지만, 내가 만든 소스여야 보기에 좋고 문제가 생겨도 대응할 수 있다고 주장하기도 합니다.

그러나 무시 못할 것은 코드 생산성입니다. 이런 고집을 피우는 분께는 이 말씀을 드리고 싶어요. UART를 이용하는 MODBUS-RTU는 그나마 쉽게 작성할 수 있습니다. 그러나 TCP/IP를 지원하는 요청이 들어오면 또 직접 코딩해야 합니다. MODBUS TCP/IP 클라이언트는 그나마 쉽지요, 서버 작성은 어떻게 하실 것인가요? MODBUS over TCP와 over UDP가 필요해지면 그때도 코딩하시겠습니까? 상대방이 MODBUS-ASCII를 용청할 수도 있습니다.

매번 만들 때마다 수고롭지만, 올바르게 코딩했는지 검증하는 것도 쉽지 않습니다.

코드의 생산성은 얼마큼 빨리 프로그램을 작성하고 디버깅해서 작업을 완료하느냐의 의미가 있지만, 다른 사람에게 쉽고 빠르게 인수인계하는 것도 큰 요소입니다. 모두 나 만의 코드로 작성해서 모든 코드를 일일이 설명하기보다는 범용적으로 사용하는 라이브러리를 사용함으로써 수고로움을 크게 줄일 수 있습니다. 많은 개발자가 사용하는 라이브러리는 인터넷에 설명서와 관련 자료가 많아서 세세하게 설명할 필요가 없습니다.

libmodbus 라이브러리가 제공하는 변수 타입과 함수 형태가 매우 생소해서 나만의 코딩 습관과 맞지 않을 수 있습니다. 그러나 libmodbus는 매우 많은 개발자가 사용하는 라이브러리로 인터넷에서 사용 예제까지 쉽게 찾을 수 있습니다. 개발하기 쉽고 후임이나 업체에게 인계하기가 매우 수월합니다.

MODBUS 외부 유명 프로그램으로 검증

MODBUS 프로그램을 작성한다면 디버깅을 위해 응답 프로그램을 만들어서 테스트합니다만, 이렇게 디버깅을 위한 프로그램을 직접 만들기보다는 Modbus Poll이나 Modbus Slave 같은 외부 프로그램으로 검증하는 것이 좋습니다. 자기 프로그램을 자기가 만든 프로그램으로 검증한다고 해서 디버깅이 안 되는 것은 아닙니다만, MODBUS는 통신 프로그램이어서 다른 개발자와도 통신해야 합니다.

안타깝게도 통신이 제대로 되지 않는다면 원인을 찾아야 하는데, 내가 만든 프로그램으로 상대방에게 설명하려고 하면 장황해지고 신뢰를 얻기 힘들기도 합니다. 내가 만든 프로그램이 아닌 외부에서 MODBUS 전용으로 만들어진 프로그램으로 확인했다면 얘기가 수월해집니다. 상대방이 트집 잡을 꺼리가 없는 것이죠.

특히, 모드버스 프로토콜은 Modbus Poll로 검증해서 이상이 없다면, 상대방에게 Modbus Poll로 확인해 보라고 하면 수고로움을 크게 줄일 수 있습니다. 내가 만든 디버깅 프로그램은 주관적인 느낌이라면 Modbus Poll은 객관적인 테스트를 진행하는 것 같은데요, 상대방과 말이 잘 안 통한다 싶으면 Modbus Poll로 확인했다 또는 Modbus Poll로 확인하라고 하면 끝입니다. 내 프로그램에서 확인했다고 하면 믿지를 않습니다.

Modbus Poll과 Modbus Slave는 유료이지만, 시건방진 개발자에게 시달리는 것을 생각하면 돈이 아깝지 않습니다.

업체와 좋지 않은 기억으로 이 글을 쓰게 되었습니다만, 이런 경우 말고도 떠들 얘기가 참 많습니다. rs485 통신을 처음 접했을 때는 이론으로만 덤볐다가 얼마나 고생했던지요. 당시에 사용했던 하드웨어에 비해 요즘은 정말 많이 좋아졌기도 했습니다만, rs485에서는 통신 에러가 발생하는 것은 당연하다고 생각을 바꾼 이후로 적응하기 쉬워졌습니다. 그만큼 통신 에러에 대한 대응 코딩에 더욱 신경을 쓰고요.

통신 프로그램 얘기는 항상 말이 길어지네요. 모쪼록 MODBUS 통신 프로그램에 도움이 되는 글이 되기를 바랍니다.

이 댓글을 비밀 댓글로