2022년 12월 25일 일요일

파라메트릭 모델링 지원 Revit Dynamo 개발 역사, 사용법 및 JSON에서 Revit BIM 객체 생성 파이썬 코딩하기

이 글은 파라메트릭 모델링을 지원하는 Revit Dynamo 개발역사, 사용법을 간략히 설명한다. 그리고, JSON에 저장된 객체정보로 부터 Revit BIM(Building Information Modeling) 객체를 자동생성하는 다이나모 파이썬 스크립트를 간단히 개발해본다. 이를 통해, 다이나모 장단점을 이해하고, 다음과 같은 사용법을 이해할 수 있다. 
  • 플로우 프로그래밍 방법
  • 다이나모 API와 패키지
  • 다이나모 파이썬 프로그래밍 및 디버깅 방법
  • 다이나모에서 JSON 파일 사용 방법
Revit Dynamo 기본 개념
래빗 다이나모는 3차원 파라메트릭 디자인에서 영역을 키워가고 있는 라이노(Rhino)의 그래스호퍼(Grasshopper)에 대응하기 위해 개발된 비쥬얼 플로우(flow)기반 프로그래밍 도구이다. 오토데스크에서 이를 주도한 Matt Jezyk는 수치 계산에 기반한 BIM 개념(Computational BIM)으로 다이나모를 개발했다고 한다(2013년). 참고로, 그는 다이나모를 이전부터 오픈소스운동에 대한 신념으로 개발해왔다.

다이나모 github 사이트

처음 다이나모 릴리즈 시에는 많은 버그와 문제가 있었으나, 오토데스크의 지원과 개발로 지금은 많이 안정화되었고, 성능도 좋아졌다. 아직 그래스호퍼 많큼 품질 좋은 애드인이 부족하지만, 이 부분도 개선되고 있다.

참고로, 플로우 프로그래밍은 텍스트로 코딩하여 프로그램을 개발하는 방식이 아닌, 제공된 기능 도구에서 드래그&드롭 식으로 캔버스에 배치해, 각각의 기능 실행 순서를 그래프로 연결해 프로그램을 개발하는 방식이다. 

플로우 프로그래밍 예시

이 방식의 장점은 특정 프로그래밍 언어를 잘 몰라도, 쉽게 프로그램 개발이 가능하다는 점이다. 다만, 텍스트에서 20줄 정도 소스코드가 플로우 프로그래밍 캔버스에서는 너무 복잡하게 보여진다는 점과 유지관리가 어렵다는 점이다. 아울러, 최신 라이브러리, 디버깅 도구 등 사용에 제한이 있다.

사용법
래빗과 래빗 컨텐츠를 설치한다. 이때, 다이나모도 같이 설치된다. 다음 리본 메뉴를 실행하면, 다이나모가 실행된다. 
다이나모 실행 버튼
다이나모 윈도우

다이나모 New 버튼을 클릭하면, 다이나모 프로그램이 다음과 같이 보여진다. 
다이나모 프로그램 UI

UI는 상단 메뉴, 왼쪽 도구 및 애드인 패널, 중간 빈 캔버스, 왼쪽 하단 플로우 프로그램 실행 모드(자동 및 수동), 우측 상단 모드 선택 메뉴 등으로 구성된다. 

라이노 그래스호퍼처럼, 실행 결과가 엔티티 객체로 렌더링 및 생성되므로, 이를 확인할 수 있는 모드가 필요하다. 이를 위해, 다이나모 캔버스는 모델 모드, 플로우 프로그래밍 모드의 두 가지가 있고, 캔버스의 우측 상단 메뉴를 통해 스위치할 수 있다.
모드 전환 스위치 메뉴

프로그래밍 방법은 매우 간단하다. 왼쪽 도구 메뉴에서 필요한 도구를 선택하고, 클릭하면, 캔버스에 자동으로 도구가 노드로 배치된다. 캔버스에서 컨텍스트 메뉴를 호출해 배치하기 원하는 기능 노드를 선택할 수도 있다. 다음과 같이 원하는 노드들을 배치한 후, 각 노드의 입출력 포트를 연결해 와이어링(wiring)해 주면 된다. 이후, 좌측 아래실행 버튼을 클릭해, 엔티티 객체 등을 생성하면 된다. 
두개 시점, 종점 좌표들을 생성해 선들을 생성하는 프로그램 예시

다이나모는 그래스호퍼처럼 플로우 프로그래밍 가능하도록, C++와 같은 프로그래밍 언어의 제어문, 수치 계산, 파일 입출력 등을 기본 제공한다. Revit API가 도구화되어 있어, 계산된 데이터에 의한 파라메트릭한 BIM 객체 생성 기능을 제공한다. 또한, 개발자가 외부에서 작성한 애드인 도구들을 추가해 사용할 수 있다. 좀 더 상세한 사용법은 다음을 참고한다.

플로우 프로그래밍 한계점
앞서 언급한 바와 같이, 노드와 노드의 입출력 포트를 연결해 프로그래밍하는 방식은 접근하기 쉬우나, 프로그램 구조가 조금만 복잡해지면, 유지보수하기 어려울만큼 노드 그래프의 구조를 알아보기 어려워진다. 
노드 기반 플로우 프로그래밍 Hell 

이외에, 이 상태에서 에러가 발생하면, 디버깅이 거의 불가능하다는 것도 큰 문제다. 발전하는 최신 기술과 라이브러리를 사용하지 못하는 것은 덤이다. 

이런 문제를 다이나모의 파이썬 스크립트 노드를 이용해 일부 해결할 수 있다. 

다이나모 파이썬 기반 JSON에서 Revit BIM 객체 자동 생성
앞에 언급된 문제를 피해, 기본적인 부분만 플로우 프로그래밍하고, 나머지 복잡한 부분은 파이썬으로 코딩해 본다. 

이 예시는 JSON 입력 파일로 부터, 데이터를 읽어, 이를 Revit BIM 객체로 생성하는 방법을 간단히 보여준다. 알고리즘은 다음과 같다. 
  1. BIM 객체 생성할 Revit Family 및 Level 선택
  2. input.json 파일 읽기
  3. 파일에서 생성할 객체 정보 획득
  4. 객체를 패밀리로 부터 생성하고, 객체 리스트를 만듬
  5. 객체 리스트를 이용해, Revit BIM 객체 출력
input.json 파일은 다음과 같이 저장되어 있다고 가정한다. 
{
"objects": [
{
"data": "data_1",
"bbox": [[0, 0, 0], [100, 100, 100]] 
},
{
"data": "data_2",
"bbox": [[2000, 2000, 0], [2100, 2100, 100]] 
}
]
}

다음과 같이 Family Types, Levels, Python script, Element.Geometry, Watch 노드를 캔버스에 배치하고, 입출력 포트를 서로 연결한다. Python script 노드 이름을 목적에 맞게 create objects로 수정하고, '+' 버튼을 클릭해 IN 포트를 하나 더 추가한다.
JSON to BIM object 프로그래밍된 노드 그래프

Family Types노드와 Levels 입력 콤보박스를 적절히 선택한다. 그리고, Python script 노드의 '...' 메뉴에서 Edit 메뉴를 선택한다.
파이썬 스크립트 창

다음과 같이 파이썬 편집창에서 코딩한다. 
# Load the Python Standard and DesignScript Libraries
import sys, clr, math, os, json # 라이브러리 임포트
clr.AddReference('ProtoGeometry')
clr.AddReference('RevitNodes')
clr.AddReference("RevitAPIUI")
clr.AddReference('DynamoRevitDS')
clr.AddReference('RevitServices')

from Autodesk.DesignScript.Geometry import *
from Autodesk.Revit.UI import *
# from Autodesk.Revit.DB import * # error. not support
from Revit.Elements import *
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
from Autodesk.Revit.UI.Selection import *
from io import StringIO
import Dynamo 

# input
sys.stdout = StringIO()  # 디버깅 위해 표준출력을 StringIO로 설정
print('begin')

doc = DocumentManager.Instance.CurrentDBDocument  
uiapp = DocumentManager.Instance.CurrentUIApplication
TransactionManager.Instance.EnsureInTransaction(doc)  # 트랜잭션 구간 시작

ftype = IN[0]   # 노드 1번 입력. 패밀리 유형
level = IN[1]    # 노드 2번 입력. 레벨

# define functions
def create_objects(objects_json):   # 객체 생성 함수 정의. JSON 데이터 입력 받음
    input_objects = objects_json['objects']
    
    objs = []
    for input_obj in input_objects:   # JSON 내 각 객체 정보 획득
        data = input_obj['data']
        bbox = input_obj['bbox']
        pt1 = bbox[0]
        pt2 = bbox[1]

        pt = Point.ByCoordinates(pt1[0], pt1[1], pt1[2])
        # TaskDialog.Show("debug", str(pt)) 
        
        obj = FamilyInstance.ByPointAndLevel(ftype, pt, level)
        objs.append(obj)   # 패밀리에서 BIM 객체 생성
    return objs  # 리스트 리턴

# define variables
dyn = Dynamo.Applications.DynamoRevit()
cur_wspace = dyn.RevitDynamoModel.CurrentWorkspace
curpath = cur_wspace.FileName # os.getcwd()
path_fname = os.path.split(curpath)

# 현재 다이나모 소스 파일 저장된 폴더에 저장된 input.json 파일 읽기
fname = path_fname[0] + '\input.json'
objs = []
objects_json = {}
try:    # 디버깅하기 쉽게 exception 처리
    with open(fname, "r") as read_file:
        objects_json = json.load(read_file)  # JSON 파일 로딩
    objs = create_objects(objects_json)    # 객체 생성
except Exception as e:
    TaskDialog.Show("error", str(e))
        
# output 
OUT = objs  # 객체 리스트 리턴
    
TransactionManager.Instance.TransactionTaskDone()     # 트랜잭션 종료
print('end')

이를 실행하면, 다음과 같이, JSON 파일에서 BIM 객체들이 자동 생성된다. 이제 외부에 저장된 데이터에서 파라메트릭하게 객체들을 쉽게 생성할 수 있다.

디버깅을 위해, 예외처리가 되어 있어, 유지보수하기 편리하다. exception 발생하면, TaskDialog로 에러 메시지를 확인할 수 있도록 하였다.


마무리
이 글은 파라메트릭 모델링을 지원하는 Revit Dynamo의 개념 및 사용법을 설명한 후, JSON에서 Revit BIM 객체를 자동 생성하는 파이썬 스크립트를  코딩해 보았다. 

노드와 노드의 입출력 포트를 연결해 프로그래밍하는 방식은 접근하기 쉬우나, 프로그램 구조가 조금만 복잡해지면, 유지보수하기 어렵다. 복잡도가 높은 부분은 적절히 파이썬으로 구현하면, 이런 문제를 개선할 수 있다. 다만, 다이나모는 아직도 예제 등 많은 부분에서 문서화되어 있지 않고, 버그가 많으며(파이썬 스크립트 에러 발생 시 래빗 재부팅 문제, 도움말 복사 안됨, Revit과 다이나모 API 충돌 등), 디버깅에 한계가 있다. 
구글링 검색 잘 안되는 다이나모 API(예제가 부족해 도움말로 추측해 사용해야 한다-.-)

여러 문제에도 불구하고, 다이나모는 강력한 오토데스크 BIM 개발도구 지원아래 오픈소스 프로젝트로부터 시작되어 많은 개발자들의 공헌으로 지금까지 꾸준히 개발되고 있다. 이런 점은 쓸만한 오픈소스가 많지 않은 국내 엔지니어링 산업계에 비해 많은 점을 느끼게 한다.

레퍼런스

2022년 12월 18일 일요일

드론 자율비행제어 지원 플랫폼 픽스호크(PX4) 소개, 역사 및 사용방법

이 글은 드론 자율비행제어 시 자주 사용되는 오픈소스 플랫폼인 픽스호크(PX4)에 대한 소개, 개발역사 및 사용 방법에 대해 간략히 정리한다. 

픽스호크는 무선 통신 장치인 Telemetry가 연결된 그라운드 스테이션(ground station. 보통 노트북)에 설치된 오픈소스인 미션플래너와 데이터 통신을 할 수 있다. 미션플래너 지도 상에 사용자가 입력한 경로(waypoint)를 무선으로 픽스호크에 전송하고, 픽스호크는 드론이 자율비행할 수 있도록, 모터 등 액추에이터를 제어한다. 이때, 드론에 연결된 센서로 부터 얻은 데이터는 미션플래너에서 모니터링할 수 있다. ROS(Robot Operating System)와 PX4-ROS Bridge를 통해, 통신할 수 있어, 상호 데이터를 교환하거나, ROS에서 처리된 정보를 비행에 활용할 수 있다.
PX4 기반 자율비행시스템 개발 사례(Autonomous flight mission in ROS using MavROS + PX4 + Gazebo)

참고로, 미션 플래너 및 송수신기 관련 내용은 아래 링크를 참고하길 바란다.

Pixhawk PX4 소개
2008년. 픽스호크는 Lorenz Meier 가 2008년 개발한 오픈소스 자율비행 지원 도구이다. ETH Zurich 석사 연구 프로젝트로 진행, 주변 14명 팀원 모아 개발되었다. 이후 개발 역사는 다음과 같다.
  • 2009년. 9개월동안 개발. 실내 드론 비행 관련 유럽 초소형 항공기 대회 우승. 팀 이름이 픽스호크였음. 오픈소스로 릴리즈함. 개발된 통신 프로토콜 MAVLink는 산업계 표준이 됨. 
  • 2011년. 이전까지 개발된 소스코드 폐기후 재개발. 이 결과로 PX4가 개발됨. 드론 제조업체인 3D Robotics와 협업해 하드웨어 구축 및 판매 시작. ArduPilot과 협력해 호환성 추가. 하드웨어 설계 문서는 github에 공개함. QGroundControl 미션 플래너 개발. 
  • 기능 추가 후 전체 코드 자동 테스트 수행됨. 매월 평균 1,000회 테스트 비행 거침. 
  • 2014년. Dronecode 설립. 개방형 기술 표준 추진. 오픈소스 커뮤니티 9,600 명 이상 사용자 및 600명 이상 기여 개발자로 성장. 
  • 2019년. 개발 코드가 150만줄로 성장.
  • 2020년. Skynode 통해 LTE 클라우드 연결 지원. 무선 업데이트 지원. 
PX4와 주변 장치 연결 방법
장치 연결 레이아웃은 다음과 같디(참고 - Pixhawk Wiring Quick Start). 

픽스호크 연결 개요도
  • (필수) 3DR GPS+컴파스와 연결. 이는 현재 위치 데이터를 제공해 줌. GPS 6-wire 포트와 I2C 2-wire (MAG 센서. 고도)에 연결. 
  • (필수) 3DR 파워 모듈과 6-wire 포트에 연결. 파워 모듈은 LiPo 배터리와 직접 연결됨. 
  • (필수) 에러 및 상태 표시 부저 연결. 안전 스위치 연결
  • (필수) 통신 수신기 연결은 RC IN 핀과 연결함.
  • (옵션) 3DR Radio 키트와 픽스호크 6-wire 포트를 연결. 데이터 통신 담당.
  • I2C 인터페이스 splitter 로 4개 추가 병렬 연결 포트 사용 가능. 이 포트를 통해, 외부 상태 LED, 컴파스 센서, 디지털 air speed 센서 및 다른 센서들을 연결할 수 있음
픽스호크는 파워포트로 부터 전원이 공급된다. 적절 동작 전원 공급 여부는 자동 체크해 LED로 표시된다.
전원 연결 및 표시등

주의사항으로 서보모터 등을 픽스호크의 PWM 출력에 직접 연결하지 말라. RCIN 포트는 저전력 장치만을 위해 디자인되어 있다. 서버 및 릴레이는 PX4로 부터 많은 전류를 가져간다. 만약, PX4의 RCIN에 전원 인가되어 있는 중, 서버모터를 직접 포트에 연결할 경우, PX4가 고장날 수도 있다.

연결 장치 호환성은 다음과 같다.
  1. PPM-Sum receivers
  2. SBUS receivers
  3. IBUS receivers
  4. FPort receivers
  5. Spektrum DSM, DSM2, DSM-X 위성 수신기
  6. SRXL 버전1, 2 수신기
  7. Graupner SUM-D 
Single wire per channel (PWM) 지원을 위해, PPM 인코더는 수신기 출력을 PPM-SUM 으로 변환할 수 있음 (참고 - Radio Control Systems).
FRSky 송신기 제품 예 및 3DR GPS + Compass 모듈

모터 연결은 다음과 같다. 
이는 다음과 같이 모터 신호선과 각 채널을 연결한 것이다.
Pin 1 = Motor 1 - - Pin 5 = Motor 5, Pin 2 = Motor 2 - - Pin 6 = Motor 6
Pin 3 = Motor 3 - - Pin 7 = Motor 7, Pin 4 = Motor 4 - - Pin 8 = Motor 8

상세 내용은 Connect ESCs and Motors 문서를 참고하라.
다음은 다양한 장치를 연결한 예시이다(참고 - Advanced Pixhawk Quadcopter Wiring Chart).

픽스호크 연결 예시(참고)

픽스호크는 제공 전압 등 적절한 스펙 범위내에서 동작한다. 
다음과 같은 기타 장치 연결은 Optional Hardware 문서를 참고하라.
  • Airspeed Sensor
  • AIS (Automatic Identification System)
  • Barometer (external)
  • Button Inputs
  • Buzzer
  • Cameras & Gimbals
  • Companion Computers
  • Display (Onboard)
  • ESCs and Motors
  • DroneCAN Adapter Node
  • DroneCAN Peripherals
  • First Person View Video
  • Grippers
  • Joystick or Gamepad
  • LEDs (external)
  • PPM Encoder
  • Radio Control Systems
  • Received Signal Strength Indication (RSSI)
  • Relay Switch
  • Servos
  • Smart Batteries
  • Telemetry Radio
  • Video (High Definition)
  • Winch
모터 장비 연결 예시 (좌상 - 참고, 우상 - 참고, 좌하 - 참고, 좌우 - 참고)

CANbus 연결
CAN(Controller Area Network)는 신뢰성있는 유선 네트웍으로 ESC(Electronic speed controllers), 센서, 기타 장치들과 다른 장치들 간의 통신을 가능하게 한다. 서로 다른 신호 체계를 이용해 수평적 통신이 가능하도록 설계되어, 긴 케이블 길이를 가진 네트웍에서도 신뢰성있는 통신이 가능하다. 이를 통해, 통신 실패 가능성을 없앤다. CAN는 상태 피드백을 장치로 부터 전달받고, 펌웨어 업데이트를 지원한다. 

PX4는 두가지 종류의 CAN 통신 프로토콜을 지원한다. 이 두 프로토콜 모두 오래전에는 UAVCAN(참고)으로 불렸다. PX4는 다른 KDECAN과 같은 CAN 프로토콜은 지원하지 않는다.
  • DroneCAN(UAVCAN v0): PX4는 가장 기본적인 셋업으로 이를 권장한다. 많은 테스트로 신뢰성있게 동작한다(참고 - 소스코드).
  • Cyphal(UAVCAN v1): PX4는 현재 개발 진행 중인 이 프로토콜을 지원한다. 유연성있고 복잡한 vehicle 장치 제어를 지원한다. 
CAN네트워크 연결 예시는 다음과 같다. 4개의 CAN ESC와 GNSS가 연결되어 있고, 각 ESC는 모터를 제어하도록 연결되어 있다.
  
CAN 체인 연결 예시와 CAN 체인 termination resistor
PX4와 실제 CANbus 연결 사례(DroneCAN ESCs)

각 장치들은 체인으로 연결된다. 그래서 확장성이 높다. 체인의 말단은 120옴 termination resistor(참고)로 두 선이 연결되어 있어야 한다. 비행 컨트롤러와 몇몇 GNSS 모듈은 편리하게도 자체에 termination resistor가 내장되어 있다. 

앞의 다이어그램에는 전원 연결이 표시되어 있지는 않다. 각 장치 제조사에는 CAN 버스 자체로 부터 전원이 공급되거나 각 장치별 개별 전원이 공급되도록 가이드 문서를 줄 것이다. 
  • Connectors: 픽스호크는 4 핀 JST-GH 연결 포트와 호환된다. 두 컨넥터들은 입력과 출력으로 사용되어 체인을 연결할 때 사용된다. 픽스호크는 두개 CAN 인터페이스 연결을 지원한다.
  • Firmware: CAN 은 오픈소스 펌웨어로 실행된다. PX4는 DroneCAN 펌웨어 오픈소스로 동작된다(참고).
연결 시 PX4에서는 연결 방법에 대한 영상(Intro to UAVCAN and Practical Example)등을 제공하므로 참고한다.

DroneCAN 설정 및 연결 상세는 다음을 참고한다.
참고로, ArduPilot은 브러쉬 모터 ESC의 RC PWM (신호는 1ms에서 2ms 폭을 가짐) 입력을 지원한다. 대부분 hobby 등급 RC Car ESC는 이 유형이다. 브러쉬 모터는 duty cycle 동안 스피드를 제어하게 된다. 다음은 검증된 모터 드라이버들이다. 
  • Sabertooth Dual 32A Motor Driver supports “Normal” when the Sabertooth is in RC Mode
  • Pololu G2 High-Power Motor Driver supports “BrushedWithRelay”
  • Pololu DRV8838 Motor Driver supports “BrushedWithRelay”
  • RoboClaw 2x7A Motor Controller supports “Normal” when the Roboclaw is in RC Mode
  • L298N Motor Driver. See also these setup instructions
  • SkyRocket drones use “Brushed” motors
UAVCAN 사용 사례
CANbus는 유선 인터넷과 비슷한 방식으로 동작한다. CANBus는 4선 케이블과 연결되어, 데이지 체인 방식으로 처리된다. 캔버스와 연결되는 장치는 다른 캔버스 연결 장치와 통신 방법(프로토콜)이 펌웨어로 내장되어 있어야 한다. 캔버스는 보쉬 기업에 의해 자동차용으로 설계되었다. 
캔버스 네트웍 기반 자동차 장치 통신 및 캔버스 허브
캔버스 적용된 드론 개발 사례(참고 - CANbus for Ardupilot with UAVCAN and UC4H)

PX4기반 로버(rover) 개발 사례
로버는 PX4, ardupilot을 이용해 자동 가이드 기능을 실행할 수 있다. 사전 정의된 경로를 통해, 완전 자율 주행이 가능하다. 다음 로버 플랫폼은 2013, 2014년 Sparkfun 자율 주행 대회(2018년 대회까지 기록)에서 우승한 것이다 (비디오 데모).

PX4, ardupilot 기반 2013년 대회 출전 로버(좌), 자율 주행 트랙터 및 차(우)

다음은 PX4를 이용해 RC 카를 개발한 예이다(참고 - Motor and Servo Connections).
RC 카 개발 예

마무리
픽스호크를 사용하면, 미션플래너 지도 상에 사용자가 입력한 경로를 따라 드론과 같은 로보틱스 플랫폼이 자율비행/이동 할 수 있다. 또한, PX4 ROS Bridge를 이용하면, ROS와 연동해 좀 더 지능적인 자율비행을 지원할 수 있다. 픽스호크는 파트너 기업이 많아, 호환되는 센서나 장비 연결이 손쉽다. 다만, 오픈소스 특성상 목적에 맞는 기기 개발 시 부족한 스펙 및 기능은 직접 개발하거나 커스텀해서 사용해야 한다.
PX4 ROS Bridge 개요도

레퍼런스

2022년 12월 16일 금요일

파이썬 기반 멀티플랫폼 GUI 개발 라이브러리 wxPython 소개 및 사용하기

이 글은 유명한 파이썬 기반 크로스 플랫폼 GUI(Graphic User Interface) 개발 라이브러리 wxPython인 소개 및 사용방법을 간단히 설명한다.


소개
wxPython은 파이썬 프로그래밍용 크로스 플랫폼 GUI 라이브러리로, 동일한 코드로 윈도우, 맥북, 리눅스 등 다양한 플랫폼에 개발 코드와 디자인된 GUI를 그대로 재사용할 수 있다. wxPython은 Tkinter, Qt와 같은 GUI 디자인 API를 제공하지만, 사용방법이 쉽고, 편리한 레이아웃 기능등을 제공한다. 

wxPython은 Robin Dunn가 1995년 당시 개발되고 있던 wxWidgets 툴킷을 파이썬으로 랩핑하고, 편리하게 사용할 수 있도로 개선한 것이 개발의 시작이다. 참고로, wxWidgets은 에든버러 대학의 Julian Smart박사가 1992년 wxWindows란 이름으로 시작된 C++기반 GUI 오픈소스 프로젝트이다. 

wxWindows 로고와 Julian Smart 박사(참고)

wxPython은 2010년 피닉스 프로젝트가 시작되어, 파이썬 3과 호환되도록 하였고, 속도와 호환성을 개선했다. Robin Dunn은 2002년 프로그래머 초이스 어워드를 수상했으며, 2022년 6월 wxPython 4.x이 개발되고 있다. 
소프트웨어 엔지니어 Robin Dunn(참고)

시작
가장 단순한 예제는 다음과 같다.
import wx

app = wx.App()

frame = wx.Frame(None, title='Simple application')
frame.Show()

app.MainLoop()


여기서, 프레임위젯은 타이틀바, 경계, 위젯 컨테이너를 포함하는 윈도우이다. 
프레임 생성 옵션은 다음과 같이 추가할 수 있다.
wx.Frame(wx.Window parent, int id=-1, string title='', wx.Point pos=wx.DefaultPosition, size=(300, 200), style=wx.DEFAULT_FRAME_STYLE, string name="frame")

다음과 같이 툴바를 추가할 수 있다.
import wx

class Example(wx.Frame):
    def __init__(self, *args, **kwargs):
        super(Example, self).__init__(*args, **kwargs)
        self.InitUI()

    def InitUI(self):
        vbox = wx.BoxSizer(wx.VERTICAL)

        toolbar1 = wx.ToolBar(self)
        toolbar1.AddTool(wx.ID_ANY, '', wx.Bitmap('tnew.png'))
        toolbar1.AddTool(wx.ID_ANY, '', wx.Bitmap('topen.png'))
        toolbar1.AddTool(wx.ID_ANY, '', wx.Bitmap('tsave.png'))
        toolbar1.Realize()

        toolbar2 = wx.ToolBar(self)
        qtool = toolbar2.AddTool(wx.ID_EXIT, '', wx.Bitmap('texit.png'))
        toolbar2.Realize()

        vbox.Add(toolbar1, 0, wx.EXPAND)
        vbox.Add(toolbar2, 0, wx.EXPAND)

        self.Bind(wx.EVT_TOOL, self.OnQuit, qtool)

        self.SetSizer(vbox)

        self.SetSize((350, 250))
        self.SetTitle('Toolbars')
        self.Centre()

    def OnQuit(self, e):
        self.Close()

def main():
    app = wx.App()
    ex = Example(None)
    ex.Show()
    app.MainLoop()

if __name__ == '__main__':
    main()

Sizer 사용해 레이아웃 디자인하기
사이저를 이용하면 손쉽게 레이아웃을 디자인할 수 있다. 다양한 위젯을 행이나 열로 추가하여, 프레임크기에 따라 포함된 위젯들의 상대적 위치 크기를 자동으로 배치한다.

다음은 BoxSizer 예시이다.
box = wx.BoxSizer(integer orient)
box.Add(wx.Window window, integer proportion=0, integer flag = 0, integer border = 0)

여기서 orient 방향은 wx.VERTICAL, wx.HORIZONTAL이 된다. 파라메터에서 proportion은 정의된 방향에 상대적으로 변화되는 위젯의 화며 크기 비율이다. 만약, 3개 위젯이 0, 1, 2로 proportion 값이 설정되어 있다면, 0번 위젯은 크기가 변하지 않고, 2번 위젯은 1번 위젯에 비해 2배 크기로 변경된다. 

flag는 위젯의 행위를 설정한다. 만약, 위젯 사이 공간을 추가하고 싶다면, 다음과 같은 옵션을 주면 된다. 

wx.LEFT, wx.RIGHT, wx.BOTTOM, wx.TOP, wx.ALL

다음은 사이저를 사용한 프레임 윈도우 생성 예시이다. 
import wx

class Example(wx.Frame):
    def __init__(self, parent, title):
        super(Example, self).__init__(parent, title=title)

        self.InitUI()
        self.Centre()

    def InitUI(self):
        panel = wx.Panel(self)

        panel.SetBackgroundColour('#4f5049')
        vbox = wx.BoxSizer(wx.VERTICAL)

        midPan = wx.Panel(panel)
        midPan.SetBackgroundColour('#ededed')

        vbox.Add(midPan, wx.ID_ANY, wx.EXPAND | wx.ALL, 20)
        panel.SetSizer(vbox)

def main():
    app = wx.App()
    ex = Example(None, title='Border')
    ex.Show()
    app.MainLoop()

if __name__ == '__main__':
    main()

여기서, 다음과 같이, wx.ALL 사용하면, 모든 방향의 경계에 퍼버를 20픽셀로 정의하고, wx.EXPAND 로 모든 위젯에 버퍼를 할당하게 된다. 
        vbox.Add(midPan, wx.ID_ANY, wx.EXPAND | wx.ALL, 20)

마무리 
wxPython 을 간단히 소개하고, 사용 방법을 간단히 알아보았다. 오픈소스로 개발된 지 거의 30년이 되어가는 데도, 꾸준히 유지보수되고 있는 프로젝트이다. 이 프로젝트는 파이썬에서 GUI를 개발할 때 거의 필수적으로 사용되는 라이브러리 중 하니이다. 역사를 살펴보면, 개발자의 사회적 공헌이 얼마나 좋은 영향을 미치는지는 느낄 수 있다. 한국에도 이런 문화가 정착되었을 때, IT선진국이라 할 수 있지 않을까 싶다. 

레퍼런스

추신. 유타 브리검 영 대학
라이브러리 개발자가 졸업한 유타주의 브레임영 대학은 미국에서 가장 큰 종교대학이다. 학생 98% 이상이 몰몬교도이다. 학교는 다른 미국 대학교에 비해 그리 크지 않은 편이지만, 컴퓨터 공학 등 이공대 경쟁력이 높은 곳 중 하나이다. 유타 종교 대학 특징 상 졸업생들은 올바른 종교 사회인으로써 역할에 충실한 편이며, 이로 인해, 많은 기업들이 이 대학교 졸업생을 선호한다고 한다. 

2022년 12월 12일 월요일

ChatGPT 인공지능 기반 자동 프로그래밍 사용기, 장점과 단점

최근, 핫한 ChatGPT 를 이용한 인공지능 기반 자동 프로그래밍 사용기, 그리고 GPT 장점과 단점을 정리해 공유한다.

일부 언론에서는 ChatGPT를 이용해, 인공지능이 자동으로 소프트웨어 개발을 할 수 있는 것처럼 이야기하는 데(기사 참고 - 오픈AI가 선보인 '챗GPT'에 IT업계 '들썩'..."대화 넘어 코딩·원고 작성까지, 사실은 현실과는 거리가 있다.

ChatGPT 테스트
실제 몇 가지 테스트를 해보면, 잘 알려진 특정 분야(코드 개발 패턴이 정형화되어 있는 알고리즘. 후술)에 한에 쓸만한 코드를 만들어 낸다. 

ChatGPT를 이용해, BIM(Building Information Modeling)에서 주로 많이 사용되는 IfcOpenShell 을 이용해 특정 속성을 검색하는 코드를 생성해 보겠다. 

ChatGPT 사용 순서는 다음과 같다. 
1. https://chat.openai.com/chat 에 로그인, 접속한다.
2. 다음 문장을 프롬프트에 입력한다.
load BIM.ifc using IfcOpenShell and return the element which project name is 'DDP' in python
3. ChatGPT가 학습된 소스코드를 바탕으로 유사한 패턴의 코드가 다음과 같이 생성한다. 
import ifcopenshell

# open the IFC file
ifc_file = ifcopenshell.open("BIM.ifc")

# access the building elements in the IFC file
building_elements = ifc_file.by_type("IfcBuildingElement")

# iterate over the building elements
for element in building_elements:
    # access the properties of each element
    properties = element.IsDefinedBy
    for property in properties:
        # check if the property name is "Project" and the property value is "DDP"
        if property.Name == "Project" and property.Value == "DDP":
            # return the element if the condition is met
            print(element)
            break

4. 이 코드를 직접 입력해 실행해본다. 결과는 다음과 같다. 실제로는 사용되는 API등 이 정확하지 않아, 제대로 실행되지 않는 것을 확인할 수 있다. 
ChatGPT 코드 실행

생성된 코드를 보면, for, if 문과 같이 제어문장 패턴들은 코드가 잘 생성되는 것을 알 수 있다. 몇몇 알려진 API(예. open() 함수)등도 잘 사용한다. 다만, property API는 학습 데이터가 별로 없었는지 제대로 코딩되지 않았다. 보다시피 방어적 프로그래밍은 되어 있지 않다. 유지보수성, 재활용성을 고려한 모듈화 등은 고려되지 않는 듯 보인다. 전체적으로 좀 냉정하게 보면, stack overflow 검색 구글링 시간을 줄여준 느낌이다.


GPT 장점과 단점
당연히 ChatGPT를 이용한다고, 소프트웨어가 저절로 개발되지 않는다. 다음과 같은 경우, ChatGPT는 개발에 어느정도 도움이 될 수 있다.

G1. 결과를 보면 알겠지만, for, if 와 같은 시퀀스 처리 패턴 구조는 잘 만들어 낸다. 그러므로, 특정 알고리즘(sort, search 등)과 관련된 구조는 재활용할 수 있다. 

G2. 코딩을 전혀 모르는 경우, 대략 전체적인 워크플로우를 특정 언어로 코딩해 낸다. 이는 개발 시 다양한 전문가가 모여 서비스 기능을 디자인할 때 유용할 수 있다. 예를 들어, 개발자와 디자이너가 커뮤니케이션할 때 사용할 수 있다. 

G3. 개발자가 라이브러리 기본 사용법을 잘 모르는 경우, 기본 뼈대 코드를 얻을 수 있다. Stack overflow 사이트 무한 검색 구글링 시간을 줄일 수 있다.

G4. 개발자가 잘 알려진 라이브러리에 대해 GPT를 사용하는 경우, 예제 정도 수준의 코드를 얻을 수 있다(학습 데이터가 많은 경우).

다만, ChatGPT만으로는 다음과 같은 한계가 있다.

W1. 생성된 코드가 실행 오류가 없는 소프트웨어를 개발할 만큼 완벽하지 않다. 이전 실행 결과와 같이, 잘 알려져 있지 않은 라이브러리 사용 코드나 API 를 이해하고 있는 경우, 이는 사람이 API문서를 찾아서 적절히 코딩해야 한다. 당연하지만, ChatGPT 학습된 데이터가 부족한 데, 이런 작업을 알아서 해주지 않는다. 그렇다고, 이를 가능하게 하고자, 학습 데이터를 준비하는 것은 코딩보다 더 많은 일이 될 수 있다(가성비 문제).

W2. 도메인 맥락을 이해하지 못한다. 소프트웨어 시스템 아키텍처 설계 관점에서 코드를 생성하지는 않는다. 이는 도메인 요구사항과 지식을 반영해 디자인되는 것이므로, 이를 코드화하는 것은 쉽지 않다. 단지, ChatGPT는 한 모듈의 코드 패턴을 생성해 낼 수 있다. 결국 아키텍처 설계자, 개발자, 도메인 전문가가 함께 붙어 작업해야 하는 부분이다.

W3. 다양한 이기종 시스템으로 부터 데이터 통합, 연계, 테스트하는 것은 현장 상황에 따라 다르므로, 이를 GPT가 대치할 수 없다. 

W4. 어차피, 개발자가 개발을 해야 한다. 앞의 W1, W2, W3로 인해, 어차피 개발자가 코드를 작성해야 하고, 사용자와 요구사항 커뮤니케이션과 서비스 배포까지 고려하면, 이런 부분이 사실상 개발의 80~90% 이상을 차지한다. 

ChatGPT로 자동 작성된 코드도, 결국, 사람이 그 코드들을 이해해야, 테스트하고 품질을 검수할 수 있다(ChatGPT가 제공한 코드를 사용하다가 사고나면, GPT가 손해를 책임지는 것은 아니다). 

그래서, ChatGPT는 이전에 통합 개발환경에서 지원하던 개발보조도구의 편리한 인공지능 버전 검색 엔진 정도로 활용가능한 것이다. 당연히, 개발 과정을 대체할 수는 없을 것이다. 마찬가지 이유로, 컨텐츠를 만드는 작가, 모델러, 크리에이터의 일을 대체하는 일은 없을 것이다. 다만, 도구로 활용하면 생산성을 높일 수 있다(포토샵처럼).  

모든 문제를 풀어내는 인공지능 절대 솔류션은 없음


2022년 12월 1일 목요일

truffle, solidity, 이더리움을 활용한 스마트 계약 개발환경 설치 및 구현 방법

이 글은 truffle, solidity를 활용한 스마트 계약 개발환경 구축 및 구현 방법을 간략히 설명한다.

머리말
일반적으로 계약은 다자간 요구사항들을 만족하는 컨센서스(합의) 절차와 가치 교환 알고리즘이 포함된 프로그램이다. 다음 그림은 이를 잘 보여준다.
일반적인 계약 구조

솔리디티는 계약을 디지털화하기 위한 유명한 스마트 계약 언어 중 하나이다.
스마트 계약 개발 언어들

여기서는 솔리디티 언어를 사용해 간단한 스마트 계약 프로그램을 개발하고, 이를 배포해 본다.

개발환경 설치
다음과 같이 개발환경을 설치한다.
sudo npm install -g truffle
truffle init

스마트 계약 개발
다음과 같이 솔리디티 언어로 코딩한다. 자세한 내용은 여기를 참고한다. 
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.7.0 <0.9.0;

contract Hero{
    address owner;
    string hero;
    constructor(string memory _hero)
    {
        owner=msg.sender;
        hero=_hero;
    }
    
    function setHero(string memory _hero)public
    {
        require(msg.sender==owner,"Not the owner");
        hero =_hero;
    }
    function getHero() public view returns(string memory)
    {
        return hero;
    }
}

truffle-config.json 파일을 다음과 같이 생성한다.
module.exports = {
  compilers: {
    solc: {
      version: "0.8.1",   
    }
  },
};

다음과 같이 컴파일한다.
truffle compile


다음과 같이 컴파일된 결과를 build폴더에서 확인할 수 있다. 

배포를 위해 이더리움 시뮬레이터인 Ganache를 다운로드한다.


다음과 같이 실행 권한으로 파일을 수정한다.
chmod +x ganache-2.5.4-linux-x86_64.AppImage 

해당 파일을 실행하고, 퀵스타트 버튼을 클릭한다. 10개의 월렛이 리스트될 것이다.

배포를 위해, truffle-config.js 파일을 다음과 같이 업데이트한다.
module.exports = {
  networks: {
    development: {
      host: "127.0.0.1",
      port: 7545,
      network_id: "*"
    }
  },
  compilers: {
    solc: {
      version: "0.8.1",   
    }
  },
};

레퍼런스