USB Serial 통신관련 문의 드립니다.



  • 아두이노와 라즈파이 같의 통신을 처음 구상하다가
    아두이노 두개로 서로통신을 개발을 해서 그냥 아두이노 하나를 라즈베리 파이에 붙였습니다.

    그래서 aruduino IDE 설치도 하고 테스트도 했습니다.
    그런데 python으로 /dev/ttyUSB0 의 값을 읽으면 잘 읽어올때도 있고 끊어지거나 에러가 발생합니다. 어떨때는 아에 연결이 안됩니다.

    현상으로는 아두이노 ide로 시리얼창을 띄워서 모니터링 하는중이나 먼저 하게 되면 python 프로그램이 /dev/ttyUSB0에 값을 못읽어 오는듯 합니다.

    그리고 테스트로 3초에 한번씩 송신하면 수신하여 저장하는데 잘 돌아가다가 알수없는 에러를 뿌리고 죽어 버립니다.

    python 프로그램은 usb 값을 읽어서 db에 저장합니다.

    통신모듈을 바로 라즈파이에 연결하면 문제가 없을까요?

    라즈베리파이 3, 아두이노 우노, 통신은 cc1101 모듈 입니다.


  • Global Moderator

    @hodupi 안녕하세요 산딸기마을 이장 나무꾼 입니다.

    우선 몇 가지 답변 자체를 드리기에는 현실적 문제점이 있습니다.

    1. 사용하시는 Ti 사의 제품이 제게는 미보유 RF 모듈 입니다
    2. 코딩하신 Python 소스의 내용을 알 수가 없어 소스의 문제점 분석 불가 합니다
    3. 결과적으로 현장 테스트 없는 이론 및 가설적 답변만 가능 합니다

    위의 가장 큰 내용을 배제한 상태로 문제점 분석 을 진행 한다면,

    • 공급전원 불안정 → 데이터 전송 시, 문제 발생
    • USB 시리얼 설정 오류 문제

    정확한 원인 분석의 시작은

    • 일반 데이스 탑에서 이야기 하신 부분의 구조로 테스트 결과
    • 라즈베리파이를 연결 시에도 동일 현상이 발생 여부

    가 질문자 님의 상황에 대한 검증의 시작 점으로 잡으셔야 하실 듯 합니다.

    그럼 수고하세요 ~



  • @Jae-Sang-Lee 안녕하세요. 빠른 답변 감사합니다.

    소스는 제가 바로 올릴수 없는 상황이라 있다가 올리 겠습니다.

    라즈베리 파이에서 arduino ide로 개발을 해서 시리얼모니터링을 하면 데이터가 잘 들어 옵니다.
    현재 라즈베리 파이에 물린 아두이노는 수신역할만 하고 있습니다.
    송신은 PC usb 와 12v 전원 연결을 하여 전원 문제는 아닌듯 합니다.
    수신측은 전압 약할수도 있을것 같습니다.

    추측하건데 IDE로 모니터링 중에는 python 프로그램으로는 usb 데이터를 읽지를 못하는것 같습니다.
    그리고 ide가 선점을 하고 있는지 ide를 종료해도python에서 usb serial을 초기화 하지 못하는 에러가 발생합니다.

    stty -F /dev/ttyUSB0 로 확인하면 speed 도 9600 baud로 동일하고 수신도 되고 데이터 파싱해서 DB에도 들어 갑니다. 그런데 항상 똑 같이 동작하는게 아니며 중간에 익셉션이 떨어지며 죽어 버립니다.

    제가 잘 몰라서요… 궁금한게 usb로 데이터가 전송되면 /dev/ttyUSB0 에서 cat을 하거나 tail로 보면 아무것도 안나옵니다. 그리고 3초에 한번씩 전송하게 했는데… 접속하면 한꺼번에 데이터가 쏟아지기도 합니다.
    /dev/ttyUSB0에 버퍼같이 데이터가 쌓이는것 같은데…
    어떻케 동작하는건지 설명이 없네요.
    만약 버퍼링 된다면 처음 python 프로그램 시작할때 ttyUSB0를 초기화 할수 있는지 궁금 합니다.



  • 수신측 python 소스 올립니다.

    import time
    import pymysql
    import serial
    import os
    
    rpiCOM = "/dev/ttyUSB0"
    #rpiCOM = "/dev/ttyAMA0"
    baud = 9600
    
    #ser.flushInput()
    while True:
            try:
                    print 'Opening port'
                    ser = serial.Serial(rpiCOM, baud)
                    ser.bytesize = serial.EIGHTBITS #number of bits per bytes
                    ser.parity = serial.PARITY_NONE #set parity check: no parity
                    ser.stopbits = serial.STOPBITS_ONE #number of stop bits
                    ser.timeout = 1
                    ser.xonxoff = False     #disable software flow control
                    ser.rtscts = False     #disable hardware (RTS/CTS) flow control
                    #ser.dsrdtr = False       #disable hardware (DSR/DTR) flow control
                    #ser.writeTimeout = 0     #timeout for write
                    print 'Port OPEN'
                    break
            except serial.SerialException:
                    print 'COM port ' + rpiCOM + ' not avaliable. Wait...'
                    time.sleep(3)
    
    while True:
            try:
                    print 'Opening DB'
                    db = pymysql.connect(host='127.0.0.1', user='root', password='xxxx', db='hodupi')
                    curs = db.cursor()
                    print 'DB OPEN'
                    break
            except:
                    ser.close()
    
    while True:
            try:
                    print 'Ready to check inbuff: '
                    while 1:
                            inbuff = ser.inWaiting()
                            print inbuff
                            if inbuff > 0:
                                    input_s = ser.readline()
                                    print input_s
                                    if input_s == 'Rx Init.....OK' or input_s == '':
                                            continue
                                    else:
                                            print 'test OK'
                                            input_p = input_s.split(",")
                                            if input_p[0] > 0:
                                                    try:
                                                            sql = "INSERT INTO HF_FARM_STAT_LOG(soil_moisture,lux,temperature,water_level,relay1,relay2,moto                                                    r1,motor2,log_dt) VALUES (" + input_p[0] + "," + input_p[1] + "," + input_p[2] + "," + input_p[3] + "," + input_p[4] + "," + input_p[5] + ",'" + input_p                                                    [6] + "','" + input_p[7] + "', now())"
                                                            curs.execute(sql)
                                                            db.commit()
                                                            print "sql : " + sql
                                                    except:
                                                            db.rollback()
                                                            ser.close()
                            else:
                                    print 'Waiting...'
                                    time.sleep(2)
                    break
            except serial.serialutil.SerialException:
                    print "Serial Exception raised"
                    pass
    

  • Global Moderator

    @hodupi 안녕하세요 산딸기마을 이장 나무꾼 입니다.

    우선 이야기하신 부분을 토대로 산딸기마을 소프트웨어 개발을 지원 해주는 멤버에게 확인을 해보니, 이야기 하신것 처럼, 다른 디바이스와 통신 시에 데이터를 읽어오지 못하는 것은 현상(다른거랑 통신하면서 모니터링 안됨)은 정상 이라고 합니다.

    두번째 고민 하실 내용은 아래와 같이 조언을 들었습니다.

    1. 통신 시에 끊어지는 현상
    2. 통신이 끊어졌을 경우에 누락 데이터 처리 방안

    2번의 경우에 저희가 부득이하게
    모청의 프로젝트에 조언 및 개발 참여 시에 사용했던 방법인 서버 자체에 로그를 기본적으로 쌓아두고 통신이 재 활성화 되면 추가 전달을 하는 방법을 사용하시면 해결이 되지 않을까 합니다.

    1항은 아무래도 개인적으로 전원부족현상 이 의심이 갑니다.

    상황이 되신다면, 구형파이 중 raspberrypi 2b를 이용해 동일 상황에 대한 추가 검증이 필요 해 보입니다.



  • @Jae-Sang-Lee 안녕하세요. 설명 감사합니다.

    어제 데이터 찍어보며 디버깅을 했는데 이상한 값들이 넘어 오는게 있어서 수정했더니 잘 동작을 합니다.
    로그 저장은 송신측의 장비가 아두이노라 저장매체를 따로 하기가 좀 불편 합니다.
    그리고 아주 중요한 정보가 아니라서 ^^ 차후에 고려해 보겠습니다.
    구형 파이가 없어서 당장은 테스트가 어려울것 같습니다.

    한가지 어제 해결하지 못한부분이 있는데요.
    가끔 노이즈 때문인지 쓰레기 값들이 송신이 됩니다.
    체크비트를 넣은게 아니라서 그냥 데이터가 숫자인지 만 판단을 하는데 sNumber(), isNumeric() 인가를 써도 잘 안되네요.
    그래서 그냥 >=0크기 비교를 했는데 쓰레기 값이 8진수로 넘어오는것 같습니다.
    혹시 값을 검증하는 좋은 팁이 있을지요?

    290,93,12.32,1,0,00,00 같이 , 로 구분해서 형태로 데이터를 받습니다.


  • Global Moderator

    @hodupi 안녕하세요. 데이타를 보낼때 데이터만 보내지 마시고 앞에 다른 코드를 삽입하는 방법이 있습니다. 예를 들어 송신쪽(아두이노?)에서 31을 보내고자 할때, 간단히는 2바이트에 32를 실어보내면 되지만, 그 앞에 2바이트에 1000을 실어서 보냅니다. 받는쪽에서는 4바이트를 받고 앞에 2바이트에 1000이 없으면 쓰레기처리를 하면됩니다. 필요한데로 더 많은 데이타를 보내면 됩니다.



  • @Seungrok-Han 안녕하세요.
    그방법도 좋은 팁일것 같네요. 감사합니다.
    한번에 보낼수 있는 데이터의 길이가 있는지 궁금 합니다. 원래는 데이터를 JSON형태로 만들어서 보내려고 했었는데 길이가 기니까 짤려서 가더라구요. 그리고 데이터가 큐형태같이 나오던데… 그래서 포기하고 가능한 짧게 하려고 한 방법 입니다.

    그리고 usb에 데이터가 입력되면 flush 가 안되고 쌓이는것 처럼 보입니다.
    즉 송신측에서 계속 데이터를 보내고 수신측에서 읽지않으면 데이터를 버리지 않는것 처럼 보이는데 맞는지요?


  • Global Moderator

    @hodupi 데이터가 쌓이는것에 대해서는 제가 정확히 모르겠습니다. 근데 쌓이는게 맞는것 같기는 합니다. 그래서 Flush를 잘 해줘야 되죠.

    Serial이 그리 긴 데이타를 받지는 못할겁니다. 데이타가 길다면 쪼개서 보내는 방법도 생각해보세요.

    A.Startbit = 1000
    A.IDX = 1
    A.Colum1 = 1
    A.Data1 = 29
    A.Colum2 = 2
    A.Data2 = 23
    A.Endbit = 00FF
    
    A.Startbit = 1000
    A.IDX = 2
    A.Colum1 = 3
    A.Data1 = 45
    A.Colum2 = 4
    A.Data2 = 78
    A.Endbit = 00FF
    

    여러가지 방법이 있겠습니다만…
    시리얼이 좀 짜증나고 어려운면이 있습니다. 저도 잘 안해봐서…^^


답변을 위해 로그인하기