[plc&pc 연동] nodejs를 이용한 modbus RTU 구현
plc와 pc 연동을 C#, python으로 구현해보고, npm에 modbus-serial 모듈이 있는 것을 알고 난 후 nodejs를 활용하여 plc와의 연동을 테스트해보았다.
예제 코드도 가지고 있었던 터라 아무 문제 없이 해결할 수 있을 줄 알았지만 예상치 못한 문제가 발생하였다.
Issue
콜백 함수의 향연으로 Thread를 신경쓰지 않아도 되는 nodejs 특성상 어떤 놈이 먼저 실행이 될 지 알 수가 없다...ㅋ
그러다 보니 serial 통신을 이용해서 하나의 데이터만 가져오는 것은 아무 상관이 없었는데, read를 두 번 이상 하니 이 함수 놈이 요청하고, serial통신 버퍼에 있는 데이터를 몽땅 가져오는 바람에 뒤에 실행되는 read함수에서 데이터가 없다며 에러를 토해내는 것이 아닌가..
그렇다면 내가 할 수 있는 최선은 이 중구난방으로 실행되는 비동기 함수들을 순차적으로 실행시켜주면 되는 일..
그래서 Async.series를 사용해서 문제를 해결하였다.
p.s. series는 단순 순차 실행, waterfall은 순차 실행인데 결과를 다음 콜백 함수에 전달 할 수 있다고 한다더라.
해결
개발 환경 : Ubuntu 64bit 16.04
IDE : vscode
nodejs version : v13.11.0
npm package : modbus-serial, async
코드
const ModbusRTU = require("modbus-serial")
var async = require("async");
var client = new ModbusRTU();
var timeoutConnectRef = null
function connect(){
console.log("Connecting..!!");
clearTimeout(timeoutConnectRef);
if(client.isOpen){
console.log('Already connected!!');
run();
}
client.connectRTUBuffered("/dev/ttyUSB0", {dataBits: 8, stopBits: 1, baudRate: 115200})
.then(setClient)
.then(function() {console.log("Connected");})
}
function setClient(){
console.log("Set client ID..!!");
client.setID(1);
client.setTimeout(3000);
run();
}
var task = [
function(callback) {
client.readDiscreteInputs(1,4, function(err, res_read){
console.log("L1: " ,res_read.data[0], res_read.data[1], res_read.data[2], res_read.data[3])
callback()
})
},
function(callback){
client.readHoldingRegisters(1,4, function(err, res_read){
console.log("L1Q: " ,res_read.data[0], res_read.data[1], res_read.data[2], res_read.data[3])
callback()
})
}
]
function run(){
var setLoop = setInterval(function(){
async.series(task, function(err, results){
console.log("done")
})
}, 1000)
}
connect()
출력 결과
task 변수를 생성하여 순차적으로 동작시킬 task를 설정해주고, 1초에 한번씩 위의 동작을 반복하여 내가 필요한 값을 읽어들이는 작업을 수행하였다.
처음에 callback()을 function(callback){} 안에 넣지 않고 밖에 넣었더니 순차적으로 진행이 되지 않는 실수를..ㅎ;;
1번의 콜백 함수가 호출이 된 후, 콜백 함수가 수행이 되고, 1의 결과를 출력하고 그 다음 콜백 함수를 수행하는 형식으로 동작한다.
이거야 함수가 2개밖에 안되서 콜백에 콜백을 써도 되겠지만..... 한 3~4개만 되도 보는 사람 빡치게 만들기 충분한 코드가 될 것이라고 확답할 수 있다..ㅎㅎ
python으로 구현할 때는 thread timer를 이용하여 일정 주기로 Read&Write를 수행했는데, 흠.... js가 좀 더 깔끔한거 같기도 하고...ㅎㅎ
무튼 재밌다 코딩 ㅋㅋ