**MCT(머시닝 센터)**와 같은 고정밀 공작기계는 실시간 데이터를 수집하고 분석하는 것이 생산성 향상과 예지보전의 핵심입니다. 이번 사례에서는 MCT의 서보 로드 정보 및 3축 부하율을 실시간으로 수집하고, 이를 다양한 **플랫폼(Grafana, 클라우드, 대시보드 등)**에서 활용하기 위한 구조를 정리합니다.
3D 프린터를 디지털 트윈 환경에서 제어하거나 모니터링하려면, 프린터와의 실시간 통신과 상태 업데이트 체계가 필수입니다. 본 사례에서는 Visual Studio + C# 환경에서 시리얼 통신을 설정하고, G-code 명령어를 전송해 프린터를 직접 제어하는 구조를 소개합니다.
✅ 프로젝트 개요
항목
내용
대상 장비
FDM 방식 3D 프린터 (Marlin 펌웨어 기준)
통신 방식
Serial (USB/COM 포트)
개발 환경
Visual Studio 2022+, C# .NET 6
제어 명령
G-code (온도 설정, XY 이동, 홈 복귀 등)
활용 목적
디지털 트윈 기반 원격 제어, 프린터 상태 실시간 반영
1. 시리얼 통신 연결 설정 (C#)
using System.IO.Ports;
SerialPort serial = new SerialPort("COM3", 115200); // 포트 & 속도 설정
serial.Open();
serial.WriteLine("M115"); // 펌웨어 정보 요청 G코드 전송
📌 Tip: 3D 프린터 대부분은 115200 또는 250000 bps 속도를 사용하며, Arduino 기반이면 COM 포트 자동 설정 로직을 넣는 것이 좋습니다.
2. 기본 G-code 명령어 예제
명령
기능
예시
M105
현재 온도 요청
M105
M104 S200
노즐 온도 설정
M104 S200 (200도)
G28
홈 위치 이동
G28
G1 X50 Y50 F3000
X,Y 위치 이동
X=50, Y=50으로 이동
M140 S60
히팅 배드 온도 설정
M140 S60
3. 실시간 위치 제어 예제
void MoveToPosition(float x, float y, int speed = 3000)
{
string gcode = $"G1 X{x} Y{y} F{speed}";
serial.WriteLine(gcode);
}
📌 실무 팁:
프린터는 명령 처리 후 ok 응답을 반환함 → 응답을 기다리는 로직 필요
G-code 전송 후 딜레이(Thread.Sleep) 또는 수신 확인 필요
4. 프린터 상태 모니터링 구조
serial.WriteLine("M105"); // 현재 온도 요청
string response = serial.ReadLine();
Console.WriteLine($"프린터 응답: {response}");
아두이노는 가볍고 빠르게 센서 데이터를 처리할 수 있어, 소형 자동화, IoT 실험, 데이터 수집용 게이트웨이로 자주 활용됩니다. 하지만 산업용 시스템(OPC UA 기반 PLC, SCADA 등)과 직접 연동하려면 다소 복잡한 설정이 필요하죠.
이 글에서는 아두이노를 OPC UA 시스템과 연동하는 2가지 접근 방식을 소개하고, 실제 구현에 필요한 설정과 노하우까지 정리해드립니다.
MCU 보드: Arduino Uno / Mega / ESP32 (ESP 추천)
연동 방식:
아두이노 → 중계 서버 → OPC UA Server
아두이노 직접 OPC UA Client (ESP32+라이브러리 활용 시 가능)
통신 프로토콜: OPC UA (opc.tcp://...)
사용 환경:
아두이노 IDE + 센서 코드
중계용 Python/Node.js 서버 또는 ESP32 자체 OPC UA 구현
🧩 구조별 연동 방식 비교
방식
구성
장점
단점
중계 서버 방식
아두이노 → 시리얼 or MQTT → 중계 서버(Python) → OPC UA
구조 단순, 구현 쉬움
실시간성 다소 낮음
직접 OPC UA Client
ESP32에서 OPC UA 요청 전송
실시간성 좋고 구조 간단
구현 복잡, 메모리 제약
1️⃣ 중계 서버 방식 (추천 접근)
📦 구성도
🧪 아두이노 코드 예제 (센서 값 전송)
// 예: 온도 센서 데이터 Serial로 전송
void loop() {
int temp = analogRead(A0);
Serial.println(temp);
delay(1000);
}
🐍 Python 중계 서버 예제 (opcua 라이브러리 사용)
from opcua import Server
import serial
# OPC UA 서버 생성
server = Server()
server.set_endpoint("opc.tcp://0.0.0.0:4840/")
node = server.register_namespace("ArduinoData")
objects = server.get_objects_node()
sensor_obj = objects.add_object(node, "TemperatureSensor")
temp_val = sensor_obj.add_variable(node, "Temperature", 0.0)
temp_val.set_writable()
# 시리얼 연결
arduino = serial.Serial('COM3', 9600)
server.start()
try:
while True:
data = arduino.readline().decode().strip()
temp_val.set_value(float(data))
except KeyboardInterrupt:
server.stop()
📌 이 방식은 실시간 센서 데이터를 OPC UA 서버로 전달할 수 있어, SCADA, Node-RED, UA Client와 연동 용이합니다.
2️⃣ ESP32 직접 OPC UA 연동 (고급)
ESP32는 WiFi 지원 + 메모리 여유 → OPC UA 통신 가능
OPC UA 클라이언트 구현 라이브러리 필요
freemodbus + libuaclient (C++)
또는 ESP32 + Arduino core + OPC UA 구현체 (매우 제한적)
❗️ 하지만 OPC UA는 메모리/성능 요구가 높아, 직접 구현보다는 중계 게이트웨이 구조가 현실적입니다.
🛠️ 실무 노하우 & 팁
항목
팁
아두이노 ↔ Python 통신
시리얼 통신은 안정성 높지만, MQTT로 확장도 고려 가능
Node-RED 연동
Python 대신 Node-RED + OPC UA 노드로 중계 가능
OPC UA 서버 주소
opc.tcp://localhost:4840/ → 실제 PLC 연동 시 외부 IP 사용
인증서 이슈
테스트 시 SecurityPolicy.None 사용, 운영 시 인증서 필요
SCADA 연동
UA 클라이언트로 UAExpert, Ignition, WinCC 등에서 실시간 시각화 가능
Siemens PLC는 글로벌 산업 자동화 표준이라 할 만큼 다양한 스마트팩토리 현장에서 활용되고 있습니다. 특히 S7-1200/1500 시리즈는 OPC UA 서버 내장으로, 외부 IT 시스템과의 연결성이 뛰어납니다.
이 글에서는 C# OPC UA 클라이언트 앱을 직접 구현하여, S7 PLC에서 실시간 데이터를 읽고 이벤트 처리까지 해보겠습니다. TIA Portal → 인증서 설정 → C# 코드 구현까지 단계별로 구성되어 있어 실무에 바로 적용 가능합니다.
통신 프로토콜: OPC UA (opc.tcp://<PLC IP>:4840)
개발 언어: C# (.NET 6 이상)
개발 환경: Visual Studio 2022+
사용 라이브러리: OPCFoundation.NetStandard.Opc.Ua
주요 기능:
TIA Portal에서 태그 공유 설정
C#으로 OPC UA 연결 및 데이터 Read
Subscription 기반 변경 이벤트 수신
보안 정책/인증서 구성 실전 팁
🔧 Siemens OPC UA 서버 활성화 절차 (TIA Portal)
S7-1200/1500 모델 선택 (1500은 고급 보안, 1200은 기본 기능 제공)
Device Configuration → OPC UA 탭
OPC UA Server 활성화
Global DB 생성 → 공개할 변수에 Accessible from HMI/OPC UA 체크
보안 인증서 생성 및 외부 Client와 교환
📦 C# OPC UA 연결 코드 예제
string endpointUrl = "opc.tcp://192.168.130.72:4840"; // PLC IP 주소
string nodeId = "ns=3;s=\"DB1\".\"Speed\""; // TIA Portal에서 설정한 DB 변수
var session = await Session.Create(config, endpoint, false, "SiemensClient", 60000, null, null);
var value = session.ReadValue(nodeId);
Console.WriteLine($"Speed 값: {value.Value}");
Siemens의 노드ID는 "DB명"."태그명" 형식으로 표현됨. ns=3은 서버 구성에 따라 달라질 수 있으니 UA 클라이언트 툴(ex. UAExpert)로 확인 필요.
🔁 Subscription 이벤트 처리
var monitoredItem = new MonitoredItem(subscription.DefaultItem)
{
StartNodeId = "ns=3;s=\"DB1\".\"Speed\"",
DisplayName = "Speed",
SamplingInterval = 500
};
monitoredItem.Notification += (item, args) =>
{
foreach (var v in item.DequeueValues())
{
Console.WriteLine($"Speed 변경됨: {v.Value}");
}
};
🛠️ 실무 노하우
항목설명
TIA Portal 설정 필수
Accessible from HMI/OPC UA 옵션 체크 안 하면 외부 접근 불가
인증서 관리
Siemens는 기본적으로 인증서 기반 접근만 허용 → C# 클라이언트 인증서 생성 후 교환
스마트 팩토리 시대, 설비 간 연결은 선택이 아닌 필수입니다. OMRON NX/NJ 시리즈는 OPC UA 서버 기능이 내장된 고성능 PLC로, 제어 + 정보화를 동시에 처리하는 것이 특징입니다. 특히 C# 기반 OPC UA 클라이언트를 이용하면 MES, SCADA, ERP 등 IT 시스템과 직접 통신이 가능하죠.
이 글에서는 Visual Studio + C# 환경에서 OMRON PLC 데이터를 실시간으로 읽고, 이벤트를 처리하는 구조까지 단계별로 안내합니다.
통신 프로토콜: OPC UA (opc.tcp:// 포트 4840 기본)
개발 언어: C# (.NET 6 이상)
개발 환경: Visual Studio 2022 이상
사용 라이브러리: OPCFoundation.NetStandard.Opc.Ua
주요 기능:
OMRON Sysmac Studio에서 생성한 태그 노드 연결
PLC 변수(노드) 읽기 및 Subscription 기반 값 변경 감지
인증서 신뢰 구성 및 이벤트 처리 실무 팁 제공
1 OMRON OPC UA 통신 사전 준비
Sysmac Studio 설정:
OPC UA 서버 기능 활성화
Anonymous or 사용자 인증 허용
보안 정책: None, Basic256Sha256 등 설정 가능
변수 공개 설정 (Publish to OPC UA: TRUE)
노드 ID 확인 경로: Controller Variables > Export XML
📦 C# OPC UA 클라이언트 개발 주요 흐름
OPC UA 라이브러리 설치 (NuGet)
서버 엔드포인트 설정 (opc.tcp://192.168.0.50:4840)
태그 NodeId 확인 후 데이터 Read
Subscription 구성 → 값 변경 감지
🧪 예시 노드 구조
OMRON은 아래와 같은 심볼 기반 NodeId를 제공합니다:
// 예: Global 변수인 "MotorSpeed"
var nodeId = "ns=2;s=MotorSpeed"; // 또는 XML export로 확인
🧵 Subscription 이벤트 처리 예제
var monitoredItem = new MonitoredItem(subscription.DefaultItem)
{
DisplayName = "MotorSpeed",
StartNodeId = "ns=2;s=MotorSpeed"
};
monitoredItem.Notification += (item, args) =>
{
foreach (var v in item.DequeueValues())
{
Console.WriteLine($"모터 속도 변경됨: {v.Value}");
}
};
using System;
using System.Threading.Tasks;
using Opc.Ua;
using Opc.Ua.Client;
using Opc.Ua.Configuration;
namespace LsOpcUaClient
{
class Program
{
static async Task Main(string[] args)
{
// 애플리케이션 구성
var config = new ApplicationConfiguration()
{
ApplicationName = "LSOpcUaClient",
ApplicationType = ApplicationType.Client,
SecurityConfiguration = new SecurityConfiguration
{
ApplicationCertificate = new CertificateIdentifier(),
AutoAcceptUntrustedCertificates = true, // 테스트용
},
TransportConfigurations = new TransportConfigurationCollection(),
TransportQuotas = new TransportQuotas { OperationTimeout = 15000 },
ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 60000 }
};
await config.Validate(ApplicationType.Client);
// OPC UA 엔드포인트 설정
var endpointURL = "opc.tcp://192.168.0.100:4840"; // PLC의 OPC UA 주소 입력
var endpointDescription = CoreClientUtils.SelectEndpoint(endpointURL, useSecurity: false);
var endpointConfiguration = EndpointConfiguration.Create(config);
var endpoint = new ConfiguredEndpoint(null, endpointDescription, endpointConfiguration);
// 세션 생성
var session = await Session.Create(config, endpoint, false, "LS OPC UA Client", 60000, null, null);
Console.WriteLine("OPC UA 세션 연결 완료.");
// 노드 값 읽기
string nodeId = "ns=2;s=TAG1"; // PLC의 실제 노드 ID 입력
DataValue value = session.ReadValue(nodeId);
Console.WriteLine($"노드 값: {value.Value}");
// 세션 종료
session.Close();
Console.WriteLine("세션 종료 완료.");
}
}
}
🔍 주요 설명:
endpointURL: LS PLC의 IP와 포트를 입력
nodeId: LS PLC에 정의된 태그 (예: s=DB1.Tag1 또는 ns=2;s=MyTag)
AutoAcceptUntrustedCertificates = true: 인증서 자동 수락 (실제 운영에선 보안 정책 필요)
4. 예제 실행 전 체크리스트
항목확인
PLC의 OPC UA 서버 활성화 여부
✅
포트 방화벽 허용 (기본 4840)
✅
PLC에 등록된 노드 ID 확인
✅
인증서 정책 확인 및 설정
✅
5. [실무 팁] 데이터 변경 이벤트 처리 (Subscription 방식)
OPC UA는 클라이언트가 주기적으로 값을 읽는 Polling 방식 외에도, 서버에서 값 변경 시 자동 통지받는 Subscription 방식을 지원합니다. 이를 활용하면 다음과 같은 이점이 있습니다:
✅ Subscription 방식의 장점
실시간 데이터 반영 가능
CPU 부하 절감 (Polling 대비)
산업 현장 이벤트 기반 제어에 적합
예제: 값 변경 시 자동 알림 받기
// Subscription 및 이벤트 핸들링 예제
var subscription = new Subscription(session.DefaultSubscription)
{
PublishingInterval = 1000 // 1초 간격으로 변경사항 체크
};
// 모니터링할 노드 지정
var monitoredItem = new MonitoredItem(subscription.DefaultItem)
{
DisplayName = "MyTag",
StartNodeId = "ns=2;s=TAG1", // LS PLC의 노드 ID
SamplingInterval = 500, // 샘플링 주기 (ms)
QueueSize = 10,
DiscardOldest = true
};
// 변경 시 이벤트 핸들러 등록
monitoredItem.Notification += OnValueChanged;
// 구독 항목에 추가하고 세션에 등록
subscription.AddItem(monitoredItem);
session.AddSubscription(subscription);
subscription.Create();
콜백 함수 정의
private static void OnValueChanged(MonitoredItem item, MonitoredItemNotificationEventArgs e)
{
foreach (var value in item.DequeueValues())
{
Console.WriteLine($"[{DateTime.Now}] {item.DisplayName} 변경됨: {value.Value}");
}
}
6. 실무 노하우: Subscription 구현 시 주의점
팁
설명
1. PublishingInterval 과 SamplingInterval 적절 조절
너무 짧게 잡으면 불필요한 이벤트가 많아지고 성능 저하
2. QueueSize 조정
네트워크 지연 시 데이터 누락 방지
3. Network Loss 대비 재접속 로직 구현
KeepAlive 체크 및 세션 오류 시 재연결
4. 노드가 Null 또는 Bad Status인 경우 체크
일부 PLC에서는 데이터 초기화 전 Null 또는 StatusCode.Bad 리턴
5. 인증서 신뢰 문제로 Subscription 실패 가능
개발 중 AutoAcceptUntrustedCertificates = true 설정으로 임시 우회
고급 확장: 알람 연동
LS PLC에서 설정한 특정 조건 (예: 알람 태그)이 True로 바뀌는 순간만 감지하여 UI에 경고 표시
예: ns=2;s=Alarm_MotorOverheat가 True → 팝업 or 로그 기록
if ((bool)value.Value == true)
{
Console.WriteLine("🔥 모터 과열 경고!");
}
이처럼 Subscription 기반 구조는 SCADA 시스템, 디지털 트윈, AI 기반 제어 시스템에서 핵심 요소로 사용됩니다.
* 전용 모듈이 없는 경우, BridgeWare의LSE OPC Server를 사용하여 LS산전 PLC(Glofa, XGT, Master-K)와 데이터를 수집 가능 / 모드버스 TCP 이용
질량 (Mass) 물체가 가지고 있는 고유한 물질의 양이자, 운동 상태 변화에 대한 저항(관성)의 크기를 나타내는 정량적인 척도
관성(Inertia) 외력이 작용하지 않을 때 물체가 현재의 운동 상태(정지 또는 등속도 운동)를 그대로 유지하려는 성질
마찰(Friction) 두 물체의 접촉면 사이에서 물체의 운동을 방해하거나, 상대적인 미끄러짐에 저항하는 힘
중력(Gravity) 질량을 가진 모든 물체 사이에 서로 당기는 힘
이 요소들이 다 로봇 움직임에 영향을 준다. 그래서 실제 로봇은 수학적으로 계산한 대로 절대 안 움직인다.
2️⃣ 제어 이론
대표적인 제어 방식:
PID 제어 오차 값(목표값 - 현재값)을 이용하여비례(P)-적분(I)-미분(D)세 가지 요소를 조합해 제어량을 결정하는 피드백 제어
토크 제어 모터에 인가되는 전류를 제어하여 회전력(토크)을 직접적으로 조절하는 방식입니다. 주로 토크 기반의 힘 제어를 수행
임피던스 제어 로봇의 위치와 힘 사이의 동적인 관계(강성, 댐핑)를 제어하여, 로봇이 원하는 스프링-댐퍼 시스템처럼 행동하도록 하는 방식
제어는 결국 “오차를 줄이는 기술”이다. 로봇이 목표 위치와 실제 위치 사이의 차이를 얼마나 빨리, 얼마나 안정적으로 줄이느냐가 관건이다.
3️⃣ 시뮬레이터와 현실의 간극
시뮬레이터에선 완벽한데 현실 로봇에 올리면 망가지는 이유:
마찰 모델 부정확 실제 마찰(Coulomb + Viscous + Stribeck 효과)은 속도에 따라 변하고 비선형적입니다. 이를 정확히 모델링하지 못하면 (예: 정지 마찰력 과소평가), 저속 운전 시스틱-슬립(Stick-slip) 현상이 발생
센서 노이즈 엔코더나 힘 센서에서 발생하는 고주파 노이즈는 미분(속도 계산) 시 노이즈를 증폭
기구물의 유격 기어, 커플링 등 기구적 틈새로 인해 모터가 움직여도 부하(Load)가 바로 움직이지 않는 구간입니다. 방향 전환 시데드존(Dead-zone)이 발생
여기서부터 “이론과 현실의 전쟁”이 시작된다.
해결 방안 :
마찰 모델 부정확 > 룩업 테이블, 신경망(RBF), 또는 고도화된 마찰 모델(LuGre 등)을 사용 센서 노이즈 > 저주파 통과 필터(Low-pass filter), 칼만 필터(Kalman filter), 또는 상태 관측기(Observer)를 통해 노이즈를 제거 기구물의 유격 >백래시 보상 알고리즘(Dead-zone inverse) 적용, 이중 엔코더(모터측 + 부하측) 사용, 기계적 프리로드(Preload).