참고 문헌 : http://www.simplymodbus.ca/ASCII.htm

 

Modbus ASCII vs RTU | Simply Modbus Software

 

www.simplymodbus.ca

Modbus RTU는 구현을 했고... Modbus Ascii를 구현하기 위해 필요한 LRC...

 

LRC가 뭔지 찾아보니깐 Longitudinal Redundancy Check 라는 놈이란다.

 

구글 번역기 왈 "종 방향 중복검사"

 

흠... 뭔 소리지... 일단 에러 체크 방법 중 하나기는 한데...

 

에러를 어떻게 체크하는지 알아보니깐

 

LRC 이전 Ascii 코드를 바이너리로 다 바꾼 다음에,

다 더하고, 2의 보수를 취해준 결과값을 LRC랑 비교를 한다고 한다.

 

음... 그렇구나 ㅎㅎ

 

그건 그렇고 그래서 LRC는 어떻게 구하는데?

 

찾아보니

 

이렇게 구한단다.

 

1. byte를 모두 더해준다~

2. 8bit가 넘어가는 carry는 삭제!

3. 2의 보수를 취해준다~

4. 쨘

 

무지 간단하네 ㅋㅋㅋ

 

바로 코드로 옮겨보았다.

calcLRC()_python

def calcLRC(data):
    #Add the RTU Value
    RTU_sum = ((sum(data) & 0xff) ^ 0xff) + 0x01

    lrc = [RTU_sum >> 4, RTU_sum & 0xf]
    
    return lrc

뭐가 이리 간단해?ㅋㅋㅋ

 

입력값은 이렇다.

 LRC = calcLRC([0x11, 0x03, 0x00, 0x6B, 0x00, 0x03])

위의 코드를 해석해보자면.... 음... 일단 다 더하고? 비트 연산을 이용해서 8bit 이후의 값은 제거해주고, 1의 보수를 취해준 다음에 1을 뙇 더해주면?(2의 보수지요)

끗.

 

그 결과를 Hi, Lo 두 개로 나눠서 리스트에 넣고 반환해줬다.

 

진짜 되는지는 PLC에서 확인해봐야겠찌 ㅎㅎ

hexToAscii()_python

def hexToAscii(data):
    ret = []
    for d in data:
        ret.append(ord(format(d, 'X')))

    return ret

추가로 hex를 Ascii로 바꿔주는 함수이다.

 

data 타입은 calcLRC와 동일!

 

코드를 쪼금만 분석해보자면....

 

format(d, 'X') : d를 대문자 hexa형태의 String으로 변환해주는 것이다.

즉, d에 10이라는 int 타입이 있다면 10의 hex값은 A이니깐

format(d, 'X') = "A"라는 의미.

 

ord(parameter) : parameter를 Ascii값으로 바꿔주는 놈이다!

c의 경우 char라는 아주 좋은 타입이 있어서 'A' 하면 바로 Ascii로 인식되지만 이놈의 파이썬은 타입관련된 내용들이 참 그지같다..ㅎ

무튼 parameter가 'A'라면 A의 아스키코드값은 65(=0x41) 이므로 해당 값을 int 형태로 반환한다.

 


추가_2020.09.16

 

Java로 코드를 짜봤다.

 

이번에는 인풋이 그냥 ASCII String 형태로 들어올 때 출력해주는 걸로 짜봤다.

 

package test;

class Hello {
 
	public static void main(String[] args) {
		String s = "0101000A0001";
		
		//반환된 LRC값을 기존 명령 코드에 추가한다.
		s=s + calcLRC(s);
		
		//완성된 명령 코드 앞뒤에 Head와 Tail을 붙여 ASCII to Byte로 변환한 후 전송한다.
		
		byte[] s_byte = s.getBytes();
		byte[] head = {0x3A};
		byte[] tail = {0x0D, 0x0A};
		byte[] result_b = new byte[head.length + s_byte.length + tail.length];
		
		System.arraycopy(head, 0, result_b, 0, head.length);
		System.arraycopy(s_byte, 0, result_b, head.length, s_byte.length);
		System.arraycopy(tail, 0, result_b, head.length+s_byte.length, tail.length);
		
		String result_s = new String(result_b);
		System.out.print("HEX : ");
		for (byte b : result_b){
			System.out.print("0x"+Integer.toHexString(b).toUpperCase()+ " ");
		}
		
		System.out.println();
		
		System.out.println("ASCII: " + result_s);
		System.out.println("(CR LF는 공백이라서 표시 안됨)");
	}
	
    static String calcLRC(String s) {
        int sum = 0;
        
        int len = s.length();
        for(int i=0; i<len; i=i+2) {
        	//String을 1byte씩 잘라 Integer로 변환 한 값을 전부 더한다.
        	String subS = s.substring(i, i+2);
        	sum += Integer.parseInt(subS, 16);
        }
        
        //2's complement 수행
        sum = (((sum & 0xff) ^ 0xff) + 0x01);
        
        //상위 4bit, 하위 4bit로 자른다.
        int lrcH = sum >> 4;
        int lrcL = sum & 0xf;
        
 
        //자른 Bit를 다시 ASCII(HexaString 형태)로 변환한다.
        String res = Integer.toHexString(lrcH) + Integer.toHexString(lrcL);       
        return res.toUpperCase();
    }
   
  
}

Test 결과

 

제발 이거 보고 짜길 바란다..ㅎ;;;

Pycharm에서 새로운 아나콘다 가상환경을 설정하고, 인터프리터로 설정한 후에 opencv-python을 쓰기 위해

 

$ pip install opencv-python

을 친 결과....

Fatal error in launcher: Unable to create process using..?

이건 또 무슨 에러이길래.... 하고 인터넷을 찾아보니

 

PATH 설정이 잘못(or 안되)있어서 발생하는 문제라고 한다.

 

PATH가 무슨 역할을 하느냐... 예를 들어 pip이라는 명령어를 사용하고 싶다면 pip을 실행시켜줄 실행파일을 찾아야한다... 하지만 PATH가 설정이 잘못되어 있을 경우 이 실행파일을 찾을 수 없으므로 위와 같은 오류가 발생하는 것...

 

어떻게 해결을 하냐...

 

일단 나는 anaconda 가상환경에서 환경 설정을 수행할 것이다. 그러려면 터미널이 아나콘다에 접속을 해야 된다.

 

즉, 가장 먼저 아나콘다에 접속을 해줄 수 있게 PATH 설정을 해줄 것이다.

 

Anaconda3 PATH 설정(환경 변수 설정

1. 아래와 같이 시스템 환경 변수 편집 창으로 들어간다.

2. 아래와 같이 들어가준다.

3. 아래와 같이 3개의 PATH를 추가한다.

4. 그리고 컴퓨터를 껐다 켜주면 PATH가 반영이 된다.

 


자... 이제 PATH 설정이 모두 끝이 났다.

 

그럼 다시 내가 개발할 pycharm 프로젝트에 들어가서 아나콘다에 접속을 해보자.

 

Pyhcharm 터미널에서

$ conda activate [가상환경명]

을 입력하면 해당 가상환경으로 접속이 되면서 명령어 입력창 앞쪽에 (opencv)라고 뜬 것을 확인할 수 있다.

 

여기서 다시 pip을 입력하면?

pip list는 현재 가상환경에 깔려있는 패키지 정보를 출력하는 명령어이다.

오류 없이 pip 명령어가 잘 출력되는 것을 확인할 수 있다.


참고로 이러한 환경변수를 설정하는 귀찮은 짓을 안하려면 처음 아나콘다를 설치할 때

All Users로 선택하면 알아서 PATH가 추가될 것이다..ㅎㅎ

pytube는 pip에 두가지 종류가 있다. pytube와 pytube3

 

만약 이 두가지를 같이 설치하게 될 경우 충돌이 발생한다.

 

따라서 하나만 설치해야 된다.

 

pytube

 

pytube3

사용 가능한 python 버전을 보면 pytube3의 경우 3.6/3.7/3.8에서 가능하다고 한다.

나는 python3.7을 사용하기 때문에 두 개 다 사용할 수 있겟지만 나중을 생각해서 조금더 버전이 높은 놈을 선택했다.

 

#-*- coding:utf-8 -*-
#Youtube download module is pytube3, pytube.
#pytube3 is available to python 3.6/7/8
#if you download both, happen to abort
from pytube import YouTube

yt = YouTube('http://youtube.com/watch?v=9bZkp7q19f0')

print(yt.streams.filter())

그러고 테스트를 해보니 성공적으로 수행 완료

 

내가 만났던 에러 : ImportError: cannot import name 'quote' from 'pytube.compat'

와... 이거 쳐봐도 진심 1도 안나오더라...ㅋㅋㅋ

 

이렇게 문제가 발생하였을 땐

$ pip uninstall pytube
$ pip uninstall pytube3
$ pip insatll pytube3

모두 지우고 다시 패키지를 설치하면 잘 동작한다.

+ Recent posts