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()

 

출력 결과

ㅣ1은 bit를, L1Q는 word를 읽는 것.

github : https://github.com/Mistive/-js-modbusRTU.git

 

task 변수를 생성하여 순차적으로 동작시킬 task를 설정해주고, 1초에 한번씩 위의 동작을 반복하여 내가 필요한 값을 읽어들이는 작업을 수행하였다.

 

처음에 callback()을 function(callback){} 안에 넣지 않고 밖에 넣었더니 순차적으로 진행이 되지 않는 실수를..ㅎ;;

1번의 콜백 함수가 호출이 된 후, 콜백 함수가 수행이 되고, 1의 결과를 출력하고 그 다음 콜백 함수를 수행하는 형식으로 동작한다.

 

이거야 함수가 2개밖에 안되서 콜백에 콜백을 써도 되겠지만..... 한 3~4개만 되도 보는 사람 빡치게 만들기 충분한 코드가 될 것이라고 확답할 수 있다..ㅎㅎ

 

python으로 구현할 때는 thread timer를 이용하여 일정 주기로 Read&Write를 수행했는데, 흠.... js가 좀 더 깔끔한거 같기도 하고...ㅎㅎ

 

무튼 재밌다 코딩 ㅋㅋ

'PLC' 카테고리의 다른 글

[PLC, Python]PLC를 통한 PC 동영상 제어  (9) 2020.02.28

서론

PLC의 데이터를 이용하여 PC의 동영상을 켜고 끄는 동작을 구현해보려고 한다.

 

참 많은 우여곡절이 있었다...

 

처음엔 라즈베리파이의 omxplayer를 이용하여 구현해보려고 했는데.... omxplayer-wrapper는 2.7버전에서 구동테스트를 하고, modbus는 3.5버전에서 구동 테스트를 하고....ㅋ

 

동영상 플레이어를 어떻게 제어할까 고민하다가 subprocess를 이용하여 다른 프로세스에 명령을 보내는(?) 방법을 찾아보던 중 pytube라는 패키지에 눈이 돌아갔다.

(나도 왜 돌아갔는지는 모르겠지만..ㅋ)

 

그런데 pytube를 아무리 설치해도 안되더라.... 자꾸 quote가 없다고 에러가 뜨는데 인터넷을 아무리 뒤져봐도 이 에러에 대한 원인을 찾을 수 없었다....ㅋㅋㅋ

 

그러던 중 내가 환경 설정을 아주 x같이 했다는 것 역시 깨닫게 되었고.... 오늘 python 가상환경에 대해서 한 걸음 더 나아갈 수 있었다.


본론

각설하고, 결국 최종적으로 결정한 나의 테스트 환경은 이러하다.

  • PC
    • ubuntu 16.04 LTS
    • python 3.7 with anaconda
    • python-vlc
    • pyserial
  • PLC
    • xg5000
    • LS 산전 제품

참 우여곡절이 많았다....

 

오늘 회사에 라즈베리파이를 들고가서 이것저것 테스트 해보려고 하다가 바보같이 micro sd카드를 뽀개먹었다. 그것도 케이스에 끼우다가...ㅋ

 

당연히 동작은 맛이 갔고... 나는 오늘 무엇을 해야하는가 고민하다가....

 

rasbian과 같은 리눅스 계열인 ubuntu를 이용하여 한 번 테스트를 진행해봐야겠다라고 결심을 하고 실행에 옮기기 시작했다.

 

그러던 중 서론에서 이야기 했던 pytube관련 issue를 만나게 되었고 삽질을 오질나게 했다는 것...ㅋ


아나콘다3 가상환경 설정

아나콘다..... python을 이용하여 프로젝트를 진행하다보면 다양한 패키지들을 활용하게 되는데 이러한 패키지 설치 환경을 구분해주는 일종의 프레임워크를 만들 수 있는 도구라고 볼 수 있을 것 같다.

 

나는 pytube라는 패키지 때문에 ubuntu에 아나콘다를 깔게 되었다.

 

처음에는 그냥 내가 프로젝트 해봤자 이 환경에서 얼마나 하겠어... 하고 그냥 초기의 ubuntu 환경에서 작업을 진행하려고 했다.

 

하지만 ubuntu 16.04 LTS에는 python 2.7 버전과 python 3.5 버전이 이미 깔려있더라....

pip으로 패키지를 깔면 2.7에 저장되고, pip3로 패키지를 깔면 3.5에 저장이 되고.... 설상가상으로 pytube는 계속 인터넷에 쳐도 안나오는 오류 메세지를 내보내고..ㅋㅋ

 

그래서 ubuntu에 아나콘다를 깔았다.

 

ubuntu에 아나콘다 까는 법

간단하다.

1. 아나콘다3 홈페이지에서 linux 버전의 아나콘다3를 다운받는다.(~~~~~.sh 파일임)

2. 다운받은 쉘 파일을 설치해준다.

$ bash Anaconda3-2019.03-Linux-x86_64.sh

3. 아나콘다에서 설치한 환경변수를 반영하기 위해서 bashrc를 읽는다(터미널을 껐다 켜도 된다)

$ source ~/.bashrc

4. 가상환경을 만든다.

아래는 conda에서 자주 쓰이는 명령어들이다. 진짜 많이 쓰이더라.

※ 설치
$ conda create -n [가상환경 이름] [파이썬 버전]
$ conda create -n py356 python=3.5.6

※ 제거
$ conda remove -n [가상환경 이름] --all
$ conda remove -n py356 --all
 
※ 확인
$ conda info --envs

※ 실행
$ conda activate [가상환경 이름]
$ conda activate py356

※ 종료
$ conda deactivate

5. 환경 변수를 설정을 하고 나면 다음부 ubuntu의 터미널을 키게 되면 앞에 저런게 붙는다. 아나콘다3의 root 환경이라는 의미다.

 

저기서 conda activate를 수행하면 (base)가 [가상환경 이름]으로 바뀌는 것을 알 수 있다.

 

추가적으로 나는 ubuntu에 pycharm을 직접 깔아서 개발을 진행하려고 생각했다


pycharm-community 설치하는 법

너무 간단하다.

※ 설치
$ sudo apt install snapd snapd-xdg-open

$ sudo snap install pycharm-community --classic

※ 실행
$ pycharm-community

pycharm 가상환경 설정하는 법

1. 아나콘다 가상환경 생성(가상환경 이름 : test, python 버전 = 3.7)

$ conda create -n test python=3.7

 

2. 가상환경 생성 여부 확인 

$  conda info --envs

잘 생성 되었다


3. pycharm-community 실행(시간 조금 걸림... 아 겁나 느리네)

$  pycharm-community


4. Configure -> Settings 클릭

 

5. Project Interpreter -> 톱니바퀴 아이콘 -> Show All

 

6. 아까 만든 가상환경 설정에서 python interpreter 설정

 

7. 가상환경 선택

 

8.  새 프로젝트 생성

 

9. 아까 만든 인터프리터 설정 후 create

9.1 만약 인터프리터를 변경하고 싶다면 생성된 프로젝트-> Setting에서도 변경 가능

10. 생성된 프로젝트에서 pycharm에 존재하는 Terminal을 켜게 되면 프로젝트 생성 가능

 

11. 해당 터미널에서 설치하고 싶은 패지키 설치

 

12. 설치된 pip 패키지 정보들 확인

$ pip list

 

 

12.1 Setting(Ctrl + Alt + S) -> Project Interpreter에서도 확인 가능


다음으로는 vlc를 설치해서 프로젝트를 진행해보려 한다.

python-vlc로 동영상 제어하기

※ vlc player  설치
$ sudo apt-get install vlc

※ python-vlc  설치
$ pip install python-vlc

▼ 예제 코드 입력(파일 위치 수정이 필요할 경우 수정)

#-*- coding:utf-8 -*
#https://www.videolan.org/developers/vlc/doc/doxygen/html/group__libvlc__video.html#gabdbb7230cc3db78e73070ce10e679315

import vlc
import time
class Player():
    def __init__(self):
        self._instance = vlc.Instance(['--video-on-top', '--input-repeat=-1'])  #동영상 재생 반복
        self._player = self._instance.media_player_new()
        self._player.set_fullscreen(True)	#동영상을 전체화면으로 실행

    def play(self, path):
        media = self._instance.media_new(path)
        self._player.set_media(media)
        self._player.play()

    def stop(self):
        self._player.stop()

p=Player()
p.play('./videos/01.mp4')
time.sleep(5)
p.stop()
p.play('./videos/02.mp4')
time.sleep(5)

잘 동작하는 것을 확인할 수 있다.

 

▼ 간단하게 이런 식으로도 가능

import vlc
import time

player = vlc.MediaPlayer("./videos/01.mp4")
vlc.libvlc_set_fullscreen(player, True)
player.play()
time.sleep(5)

가상환경에서 외부 usb Serial 포트 연결

을 하기 위해서는 ubuntu에서 현재 사용자 계정이 Serial Port로 접근을 할 수 있게 권한을 설정해주어야 함.

root 계정으로 로그인
$ sudo su

passwd 입력

※ /dev 폴더로 이동
$ cd /dev


※ tttyUSB0 권한 등록
$ chown [사용자 계정 이름] ttyUSB0
chown mistive ttyUSB0

 

'PLC' 카테고리의 다른 글

[plc&pc 연동] nodejs를 이용한 modbus RTU 구현  (0) 2020.03.17

+ Recent posts