Linux에서 SocketCAN을 활용한 CAN 네트워크 제어
1. 개요
CAN(Controller Area Network)은 자동차, 산업 자동화, 로봇 제어 등 다양한 분야에서 사용되는 직렬 통신 프로토콜입니다. Linux에서는 SocketCAN을 통해 CAN 네트워크를 제어할 수 있으며, 이는 기존의 네트워크 소켓 API와 유사한 방식으로 동작합니다.
이번 포스팅에서는 Linux의 CAN 드라이버 구조 및 설정, SocketCAN API를 활용한 데이터 송수신, 그리고 Python과 C를 활용한 CAN 통신 프로그래밍 방법을 자세히 살펴보겠습니다.
2. Linux의 CAN 드라이버 구조 및 설정
2.1 CAN 드라이버 개요
Linux 커널은 SocketCAN을 통해 CAN 인터페이스를 네트워크 장치로 지원합니다. 이를 통해 CAN 인터페이스를 마치 이더넷 인터페이스처럼 다룰 수 있습니다.
2.2 CAN 드라이버 로드
CAN 인터페이스를 활성화하려면 다음과 같은 모듈을 로드해야 합니다.
sudo modprobe can
sudo modprobe can_raw
sudo modprobe can_bcm
sudo modprobe vcan # 가상 CAN 인터페이스 사용 시 필요
위 명령을 실행하면 SocketCAN을 사용하기 위한 핵심 모듈이 로드됩니다.
2.3 CAN 인터페이스 활성화
일반적으로 CAN 인터페이스는 can0
, can1
등의 이름을 갖습니다. 인터페이스를 활성화하려면 다음과 같은 명령을 사용합니다.
sudo ip link set can0 type can bitrate 500000 # CAN 속도 설정 (500kbps)
sudo ip link set up can0 # 인터페이스 활성화
가상 CAN 인터페이스(vcan)를 설정하려면 아래 명령을 실행합니다.
sudo ip link add dev vcan0 type vcan
sudo ip link set up vcan0
설정된 인터페이스를 확인하려면 다음 명령을 사용합니다.
ip -details link show can0
인터페이스를 중지하려면 아래 명령을 실행합니다.
sudo ip link set down can0
3. SocketCAN API를 활용한 데이터 송수신
Linux에서는 candump
및 cansend
명령어를 이용해 CAN 메시지를 송수신할 수 있습니다.
3.1 CAN 메시지 수신 (candump
)
다음 명령을 실행하면 can0
인터페이스에서 수신되는 모든 CAN 메시지를 출력합니다.
candump can0
3.2 CAN 메시지 송신 (cansend
)
특정 메시지를 전송하려면 아래 명령을 사용합니다.
cansend can0 123#DEADBEEF # ID: 0x123, 데이터: 0xDEADBEEF
3.3 CAN 메시지 필터링
특정 ID의 메시지만 수신하려면 아래와 같이 실행합니다.
candump can0,123:7FF # ID 0x123인 메시지만 출력
4. Python과 C를 활용한 CAN 통신 프로그래밍
4.1 Python을 활용한 CAN 송수신
Python에서는 python-can
라이브러리를 활용하여 CAN 메시지를 송수신할 수 있습니다.
(1) 라이브러리 설치
pip install python-can
(2) CAN 메시지 송신 예제
import can
bus = can.interface.Bus(channel='can0', bustype='socketcan')
msg = can.Message(arbitration_id=0x123, data=[0xDE, 0xAD, 0xBE, 0xEF], is_extended_id=False)
try:
bus.send(msg)
print("메시지를 전송했습니다.")
except can.CanError:
print("메시지 전송 실패!")
(3) CAN 메시지 수신 예제
import can
bus = can.interface.Bus(channel='can0', bustype='socketcan')
print("CAN 메시지 수신 대기 중...")
while True:
msg = bus.recv()
print(f"수신된 메시지: ID={hex(msg.arbitration_id)}, 데이터={msg.data}")
4.2 C 언어를 활용한 CAN 송수신
(1) CAN 송신 코드 (C)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>
#include <sys/ioctl.h>
int main() {
int sock;
struct sockaddr_can addr;
struct ifreq ifr;
struct can_frame frame;
sock = socket(PF_CAN, SOCK_RAW, CAN_RAW);
strcpy(ifr.ifr_name, "can0");
ioctl(sock, SIOCGIFINDEX, &ifr);
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
bind(sock, (struct sockaddr *)&addr, sizeof(addr));
frame.can_id = 0x123;
frame.can_dlc = 4;
frame.data[0] = 0xDE;
frame.data[1] = 0xAD;
frame.data[2] = 0xBE;
frame.data[3] = 0xEF;
write(sock, &frame, sizeof(struct can_frame));
printf("메시지를 전송했습니다.\n");
close(sock);
return 0;
}
컴파일 후 실행:
gcc -o can_send can_send.c
sudo ./can_send
(2) CAN 수신 코드 (C)
int sock;
struct sockaddr_can addr;
struct ifreq ifr;
struct can_frame frame;
sock = socket(PF_CAN, SOCK_RAW, CAN_RAW);
strcpy(ifr.ifr_name, "can0");
ioctl(sock, SIOCGIFINDEX, &ifr);
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
bind(sock, (struct sockaddr *)&addr, sizeof(addr));
while (1) {
read(sock, &frame, sizeof(struct can_frame));
printf("수신된 메시지: ID=%X, 데이터=%X\n", frame.can_id, frame.data[0]);
}
close(sock);
5. 결론
이번 포스팅에서는 Linux에서 SocketCAN을 활용하여 CAN 네트워크를 설정하고, 명령어 및 Python, C 코드를 활용하여 CAN 메시지를 송수신하는 방법을 알아보았습니다. 실제 프로젝트에서는 이러한 기법을 기반으로 CAN 프로토콜을 구현하여 다양한 하드웨어 장치와 통신할 수 있습니다.
'CAN > CAN 기초' 카테고리의 다른 글
CAN 기반 센서 네트워크 구축 (실전 프로젝트) (0) | 2025.03.13 |
---|---|
CAN FD 및 최신 CAN XL 기술 심화 분석 (0) | 2025.03.12 |
CAN to Wireless 통합 시스템 구축 (0) | 2025.03.10 |
CAN을 활용한 실시간 제어 시스템 (0) | 2025.03.09 |
CAN 보안(Security) 및 해킹 대응 기법 (0) | 2025.03.08 |