이번엔 비행기로 10시간 넘게 가야하는 스위스로 여행을 다녀왔다.
<> 스위스 여행 팁
- 렌트카가 대부분 수동 차량입니다. 근 16년만에 수동 차량을 몰았는데 렌트카 주차장에서 십수번 엔진 꺼트려묵고 겨우 적응 되었습니다. 1년간 수동 차량을 몰았던 경험이 있어서인지 다행이 몸이 기억하고 있어서 운행이 가능했습니다. 경사가 가파르고 폭이 좁은 언덕길 운행이 적지 않으니 수동 차량 면허증이 있다 하더라도 자동 변속 차량 운전만 계속 해왔다면 잘 판단 하시길 바랍니다.
- 안드로이드 스마트폰 사용에 능숙하다면 차 렌트하실때 GPS(네비게이션) 옵션을 빼고, 구글 오프라인 지도와 구글 지도에 기본 내장된 네비게이션 기능을 활용해 보세요. GPS 옵션 가격이 상당합니다. 돈 많다구요? 알아서 하세요.
- 모바일 단말기의 데이터가 필요하다면 SALT라는 매장에서 Pre-Pay 유심 구입을 알아 보세요. 제가 여행 할 때 10프랑(약 12,300원)으로 10일간 데이터 무제한이었습니다. 유심 장착 후 20~30분이 지나도 인터넷이 안되면 APN 설정이 정상적으로 되지 않은 것이니 가까운 SALT매장에 들러 손봐달라고 하면 바로 됩니다.
- 물가가 상상을 초월합니다. 라면과 햇반은 넉넉하게 준비해 가시고, 우리나라 대형 마트와 비슷한 COOP이나 MIGROS를 찾으면 그나마 저렴하게(하지만 여전히 비싼편) 먹거리 해결이 가능 할 겁니다. 금수저라구요? 식당 가세요.
- 스위스 기상청(?) 날씨 예측이 나름 잘 맞는듯 합니다. 다음날 여행에 참고하세요.
- 저렴하면서 비교적 시설 나쁘지 않은 호텔에 묵으려 한다면 IBIS BUDGET호텔을 추천 합니다. 라면용 온수와 햇반용 전자렌지 사용도 가능합니다. IBIS MESSE호텔도 있는데 IBIS BUDGET보다 가격이 좀 되고, 전자렌지가 없었습니다. 갑부라구요? 맘에 드는데 가세요.
- 차를 빌리셨다면 그림젤패스(Grimselpass), 푸르카패스(Furkapass), 수스텐패스(Sustenpass) 고갯길은 꼭 가보세요. 두번 가세요. Need for Speed 게임에서만 보던 그림같은 광경이 눈앞에 펼쳐 집니다. 손대면 부러질 듯한 듬성듬성 심어진 플라스틱 안전봉 아래 수백미터 절벽의 고갯길을 운전하다 보면 심장이 쫄깃해 집니다.
- 렌즈 교환식 카메라를 가져간다면 구할 수 있는 가장 넓은 광각 렌즈(어안 말고)를 가져 가세요. 눈으로 보는 장관이 뷰파인더에서는 많이 사라집니다. 스마트폰만 가져간다면 파노라마 촬영 기능이 있는지 확인하세요.
- 그린델발트(Grindelwald)에서 비교적 저렴한 숙소를 찾아 헤매다 Downtown Lodge를 발견했는데 가격 대비 나쁘지 않았습니다. 샤워장과 화장실 및 주방을 공동으로 사용하는 도미토리 형태입니다. 한국 배낭족이 많았습니다. 3프랑(약 3~4천원)을 주면 고기 굽는 그릴과 석탄을 줍니다. COOP이나 MIGROS에서 스테이크용 소고기 덩어리 사다, 눈 쌓인 뾰족산을 배경으로 구워먹어 보세요. 맛이 좋습니다. 파란색 캔의 스위스산 맥주도 싸고 맛납니다.
- 스위스 여름의 낮은 정말 깁니다. 밤 10시가 넘어가는데도 밖이 훤 합니다.
- 속도 위반 벌금이 무지 쎄다고 합니다. 주의 하세요. 단속 카메라 모양은 우리나라와 다른거 같습니다. 차 빌릴때 제공한 한국 주소나 사용한 신용카드등으로 알아내어 어떻게 해서든 범칙금 고지서를 거주지로 보낸다고 합니다. 마지막날 여유 부리다 늦어서 공항 가는길 과속을 좀 했는데 범칙금 날라올꺼 땜시 현재 두려움에 부들부들 떨고 있습니다.
- Victorinox 멀티툴(맥가이버 칼)은 스위스 현지 보다 우리나라 온라인 쇼핑몰이 더 쌉니다. 종류도 더 많습니다.
i.MX6Q (ARM Cortex-A9 Quad Core) Embedded Linux-Xenomai RTOS Porting
간만에 삽질좀 했다.
ARM Cortex-A9 쿼드코어 기반 AP인 i.MX6Q 프로세서에 Linux-Xenomai RTOS를 포팅해 봤다.
ARMv4/5기반의 오래된 ARM에만 포팅 해보다 나름 최근(?)의 성능 좋은 프로세서에 포팅작업을 하려다 보니 여러가지 삽질들이 좀 많았다.
우선 리눅스 커널 버전과 Xenomai 버전이 올라가면서 바닐라 커널의 Xenomai패치는 한결 수월해 졌으나, 커널에 Device-Tree라는 요상한게 생기고 Cortex-A9의 하드웨어 FPU인 VFPv3 및 NEON을 제대로 지원하는 툴체인을 빌드하느라 시간을 좀 많이 까묵었다 (툴체인 한번 빌드하는데 3~4시간, 커널 빌드하는데 30~40분).
마침내 커널 부팅되고 램디스크 마운팅 되고 Xenomai 어플리케이션 돌아가고...
드디어 1GHz 쿼드코어에서 돌아가는 RTOS가 만들어 졌다. 움하하...
<> 커널 부팅
------------------------------------------------------------------
Booting Linux on physical CPU 0x0
Linux version 3.10.32-xenokang (root@localhost.localdomain) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0) ) #1 SMP Wed Jun 15 10:43:26 KST 2016
CPU: ARMv7 Processor [412fc09a] revision 10 (ARMv7), cr=10c5387d
CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
Machine: Freescale i.MX6 Quad/DualLite (Device Tree), model: Freescale i.MX6 Quad SABRE Smart Device Board
Truncating RAM at 10000000-8fffffff to -7f7fffff (vmalloc region overlap).
Memory policy: ECC disabled, Data cache writealloc
PERCPU: Embedded 10 pages/cpu @815fc000 s18496 r8192 d14272 u40960
Built 1 zonelists in Zone order, mobility grouping on. Total pages: 453136
Kernel command line: console=ttymxc0,115200 root=/dev/ram0 rw --no-log initrd=0x1E000000,16M ramdisk=32768
PID hash table entries: 4096 (order: 2, 16384 bytes)
Dentry cache hash table entries: 262144 (order: 8, 1048576 bytes)
Inode-cache hash table entries: 131072 (order: 7, 524288 bytes)
Memory: 1784MB = 1784MB total
Memory: 1786168k/1786168k available, 40648k reserved, 0K highmem
Virtual kernel memory layout:
vector : 0xffff0000 - 0xffff1000 ( 4 kB)
fixmap : 0xfff00000 - 0xfffe0000 ( 896 kB)
vmalloc : 0xf0000000 - 0xff000000 ( 240 MB)
lowmem : 0x80000000 - 0xef800000 (1784 MB)
modules : 0x7f000000 - 0x80000000 ( 16 MB)
.text : 0x80008000 - 0x80693ff4 (6704 kB)
.init : 0x80694000 - 0x806ea840 ( 347 kB)
.data : 0x806ec000 - 0x80717fa0 ( 176 kB)
.bss : 0x80717fa0 - 0x807f9464 ( 902 kB)
SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1
Hierarchical RCU implementation.
NR_IRQS:16 nr_irqs:16 16
sched_clock: 32 bits at 66MHz, resolution 15ns, wraps every 65075ms
I-pipe, 66.000 MHz clocksource
I-pipe, 396.000 MHz clocksource
CPU identified as i.MX6Q, silicon rev 1.2
Interrupt pipeline (release #5)
Console: colour dummy device 80x30
Calibrating delay loop... 1581.05 BogoMIPS (lpj=7905280)
pid_max: default: 32768 minimum: 301
Mount-cache hash table entries: 512
...
...
Switching to clocksource ipipe_tsc
NET: Registered protocol family 2
TCP established hash table entries: 16384 (order: 5, 131072 bytes)
TCP bind hash table entries: 16384 (order: 5, 131072 bytes)
TCP: Hash tables configured (established 16384 bind 16384)
TCP: reno registered
UDP hash table entries: 1024 (order: 3, 32768 bytes)
UDP-Lite hash table entries: 1024 (order: 3, 32768 bytes)
NET: Registered protocol family 1
RPC: Registered named UNIX socket transport module.
RPC: Registered udp transport module.
RPC: Registered tcp transport module.
RPC: Registered tcp NFSv4.1 backchannel transport module.
Trying to unpack rootfs image as initramfs...
rootfs image is not initramfs (no cpio magic); looks like an initrd
Freeing initrd memory: 16384K (8e000000 - 8f000000)
hw perfevents: enabled with ARMv7 Cortex-A9 PMU driver, 7 counters available
I-pipe: head domain Xenomai registered.
Xenomai: hal/arm started.
Xenomai: scheduling class idle registered.
Xenomai: scheduling class rt registered.
Xenomai: real-time nucleus v2.6.4 (Jumpin' Out) loaded.
Xenomai: starting native API services.
Xenomai: starting POSIX services.
Xenomai: starting RTDM services.
VFS: Disk quotas dquot_6.5.2
Dquot-cache hash table entries: 1024 (order 0, 4096 bytes)
NFS: Registering the id_resolver key type
Key type id_resolver registered
Key type id_legacy registered
jffs2: version 2.2. (NAND) ⓒ 2001-2006 Red Hat, Inc.
fuse init (API version 7.22)
msgmni has been set to 3520
io scheduler noop registered
io scheduler deadline registered
io scheduler cfq registered (default)
imx-sdma 20ec000.sdma: initialized
Serial: IMX driver
2020000.serial: ttymxc0 at MMIO 0x2020000 (irq = 58) is a IMX
console [ttymxc0] enabled
...
...
RAMDISK: gzip image found at block 0
VFS: Mounted root (ext2 filesystem) on device 1:0.
devtmpfs: mounted
Freeing unused kernel memory: 344K (80694000 - 806ea000)
init started: BusyBox v1.22.1 (2016-06-15 10:43:42 KST)
starting pid 56, tty '': '/etc/init.d/rcS'
Please press Enter to activate this console.
starting pid 64, tty '': '-/bin/sh'
[root@imx6q /]#
[root@imx6q /]#
[root@imx6q /]# ls -al
drwxr-xr-x 17 0 0 1024 Jan 1 00:57 .
drwxr-xr-x 17 0 0 1024 Jan 1 00:57 ..
-rw------- 1 0 0 7 Jan 1 00:57 .ash_history
drwxr-xr-x 2 0 0 1024 Jun 15 2016 app
drwxr-xr-x 2 0 0 1024 Jun 15 2016 bin
drwxr-xr-x 5 0 0 2840 Jan 1 00:00 dev
drwxr-xr-x 3 0 0 1024 Jun 15 2016 etc
drwxr-xr-x 2 0 0 1024 Jun 15 2016 lib
lrwxrwxrwx 1 0 0 11 Jun 15 2016 linuxrc -> bin/busybox
drwx------ 2 0 0 12288 Jun 15 2016 lost+found
drwxr-xr-x 2 0 0 1024 Jun 15 2016 nand
dr-xr-xr-x 64 0 0 0 Jan 1 00:00 proc
drwxr-xr-x 2 0 0 1024 Jun 15 2016 root
drwxr-xr-x 2 0 0 1024 Jun 15 2016 sbin
drwxr-xr-x 2 0 0 1024 Jun 15 2016 sdcard
dr-xr-xr-x 12 0 0 0 Jan 1 00:00 sys
drwxr-xr-x 2 0 0 1024 Jun 15 2016 tmp
drwxr-xr-x 5 0 0 1024 Jun 15 2016 usr
drwxr-xr-x 2 0 0 1024 Jun 15 2016 xenomai
[root@imx6q /]#
UART, I2C, SPI, PWM, CAN, Ethernet, USB, SDIO, SATA, CAM, HDMI, 2D/3D Video 및 4개 1GHz 코어와 hardware-FPU를 탑재한 원칩 SoC에서 SMP를 지원하는 RTOS가 불과 1W 언저리에서 돌아간다... 우와, 막강이구먼.
안되는 제어가 없겠다.
어디에 쓰면 좋을까?
ARM Cortex-A9 쿼드코어 기반 AP인 i.MX6Q 프로세서에 Linux-Xenomai RTOS를 포팅해 봤다.
ARMv4/5기반의 오래된 ARM에만 포팅 해보다 나름 최근(?)의 성능 좋은 프로세서에 포팅작업을 하려다 보니 여러가지 삽질들이 좀 많았다.
우선 리눅스 커널 버전과 Xenomai 버전이 올라가면서 바닐라 커널의 Xenomai패치는 한결 수월해 졌으나, 커널에 Device-Tree라는 요상한게 생기고 Cortex-A9의 하드웨어 FPU인 VFPv3 및 NEON을 제대로 지원하는 툴체인을 빌드하느라 시간을 좀 많이 까묵었다 (툴체인 한번 빌드하는데 3~4시간, 커널 빌드하는데 30~40분).
마침내 커널 부팅되고 램디스크 마운팅 되고 Xenomai 어플리케이션 돌아가고...
드디어 1GHz 쿼드코어에서 돌아가는 RTOS가 만들어 졌다. 움하하...
<> 커널 부팅
------------------------------------------------------------------
Booting Linux on physical CPU 0x0
Linux version 3.10.32-xenokang (root@localhost.localdomain) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0) ) #1 SMP Wed Jun 15 10:43:26 KST 2016
CPU: ARMv7 Processor [412fc09a] revision 10 (ARMv7), cr=10c5387d
CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
Machine: Freescale i.MX6 Quad/DualLite (Device Tree), model: Freescale i.MX6 Quad SABRE Smart Device Board
Truncating RAM at 10000000-8fffffff to -7f7fffff (vmalloc region overlap).
Memory policy: ECC disabled, Data cache writealloc
PERCPU: Embedded 10 pages/cpu @815fc000 s18496 r8192 d14272 u40960
Built 1 zonelists in Zone order, mobility grouping on. Total pages: 453136
Kernel command line: console=ttymxc0,115200 root=/dev/ram0 rw --no-log initrd=0x1E000000,16M ramdisk=32768
PID hash table entries: 4096 (order: 2, 16384 bytes)
Dentry cache hash table entries: 262144 (order: 8, 1048576 bytes)
Inode-cache hash table entries: 131072 (order: 7, 524288 bytes)
Memory: 1784MB = 1784MB total
Memory: 1786168k/1786168k available, 40648k reserved, 0K highmem
Virtual kernel memory layout:
vector : 0xffff0000 - 0xffff1000 ( 4 kB)
fixmap : 0xfff00000 - 0xfffe0000 ( 896 kB)
vmalloc : 0xf0000000 - 0xff000000 ( 240 MB)
lowmem : 0x80000000 - 0xef800000 (1784 MB)
modules : 0x7f000000 - 0x80000000 ( 16 MB)
.text : 0x80008000 - 0x80693ff4 (6704 kB)
.init : 0x80694000 - 0x806ea840 ( 347 kB)
.data : 0x806ec000 - 0x80717fa0 ( 176 kB)
.bss : 0x80717fa0 - 0x807f9464 ( 902 kB)
SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1
Hierarchical RCU implementation.
NR_IRQS:16 nr_irqs:16 16
sched_clock: 32 bits at 66MHz, resolution 15ns, wraps every 65075ms
I-pipe, 66.000 MHz clocksource
I-pipe, 396.000 MHz clocksource
CPU identified as i.MX6Q, silicon rev 1.2
Interrupt pipeline (release #5)
Console: colour dummy device 80x30
Calibrating delay loop... 1581.05 BogoMIPS (lpj=7905280)
pid_max: default: 32768 minimum: 301
Mount-cache hash table entries: 512
...
...
Switching to clocksource ipipe_tsc
NET: Registered protocol family 2
TCP established hash table entries: 16384 (order: 5, 131072 bytes)
TCP bind hash table entries: 16384 (order: 5, 131072 bytes)
TCP: Hash tables configured (established 16384 bind 16384)
TCP: reno registered
UDP hash table entries: 1024 (order: 3, 32768 bytes)
UDP-Lite hash table entries: 1024 (order: 3, 32768 bytes)
NET: Registered protocol family 1
RPC: Registered named UNIX socket transport module.
RPC: Registered udp transport module.
RPC: Registered tcp transport module.
RPC: Registered tcp NFSv4.1 backchannel transport module.
Trying to unpack rootfs image as initramfs...
rootfs image is not initramfs (no cpio magic); looks like an initrd
Freeing initrd memory: 16384K (8e000000 - 8f000000)
hw perfevents: enabled with ARMv7 Cortex-A9 PMU driver, 7 counters available
I-pipe: head domain Xenomai registered.
Xenomai: hal/arm started.
Xenomai: scheduling class idle registered.
Xenomai: scheduling class rt registered.
Xenomai: real-time nucleus v2.6.4 (Jumpin' Out) loaded.
Xenomai: starting native API services.
Xenomai: starting POSIX services.
Xenomai: starting RTDM services.
VFS: Disk quotas dquot_6.5.2
Dquot-cache hash table entries: 1024 (order 0, 4096 bytes)
NFS: Registering the id_resolver key type
Key type id_resolver registered
Key type id_legacy registered
jffs2: version 2.2. (NAND) ⓒ 2001-2006 Red Hat, Inc.
fuse init (API version 7.22)
msgmni has been set to 3520
io scheduler noop registered
io scheduler deadline registered
io scheduler cfq registered (default)
imx-sdma 20ec000.sdma: initialized
Serial: IMX driver
2020000.serial: ttymxc0 at MMIO 0x2020000 (irq = 58) is a IMX
console [ttymxc0] enabled
...
...
RAMDISK: gzip image found at block 0
VFS: Mounted root (ext2 filesystem) on device 1:0.
devtmpfs: mounted
Freeing unused kernel memory: 344K (80694000 - 806ea000)
init started: BusyBox v1.22.1 (2016-06-15 10:43:42 KST)
starting pid 56, tty '': '/etc/init.d/rcS'
Please press Enter to activate this console.
starting pid 64, tty '': '-/bin/sh'
[root@imx6q /]#
[root@imx6q /]#
[root@imx6q /]# ls -al
drwxr-xr-x 17 0 0 1024 Jan 1 00:57 .
drwxr-xr-x 17 0 0 1024 Jan 1 00:57 ..
-rw------- 1 0 0 7 Jan 1 00:57 .ash_history
drwxr-xr-x 2 0 0 1024 Jun 15 2016 app
drwxr-xr-x 2 0 0 1024 Jun 15 2016 bin
drwxr-xr-x 5 0 0 2840 Jan 1 00:00 dev
drwxr-xr-x 3 0 0 1024 Jun 15 2016 etc
drwxr-xr-x 2 0 0 1024 Jun 15 2016 lib
lrwxrwxrwx 1 0 0 11 Jun 15 2016 linuxrc -> bin/busybox
drwx------ 2 0 0 12288 Jun 15 2016 lost+found
drwxr-xr-x 2 0 0 1024 Jun 15 2016 nand
dr-xr-xr-x 64 0 0 0 Jan 1 00:00 proc
drwxr-xr-x 2 0 0 1024 Jun 15 2016 root
drwxr-xr-x 2 0 0 1024 Jun 15 2016 sbin
drwxr-xr-x 2 0 0 1024 Jun 15 2016 sdcard
dr-xr-xr-x 12 0 0 0 Jan 1 00:00 sys
drwxr-xr-x 2 0 0 1024 Jun 15 2016 tmp
drwxr-xr-x 5 0 0 1024 Jun 15 2016 usr
drwxr-xr-x 2 0 0 1024 Jun 15 2016 xenomai
[root@imx6q /]#
------------------------------------------------------------------
<> Xenomai latency 측정
------------------------------------------------------------------
[root@imx6q /xenomai/bin]#
[root@imx6q /xenomai/bin]# ./latency -t 0 -p 1000
== Sampling period: 1000 us
== Test mode: periodic user-mode task
== All results in microseconds
warming up...
RTT| 00:00:01 (periodic user-mode task, 1000 us period, priority 99)
RTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst
RTD| -3.043| -2.028| 0.108| 0| 0| -3.043| 0.108
RTD| -3.152| -1.927| 12.189| 0| 0| -3.152| 12.189
RTD| -3.013| -1.902| 9.260| 0| 0| -3.152| 12.189
RTD| -3.109| -1.935| 10.295| 0| 0| -3.152| 12.189
RTD| -3.006| -1.879| 12.530| 0| 0| -3.152| 12.530
RTD| -3.028| -1.947| 11.944| 0| 0| -3.152| 12.530
RTD| -3.175| -1.940| 11.242| 0| 0| -3.175| 12.530
RTD| -3.102| -1.975| 9.166| 0| 0| -3.175| 12.530
RTD| -3.104| -1.950| 12.343| 0| 0| -3.175| 12.530
RTD| -3.091| -1.958| 10.580| 0| 0| -3.175| 12.530
RTD| -3.089| -1.955| 11.234| 0| 0| -3.175| 12.530
RTD| -3.003| -1.973| 11.452| 0| 0| -3.175| 12.530
RTD| -3.086| -1.920| 8.444| 0| 0| -3.175| 12.530
RTD| -3.124| -1.925| 12.068| 0| 0| -3.175| 12.530
RTD| -3.185| -1.953| 12.439| 0| 0| -3.185| 12.530
RTD| -2.973| -1.955| 11.510| 0| 0| -3.185| 12.530
RTD| -3.079| -1.955| 11.401| 0| 0| -3.185| 12.530
RTD| -3.096| -1.955| 9.636| 0| 0| -3.185| 12.530
RTD| -3.056| -1.958| 10.664| 0| 0| -3.185| 12.530
RTD| -3.081| -1.877| 11.353| 0| 0| -3.185| 12.530
RTD| -2.958| -1.872| 11.348| 0| 0| -3.185| 12.530
RTT| 00:00:22 (periodic user-mode task, 1000 us period, priority 99)
RTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst
RTD| -3.099| -1.958| 11.406| 0| 0| -3.185| 12.530
RTD| -3.190| -1.917| 11.838| 0| 0| -3.190| 12.530
RTD| -3.104| -1.958| 12.045| 0| 0| -3.190| 12.530
RTD| -3.033| -1.940| 9.477| 0| 0| -3.190| 12.530
RTD| -2.980| -1.892| 11.714| 0| 0| -3.190| 12.530
^C---|-----------|-----------|-----------|--------|------|-------------------------
RTS| -3.190| -1.937| 12.530| 0| 0| 00:00:27/00:00:27
[root@imx6q /xenomai/bin]#
[root@imx6q /xenomai/bin]# ./latency -t 1 -p 1000
== Sampling period: 1000 us
== Test mode: in-kernel periodic task
== All results in microseconds
warming up...
RTT| 00:00:01 (in-kernel periodic task, 1000 us period, priority 99)
RTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst
RTD| -5.809| -4.296| -1.410| 0| 0| -5.809| -1.410
RTD| -5.299| -4.212| 7.689| 0| 0| -5.809| 7.689
RTD| -5.839| -4.229| 5.860| 0| 0| -5.839| 7.689
RTD| -6.036| -4.262| 6.257| 0| 0| -6.036| 7.689
RTD| -5.807| -4.261| 4.067| 0| 0| -6.036| 7.689
RTD| -5.832| -4.239| 5.286| 0| 0| -6.036| 7.689
RTD| -5.719| -4.238| 6.799| 0| 0| -6.036| 7.689
RTD| -5.164| -4.241| 6.147| 0| 0| -6.036| 7.689
RTD| -5.704| -4.271| 5.980| 0| 0| -6.036| 7.689
RTD| -5.659| -4.252| 4.008| 0| 0| -6.036| 7.689
RTD| -5.422| -4.270| 3.601| 0| 0| -6.036| 7.689
RTD| -5.033| -4.244| 5.464| 0| 0| -6.036| 7.689
RTD| -5.599| -4.255| 6.290| 0| 0| -6.036| 7.689
RTD| -5.844| -4.233| 5.909| 0| 0| -6.036| 7.689
RTD| -5.829| -4.246| 6.244| 0| 0| -6.036| 7.689
RTD| -5.226| -4.236| 3.805| 0| 0| -6.036| 7.689
RTD| -5.741| -4.213| 4.822| 0| 0| -6.036| 7.689
RTD| -5.004| -4.231| 3.398| 0| 0| -6.036| 7.689
RTD| -5.721| -4.277| 5.842| 0| 0| -6.036| 7.689
RTD| -5.095| -4.245| 6.205| 0| 0| -6.036| 7.689
RTD| -5.777| -4.270| 4.114| 0| 0| -6.036| 7.689
RTT| 00:00:22 (in-kernel periodic task, 1000 us period, priority 99)
RTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst
RTD| -5.394| -4.246| 8.788| 0| 0| -6.036| 8.788
RTD| -5.677| -4.195| 4.803| 0| 0| -6.036| 8.788
RTD| -5.715| -4.183| 5.942| 0| 0| -6.036| 8.788
RTD| -5.798| -4.256| 6.323| 0| 0| -6.036| 8.788
RTD| -4.904| -4.132| 3.240| 0| 0| -6.036| 8.788
RTD| -5.564| -4.200| 7.257| 0| 0| -6.036| 8.788
RTD| -5.779| -4.227| 4.143| 0| 0| -6.036| 8.788
RTD| -5.693| -4.237| 5.726| 0| 0| -6.036| 8.788
RTD| -5.572| -4.254| 6.375| 0| 0| -6.036| 8.788
RTD| -5.067| -4.142| 3.623| 0| 0| -6.036| 8.788
^C---|-----------|-----------|-----------|--------|------|-------------------------
RTS| -6.036| -4.235| 8.788| 0| 0| 00:00:32/00:00:32
[root@imx6q /xenomai/bin]#
[root@imx6q /xenomai/bin]# ./latency -t 2 -p 1000
== Sampling period: 1000 us
== Test mode: in-kernel timer handler
== All results in microseconds
warming up...
RTT| 00:00:01 (in-kernel timer handler, 1000 us period, priority 99)
RTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst
RTD| -8.207| -8.152| -6.869| 0| 0| -8.207| -6.869
RTD| -8.207| -8.094| -2.076| 0| 0| -8.207| -2.076
RTD| -8.205| -8.123| -2.359| 0| 0| -8.207| -2.076
RTD| -8.205| -8.105| -2.311| 0| 0| -8.207| -2.076
RTD| -8.195| -8.113| -2.102| 0| 0| -8.207| -2.076
RTD| -8.208| -8.119| -0.008| 0| 0| -8.208| -0.008
RTD| -8.203| -8.123| -2.276| 0| 0| -8.208| -0.008
RTD| -8.196| -8.111| -2.676| 0| 0| -8.208| -0.008
RTD| -8.209| -8.092| -1.744| 0| 0| -8.209| -0.008
RTD| -8.196| -8.111| -2.721| 0| 0| -8.209| -0.008
RTD| -8.204| -8.122| -0.729| 0| 0| -8.209| -0.008
RTD| -8.202| -8.119| -0.676| 0| 0| -8.209| -0.008
RTD| -8.202| -8.108| -2.487| 0| 0| -8.209| -0.008
RTD| -8.194| -8.104| -2.184| 0| 0| -8.209| -0.008
RTD| -8.202| -8.103| -1.919| 0| 0| -8.209| -0.008
RTD| -8.210| -8.125| -2.677| 0| 0| -8.210| -0.008
RTD| -8.205| -8.119| -0.187| 0| 0| -8.210| -0.008
RTD| -8.205| -8.117| -2.655| 0| 0| -8.210| -0.008
RTD| -8.208| -8.107| 0.115| 0| 0| -8.210| 0.115
RTD| -8.206| -8.123| -2.494| 0| 0| -8.210| 0.115
RTD| -8.193| -8.102| -2.380| 0| 0| -8.210| 0.115
RTT| 00:00:22 (in-kernel timer handler, 1000 us period, priority 99)
RTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst
RTD| -8.209| -8.118| -0.395| 0| 0| -8.210| 0.115
^C---|-----------|-----------|-----------|--------|------|-------------------------
RTS| -8.210| -8.114| 0.115| 0| 0| 00:00:23/00:00:23
[root@imx6q /xenomai/bin]#
[root@imx6q /xenomai/bin]#
[root@imx6q /xenomai/bin]# ./latency -t 0 -p 1000
== Sampling period: 1000 us
== Test mode: periodic user-mode task
== All results in microseconds
warming up...
RTT| 00:00:01 (periodic user-mode task, 1000 us period, priority 99)
RTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst
RTD| -3.043| -2.028| 0.108| 0| 0| -3.043| 0.108
RTD| -3.152| -1.927| 12.189| 0| 0| -3.152| 12.189
RTD| -3.013| -1.902| 9.260| 0| 0| -3.152| 12.189
RTD| -3.109| -1.935| 10.295| 0| 0| -3.152| 12.189
RTD| -3.006| -1.879| 12.530| 0| 0| -3.152| 12.530
RTD| -3.028| -1.947| 11.944| 0| 0| -3.152| 12.530
RTD| -3.175| -1.940| 11.242| 0| 0| -3.175| 12.530
RTD| -3.102| -1.975| 9.166| 0| 0| -3.175| 12.530
RTD| -3.104| -1.950| 12.343| 0| 0| -3.175| 12.530
RTD| -3.091| -1.958| 10.580| 0| 0| -3.175| 12.530
RTD| -3.089| -1.955| 11.234| 0| 0| -3.175| 12.530
RTD| -3.003| -1.973| 11.452| 0| 0| -3.175| 12.530
RTD| -3.086| -1.920| 8.444| 0| 0| -3.175| 12.530
RTD| -3.124| -1.925| 12.068| 0| 0| -3.175| 12.530
RTD| -3.185| -1.953| 12.439| 0| 0| -3.185| 12.530
RTD| -2.973| -1.955| 11.510| 0| 0| -3.185| 12.530
RTD| -3.079| -1.955| 11.401| 0| 0| -3.185| 12.530
RTD| -3.096| -1.955| 9.636| 0| 0| -3.185| 12.530
RTD| -3.056| -1.958| 10.664| 0| 0| -3.185| 12.530
RTD| -3.081| -1.877| 11.353| 0| 0| -3.185| 12.530
RTD| -2.958| -1.872| 11.348| 0| 0| -3.185| 12.530
RTT| 00:00:22 (periodic user-mode task, 1000 us period, priority 99)
RTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst
RTD| -3.099| -1.958| 11.406| 0| 0| -3.185| 12.530
RTD| -3.190| -1.917| 11.838| 0| 0| -3.190| 12.530
RTD| -3.104| -1.958| 12.045| 0| 0| -3.190| 12.530
RTD| -3.033| -1.940| 9.477| 0| 0| -3.190| 12.530
RTD| -2.980| -1.892| 11.714| 0| 0| -3.190| 12.530
^C---|-----------|-----------|-----------|--------|------|-------------------------
RTS| -3.190| -1.937| 12.530| 0| 0| 00:00:27/00:00:27
[root@imx6q /xenomai/bin]#
[root@imx6q /xenomai/bin]# ./latency -t 1 -p 1000
== Sampling period: 1000 us
== Test mode: in-kernel periodic task
== All results in microseconds
warming up...
RTT| 00:00:01 (in-kernel periodic task, 1000 us period, priority 99)
RTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst
RTD| -5.809| -4.296| -1.410| 0| 0| -5.809| -1.410
RTD| -5.299| -4.212| 7.689| 0| 0| -5.809| 7.689
RTD| -5.839| -4.229| 5.860| 0| 0| -5.839| 7.689
RTD| -6.036| -4.262| 6.257| 0| 0| -6.036| 7.689
RTD| -5.807| -4.261| 4.067| 0| 0| -6.036| 7.689
RTD| -5.832| -4.239| 5.286| 0| 0| -6.036| 7.689
RTD| -5.719| -4.238| 6.799| 0| 0| -6.036| 7.689
RTD| -5.164| -4.241| 6.147| 0| 0| -6.036| 7.689
RTD| -5.704| -4.271| 5.980| 0| 0| -6.036| 7.689
RTD| -5.659| -4.252| 4.008| 0| 0| -6.036| 7.689
RTD| -5.422| -4.270| 3.601| 0| 0| -6.036| 7.689
RTD| -5.033| -4.244| 5.464| 0| 0| -6.036| 7.689
RTD| -5.599| -4.255| 6.290| 0| 0| -6.036| 7.689
RTD| -5.844| -4.233| 5.909| 0| 0| -6.036| 7.689
RTD| -5.829| -4.246| 6.244| 0| 0| -6.036| 7.689
RTD| -5.226| -4.236| 3.805| 0| 0| -6.036| 7.689
RTD| -5.741| -4.213| 4.822| 0| 0| -6.036| 7.689
RTD| -5.004| -4.231| 3.398| 0| 0| -6.036| 7.689
RTD| -5.721| -4.277| 5.842| 0| 0| -6.036| 7.689
RTD| -5.095| -4.245| 6.205| 0| 0| -6.036| 7.689
RTD| -5.777| -4.270| 4.114| 0| 0| -6.036| 7.689
RTT| 00:00:22 (in-kernel periodic task, 1000 us period, priority 99)
RTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst
RTD| -5.394| -4.246| 8.788| 0| 0| -6.036| 8.788
RTD| -5.677| -4.195| 4.803| 0| 0| -6.036| 8.788
RTD| -5.715| -4.183| 5.942| 0| 0| -6.036| 8.788
RTD| -5.798| -4.256| 6.323| 0| 0| -6.036| 8.788
RTD| -4.904| -4.132| 3.240| 0| 0| -6.036| 8.788
RTD| -5.564| -4.200| 7.257| 0| 0| -6.036| 8.788
RTD| -5.779| -4.227| 4.143| 0| 0| -6.036| 8.788
RTD| -5.693| -4.237| 5.726| 0| 0| -6.036| 8.788
RTD| -5.572| -4.254| 6.375| 0| 0| -6.036| 8.788
RTD| -5.067| -4.142| 3.623| 0| 0| -6.036| 8.788
^C---|-----------|-----------|-----------|--------|------|-------------------------
RTS| -6.036| -4.235| 8.788| 0| 0| 00:00:32/00:00:32
[root@imx6q /xenomai/bin]#
[root@imx6q /xenomai/bin]# ./latency -t 2 -p 1000
== Sampling period: 1000 us
== Test mode: in-kernel timer handler
== All results in microseconds
warming up...
RTT| 00:00:01 (in-kernel timer handler, 1000 us period, priority 99)
RTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst
RTD| -8.207| -8.152| -6.869| 0| 0| -8.207| -6.869
RTD| -8.207| -8.094| -2.076| 0| 0| -8.207| -2.076
RTD| -8.205| -8.123| -2.359| 0| 0| -8.207| -2.076
RTD| -8.205| -8.105| -2.311| 0| 0| -8.207| -2.076
RTD| -8.195| -8.113| -2.102| 0| 0| -8.207| -2.076
RTD| -8.208| -8.119| -0.008| 0| 0| -8.208| -0.008
RTD| -8.203| -8.123| -2.276| 0| 0| -8.208| -0.008
RTD| -8.196| -8.111| -2.676| 0| 0| -8.208| -0.008
RTD| -8.209| -8.092| -1.744| 0| 0| -8.209| -0.008
RTD| -8.196| -8.111| -2.721| 0| 0| -8.209| -0.008
RTD| -8.204| -8.122| -0.729| 0| 0| -8.209| -0.008
RTD| -8.202| -8.119| -0.676| 0| 0| -8.209| -0.008
RTD| -8.202| -8.108| -2.487| 0| 0| -8.209| -0.008
RTD| -8.194| -8.104| -2.184| 0| 0| -8.209| -0.008
RTD| -8.202| -8.103| -1.919| 0| 0| -8.209| -0.008
RTD| -8.210| -8.125| -2.677| 0| 0| -8.210| -0.008
RTD| -8.205| -8.119| -0.187| 0| 0| -8.210| -0.008
RTD| -8.205| -8.117| -2.655| 0| 0| -8.210| -0.008
RTD| -8.208| -8.107| 0.115| 0| 0| -8.210| 0.115
RTD| -8.206| -8.123| -2.494| 0| 0| -8.210| 0.115
RTD| -8.193| -8.102| -2.380| 0| 0| -8.210| 0.115
RTT| 00:00:22 (in-kernel timer handler, 1000 us period, priority 99)
RTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst
RTD| -8.209| -8.118| -0.395| 0| 0| -8.210| 0.115
^C---|-----------|-----------|-----------|--------|------|-------------------------
RTS| -8.210| -8.114| 0.115| 0| 0| 00:00:23/00:00:23
[root@imx6q /xenomai/bin]#
------------------------------------------------------------------
UART, I2C, SPI, PWM, CAN, Ethernet, USB, SDIO, SATA, CAM, HDMI, 2D/3D Video 및 4개 1GHz 코어와 hardware-FPU를 탑재한 원칩 SoC에서 SMP를 지원하는 RTOS가 불과 1W 언저리에서 돌아간다... 우와, 막강이구먼.
안되는 제어가 없겠다.
어디에 쓰면 좋을까?
오래된 비디오폰 수리 및 컬러 LCD 개조
살고 있는 아파트에 20년이 넘은 비디오폰이 설치되어 있다.
당시에는 상당히 획기적이고 고가의 장비였을 것이다.
그 당시를 살아보지 않은 사람이라 잘 모른다. 크크크...
현관 카메라는 흑백이며, 비디오 디스플레이도 역시 흑백에 무려 브라운관 모니터.
고장이난듯 동작도 하지 않고 누렇게 변색된채로 거실벽에 큼지막하게 자리를 차지하고 있어 미관상 좋지도 않다. 하다 못해 외부 카메라 만이라도 동작해주면 좋으련만...
그래서 컬러 카메라에 LCD 모니터를 달아주는 개조를 해보기로 했다. 개조와 더불어 수리가 가능한 부분이 있으면 수리도 해주었다.
뜯기전 사진을 찍지 않았는데 대충 분위기가 위 사진과 같다. 우리집은 벽지가 하얀색이라 누렇게 변색된게 나이 많이 먹은걸 그대로 보여주고 있었다.
수리 및 개조를 하려면 일단 뜯는다.
배선이 예상했던 것보다 무지하게 복잡하다. 신형으로 설치된 인터폰 배선과 얽혀있어 더 복잡해 보인다. NTSC용 동축 케이블을 제외하고 나머지는 모두 같은 종류의 선재를 사용해 구분이 되지도 않는다. 모든 선마다 라벨을 붙여주고 뜯어 낸다.
현관 밖에 설치되어 있는 카메라를 뜯어봤다. 카메라가 동작 되는지 전원 넣고 별도 모니터로 확인해 보니 게슴츠레 흑백 영상이 나오는가 싶더니 이내 화면이 깨지고 지글지글거린다. 다행히 카메라 모듈과 음성 모듈이 분리되어 있어 작업이 수월 했다. 기존에 붙어 있는 흑백 카메라 모듈을 들어 내고 컬러 카메라를 달아 준다.
일전에 아파트 CCTV 교체하면서 버려 놓은 카메라를 주워 놓았던걸 재 사용했다. 아파트 현관 천장에 반구 모양으로 달려있는 그 카메라에서 뜯은 것이다. 렌즈만 닦아 주니 잘 나오는데 왜 교체를 했는지 모르겠다. HD급으로 바뀌었나?...
여튼 아래와 같이 달아 준다.
비디오폰 본체에는 아래 사진과 같이 상당히 컴팩트하게 잘 만들어진 브라운관 모니터가 달려 있다. 브라운관 모니터를 그 작은 공간에 잘 우겨 넣었다. 역시 공돌이들은 대단해...
컬러 LCD 모니터는 비디오폰 연령대에 맞춰 'GoldStar' 할아버지를 달아 줬다. 그래도 나이대가 맞아야 잘 어울리겠지 하는 마음에서다.
LCD모니터는 오래된 캠코더에 모니터용으로 달려있던 것이다. 최근 기종을 달아 주려고 했으나 최근 LCD 모니터는 전원 및 입력 소스 선택이 리모컨 방식이거나 소프트 스위치 방식이라 전원이 들어 가자 마자 바로 동작 해야 하는 비디오폰 모니터 용도로 사용하기에 적합하지가 않다.
다만 좀 아쉬운건 LCD 크기가 작다는거...
이제 모두 가조립 하고 배선연결 후 동작 시험을 해본다.
잘 되는군...
어렸을적 내가 그림을 좀 잘 그렸었다.
잘 되는 것을 확인 했으니 다시 달아 준다.
달아 주기 전에 비디오폰 프레임을 모두 탈거하여 세제로 다시 닦아 준다. 닦아 주고 나니 누런끼가 살짝 줄어 들면서 좀 나아 졌다.
조립은 분해의 역순.
볼트가 몇개 남아도 당황하지 말고 침착하게 처음부터 다시...
당시에는 상당히 획기적이고 고가의 장비였을 것이다.
그 당시를 살아보지 않은 사람이라 잘 모른다. 크크크...
현관 카메라는 흑백이며, 비디오 디스플레이도 역시 흑백에 무려 브라운관 모니터.
고장이난듯 동작도 하지 않고 누렇게 변색된채로 거실벽에 큼지막하게 자리를 차지하고 있어 미관상 좋지도 않다. 하다 못해 외부 카메라 만이라도 동작해주면 좋으련만...
그래서 컬러 카메라에 LCD 모니터를 달아주는 개조를 해보기로 했다. 개조와 더불어 수리가 가능한 부분이 있으면 수리도 해주었다.
[참고 이미지]
뜯기전 사진을 찍지 않았는데 대충 분위기가 위 사진과 같다. 우리집은 벽지가 하얀색이라 누렇게 변색된게 나이 많이 먹은걸 그대로 보여주고 있었다.
수리 및 개조를 하려면 일단 뜯는다.
[비디오폰 탈거]
배선이 예상했던 것보다 무지하게 복잡하다. 신형으로 설치된 인터폰 배선과 얽혀있어 더 복잡해 보인다. NTSC용 동축 케이블을 제외하고 나머지는 모두 같은 종류의 선재를 사용해 구분이 되지도 않는다. 모든 선마다 라벨을 붙여주고 뜯어 낸다.
[비디오폰 본체]
[비디오폰 본체 메인보드]
[비디오폰 본체 단자대]
[현관 설치 카메라]
현관 밖에 설치되어 있는 카메라를 뜯어봤다. 카메라가 동작 되는지 전원 넣고 별도 모니터로 확인해 보니 게슴츠레 흑백 영상이 나오는가 싶더니 이내 화면이 깨지고 지글지글거린다. 다행히 카메라 모듈과 음성 모듈이 분리되어 있어 작업이 수월 했다. 기존에 붙어 있는 흑백 카메라 모듈을 들어 내고 컬러 카메라를 달아 준다.
[컬러 카메라 모듈]
일전에 아파트 CCTV 교체하면서 버려 놓은 카메라를 주워 놓았던걸 재 사용했다. 아파트 현관 천장에 반구 모양으로 달려있는 그 카메라에서 뜯은 것이다. 렌즈만 닦아 주니 잘 나오는데 왜 교체를 했는지 모르겠다. HD급으로 바뀌었나?...
여튼 아래와 같이 달아 준다.
[카메라 모듈 교체]
비디오폰 본체에는 아래 사진과 같이 상당히 컴팩트하게 잘 만들어진 브라운관 모니터가 달려 있다. 브라운관 모니터를 그 작은 공간에 잘 우겨 넣었다. 역시 공돌이들은 대단해...
[흑백 브라운관 모니터]
컬러 LCD 모니터는 비디오폰 연령대에 맞춰 'GoldStar' 할아버지를 달아 줬다. 그래도 나이대가 맞아야 잘 어울리겠지 하는 마음에서다.
[비디오폰과 비슷한 연세로 보이는 컬러 LCD 모니터]
LCD모니터는 오래된 캠코더에 모니터용으로 달려있던 것이다. 최근 기종을 달아 주려고 했으나 최근 LCD 모니터는 전원 및 입력 소스 선택이 리모컨 방식이거나 소프트 스위치 방식이라 전원이 들어 가자 마자 바로 동작 해야 하는 비디오폰 모니터 용도로 사용하기에 적합하지가 않다.
다만 좀 아쉬운건 LCD 크기가 작다는거...
이제 모두 가조립 하고 배선연결 후 동작 시험을 해본다.
[비디오폰 및 카메라 연동 시험]
[카메라 연동 확인]
잘 되는군...
어렸을적 내가 그림을 좀 잘 그렸었다.
잘 되는 것을 확인 했으니 다시 달아 준다.
달아 주기 전에 비디오폰 프레임을 모두 탈거하여 세제로 다시 닦아 준다. 닦아 주고 나니 누런끼가 살짝 줄어 들면서 좀 나아 졌다.
[재 장착]
[현관 카메라 모니터]
조립은 분해의 역순.
볼트가 몇개 남아도 당황하지 말고 침착하게 처음부터 다시...
Pure Single Precision Math-Library
써 놓고 보니 제목이 그럴싸하다.
ARM Cortex-M4 코어가 들어가는 STM32F429 보드를 가지고 놀던중 수학함수(sin(), cos(), sqrt() 등등)를 사용할 필요가 있어 sin() 함수를 호출 했더니 CPU가 죽는다.
Cortex-M4 FPU는 double precision을 지원 하지 않는 다는걸 알았다. 그래서 이번엔 sinf()를 호출 해 봤더니 역시 또 CPU가 죽는다.
나는 보통 Embedded System용 툴체인은 직접 빌드해서 사용한다. 내가 만든 툴체인에 문제가 있나 싶어 FPU관련 옵션을 이리저리 바꿔가면서 툴체인을 다시 빌드해봤으나 역시 증상이 동일 하다. 해본 사람은 알겠지만 툴체인 한번 빌드하는데 적게는 30분에서 많게는 2~3시간이 걸린다. 더 많은 옵션으로 테스트를 해보고 싶지만 툴체인 빌드하느라 시간을 다 까먹고 있어서 툴체인 빌드 삽질을 중지 하고 수학함수(libm) 소스를 열어 봤다. arm-unknown-eabihf(bare-metal)로 빌드 할 경우 newlib가 사용되고 arm-unknown-linux-gnueabihf로 빌드 할 경우 glibc가 사용된다(툴체인 뒤에 붙는 hf는 hardware FPU라는 뜻임). newlib의 경우 수학함수가 모두 double precision으로만 빌드 되고 sinf()나 cosf()와 같은 single precision 함수는 껍데기만 single precision일뿐 정작 함수 내부 구현시 double precision을 사용한다. 그러니 CPU가 죽을 수 밖에...
glibc소스 확인 결과 삼각함수나 sqrtf(), powf()등은 함수 이름에 걸맞게 내부 구현도 pure single precision으로 구현되어 있었다. 그런데 왜 CPU가 죽는 것일까? 툴체인 빌드시 명확하게 single precision으로만 수학 함수가 빌드되도록 옵션을 설정 해야 한다. 또한 gcc 버전이 올라 갈 수록 하위 호환이 필요한 함수들의 경우 실제 테스트를 해보지 않는 이상 잠정적인 버그로 남아 있을 수 있다. 실제로 ARMv4로 빌드 옵션을 주고 컴파일 해도 최근 gcc의 경우 ARMv7로만 빌드 되는 경우도 있다. 아마 낮은 버전의 gcc와 glibc의 조합을 이용하면 Cortex-M4용 수학함수 툴체인을 만들 수 있을 것이나, 시간 소모가 많다.
이번 문제는 툴체인을 다시 빌드하지 않고 필요한 수학 함수를 소스 수준에서 포팅하여 완전한 'pure single precision'으로 빌드 하여 사용하기로 하였다.
openlibm, fdlibm, glibc, yeppp등을 검토하여봤다. openlibm의 경우 ***f()함수는 대부분 single precision으로 구성되어 있으나 삼각함수는 double precision으로만 구현되어 적용이 불가 하였다. sinf(), cosf()등이 있으나 함수 껍데기만 float이고 내부 상수 및 수치 연산은 모두 double로 구성되어 있었다. fdlibm은 오직 double precision만 사용 가능하다(readme에 언급되어 있음). yeppp의 경우 소스크기가 큰편이라 자세히 보지 못했다. architecture별로 FPU사용에 최적화가 되어 사용시 큰 잇점이 있을 것으로 보이나 일반적인 libm 형태 소스 구성이 아니라 분석하는데 시간이 걸려 pass함(나중에 속도 최적화시 다시 봐야 할거 같다). 마지막으로 glibc는 대부분 내가 필요로 하는 함수는 single precision으로 구현되어 있었다. 역시 구관이 명관이라... glibc의 libm중에도 expf()와 같은 일부 함수는 내부에 double precision 연산이 들어가 있는 것도 있었다. glibc 버전중에 찾아보면 single precision으로 구현된 소스가 있을 텐데 일단 지금은 필요한 함수가 아니라 우선 아래 함수만 포팅하여 사용하였다.
- sqrtf()
- sinf()
- cosf()
- tanf()
- asinf()
- acosf()
- atanf()
- atan2f()
pure single precision으로 구성한 소스를 첨부합니다. 필요하신 분은 가져다 활용 하시기 바랍니다. libm 소스는 glibc-2.21에서 발췌 하였습니다. 첨부된 소스 이외 의존성은 없습니다. standalone으로 빌드하여 사용 하시면 됩니다. *.c 파일은 프로젝트에 포함 시켜서 빌드하면 되고 사용시 math.h 헤더파일만 포함하여 사용 하면 됩니다.
IEEE754(부동 소숫점 연산 표준) 함수를 발췌 하여 사용하였으므로 각 architecture별 FPU가 가지고 있는 최대 성능이 나오지 않을 수 있습니다.
소스다운로드
ARM Cortex-M4 코어가 들어가는 STM32F429 보드를 가지고 놀던중 수학함수(sin(), cos(), sqrt() 등등)를 사용할 필요가 있어 sin() 함수를 호출 했더니 CPU가 죽는다.
Cortex-M4 FPU는 double precision을 지원 하지 않는 다는걸 알았다. 그래서 이번엔 sinf()를 호출 해 봤더니 역시 또 CPU가 죽는다.
나는 보통 Embedded System용 툴체인은 직접 빌드해서 사용한다. 내가 만든 툴체인에 문제가 있나 싶어 FPU관련 옵션을 이리저리 바꿔가면서 툴체인을 다시 빌드해봤으나 역시 증상이 동일 하다. 해본 사람은 알겠지만 툴체인 한번 빌드하는데 적게는 30분에서 많게는 2~3시간이 걸린다. 더 많은 옵션으로 테스트를 해보고 싶지만 툴체인 빌드하느라 시간을 다 까먹고 있어서 툴체인 빌드 삽질을 중지 하고 수학함수(libm) 소스를 열어 봤다. arm-unknown-eabihf(bare-metal)로 빌드 할 경우 newlib가 사용되고 arm-unknown-linux-gnueabihf로 빌드 할 경우 glibc가 사용된다(툴체인 뒤에 붙는 hf는 hardware FPU라는 뜻임). newlib의 경우 수학함수가 모두 double precision으로만 빌드 되고 sinf()나 cosf()와 같은 single precision 함수는 껍데기만 single precision일뿐 정작 함수 내부 구현시 double precision을 사용한다. 그러니 CPU가 죽을 수 밖에...
glibc소스 확인 결과 삼각함수나 sqrtf(), powf()등은 함수 이름에 걸맞게 내부 구현도 pure single precision으로 구현되어 있었다. 그런데 왜 CPU가 죽는 것일까? 툴체인 빌드시 명확하게 single precision으로만 수학 함수가 빌드되도록 옵션을 설정 해야 한다. 또한 gcc 버전이 올라 갈 수록 하위 호환이 필요한 함수들의 경우 실제 테스트를 해보지 않는 이상 잠정적인 버그로 남아 있을 수 있다. 실제로 ARMv4로 빌드 옵션을 주고 컴파일 해도 최근 gcc의 경우 ARMv7로만 빌드 되는 경우도 있다. 아마 낮은 버전의 gcc와 glibc의 조합을 이용하면 Cortex-M4용 수학함수 툴체인을 만들 수 있을 것이나, 시간 소모가 많다.
이번 문제는 툴체인을 다시 빌드하지 않고 필요한 수학 함수를 소스 수준에서 포팅하여 완전한 'pure single precision'으로 빌드 하여 사용하기로 하였다.
openlibm, fdlibm, glibc, yeppp등을 검토하여봤다. openlibm의 경우 ***f()함수는 대부분 single precision으로 구성되어 있으나 삼각함수는 double precision으로만 구현되어 적용이 불가 하였다. sinf(), cosf()등이 있으나 함수 껍데기만 float이고 내부 상수 및 수치 연산은 모두 double로 구성되어 있었다. fdlibm은 오직 double precision만 사용 가능하다(readme에 언급되어 있음). yeppp의 경우 소스크기가 큰편이라 자세히 보지 못했다. architecture별로 FPU사용에 최적화가 되어 사용시 큰 잇점이 있을 것으로 보이나 일반적인 libm 형태 소스 구성이 아니라 분석하는데 시간이 걸려 pass함(나중에 속도 최적화시 다시 봐야 할거 같다). 마지막으로 glibc는 대부분 내가 필요로 하는 함수는 single precision으로 구현되어 있었다. 역시 구관이 명관이라... glibc의 libm중에도 expf()와 같은 일부 함수는 내부에 double precision 연산이 들어가 있는 것도 있었다. glibc 버전중에 찾아보면 single precision으로 구현된 소스가 있을 텐데 일단 지금은 필요한 함수가 아니라 우선 아래 함수만 포팅하여 사용하였다.
- sqrtf()
- sinf()
- cosf()
- tanf()
- asinf()
- acosf()
- atanf()
- atan2f()
pure single precision으로 구성한 소스를 첨부합니다. 필요하신 분은 가져다 활용 하시기 바랍니다. libm 소스는 glibc-2.21에서 발췌 하였습니다. 첨부된 소스 이외 의존성은 없습니다. standalone으로 빌드하여 사용 하시면 됩니다. *.c 파일은 프로젝트에 포함 시켜서 빌드하면 되고 사용시 math.h 헤더파일만 포함하여 사용 하면 됩니다.
IEEE754(부동 소숫점 연산 표준) 함수를 발췌 하여 사용하였으므로 각 architecture별 FPU가 가지고 있는 최대 성능이 나오지 않을 수 있습니다.
소스다운로드
2016/02/10~2/14 두번째 괌여행
두번째로 괌을 다녀왔다.
이번엔 지난번 가보지 못했던 괌섬 남부 이나라한 자연 풀장도 가봤다.
자연 형성된 잔잔한 바다 풀장에 사람들은 물놀이 삼매경이지만 풀장 바로 앞
불과 10미터 바깥쪽은 사람 키보다 더 큰 파도가 굉장하게 일고 있었다.
여행가기전 괌 숙박 호텔의 95%가 예약이 끝나있었다.
도대체 문슨일인가 싶었는데 발렌타인데이가 주말휴일 끼어 있다보니
호텔 예약이 불가능했었다.
홈페이지에서 한글 지원을 하지 않거나 통합 호텔 예약 사이트(앱)등에서 검색되지 않는
콘도를 찾아 매니저와 메일로 직접 컨택하여 겨우 구할 수 있었다.
이번엔 지난번 가보지 못했던 괌섬 남부 이나라한 자연 풀장도 가봤다.
자연 형성된 잔잔한 바다 풀장에 사람들은 물놀이 삼매경이지만 풀장 바로 앞
불과 10미터 바깥쪽은 사람 키보다 더 큰 파도가 굉장하게 일고 있었다.
여행가기전 괌 숙박 호텔의 95%가 예약이 끝나있었다.
도대체 문슨일인가 싶었는데 발렌타인데이가 주말휴일 끼어 있다보니
호텔 예약이 불가능했었다.
홈페이지에서 한글 지원을 하지 않거나 통합 호텔 예약 사이트(앱)등에서 검색되지 않는
콘도를 찾아 매니저와 메일로 직접 컨택하여 겨우 구할 수 있었다.
네비게이션 기기(UB-5)에 임베디드 리눅스 올리기
쓰레기통에 버려진 네비게이션 기기를 하나 주웠다.
현대유비스 UB-5라는 모델인데 동작은 하는듯 보였다.
[현대유비스 UB-5]
외부 NTSC 카메라 입력 기능이 있어 영상처리쪽 공부나좀 해볼겸 해서 영상처리용 테스트 보드로 만들어 보기로 했다.
뭐든 시작은 배를 따는것 부터 한다.
배 따고 EMI차폐용 철판 들어내 보니 ARM1176기반의 삼성 S3C6410 ARM 프로세서가 들어가 있었다. 아주 오래전에 잠깐 써본적이 있는 놈이라 좀 수월 할 듯 해보인다.
보드 여기저기 JTAG이나 콘솔/디버그 UART용으로 할당 되어 있을 법한 커넥터나 PCB 패턴들을 들쑤셔 찾아낸다.
JTAG용으로 할당된 PCB패던 뭉치를 찾아내 자작해서 쓰고 있던 'JTAG 핀 분석기'를 물리고 핀맵을 찾아 낸다. 콘솔용 UART 패턴도 찾아내어 기본 펌웨어에서 뭐라그러는지 함 봐준다. 기본 펌웨어에서 뿌려주는 메시지중에 일부는 리버스엔지니어링시 중요한 정보나 단서를 제공 할 수 있으니 예의상 함 읽어봐 주고 저장해 놓는다.
역시 자작해서 쓰고 있는 'USB-JTAG'하드웨어를 물려주고 S3C6410용 OpenOCD 스크립트를 입수해 CPU 제어권을 잡아 본다. 역시 툴이 좋으니 일사천리로 일이 된다. 움하하...
기본 저장된 펌웨어를 모조리 덤프받아 백업해 놓고 자작한 부트로더를 올린다.
자작한 부트로더가 일단 올라가면 JTAG연동은 필요 없으니 외부에 콘솔용 UART포트만 뽑아 준다.
[콘솔용 UART포트 인출]
보드에 USB-OTG 커넥터가 부착되어 있으나 케이스에 구멍이 없어 구멍도 같이 뚫어 주었다. 리눅스 커널 보낼려면 필요하다.
아주 손쉽게(?) S3C6410 기반의 UB-5 보드용 임베디드 리눅스 커널을 빌드하고 파일시스템 꾸며주고 런타임라이브러리 올려주고 등등 작업후 부팅해본다.
[리눅스 커널 포팅 및 부팅 확인]
잘 되는군....
터치스크린 사용을 위해 tslib를 올려 캘리브레이션을 해본다.
[tslib포팅 및 캘리브레이션]
터치 캘리브레이션 했으니 되는지 확인해 본다.
[터치스크린 테스트]
역시 잘 되는군...
CPU 성능이 좋으니 이번엔 SDL대신 QTE를 올려봤다.
QTE 런타임 라이브러리 용량이 줄이고 줄여도 약 30MB정도로 상당하다. 임베디드 환경에서 30MB는 좀 큰 편이다.
내장된 1GB NAND를 파티셔닝해서 tslib와 QTE 런타임라이브러리를 올리고 리눅스 부팅시 마운팅되도록 한다.
[QT 어플리케이션 테스트]
tslib에서 캘리브레이션된 데이터와 연동되어 QT에서 위치도 잘 잡힌다.
역시 잘된다.
모든게 순조롭다. 난 역시 대단해. 움하하...
이제 내장된 NTSC 디코더 칩을 사용해봐야 한다. 리눅스 커널에서 잘 잡히질 않는다.
다시 배 따고 디코더 칩 외부 IO가 정상적인지 스코프로 확인해 본다.
전원도 잘 들어가고 I2C 신호는 뜨는데 I2C 통신에 응답을 하지 않는다.
근처에 있는 음원칩에 대해서도 I2C가 응답을 하지 않는다. 뭐지??
모든 어드레스에 대해 I2C 스캔을 해봤는데 엉뚱한 어드레스에서 응답을 한다.
뭔가 했더니 CPU 옆에 붙어있던 DMB 수신 칩에서 응답을 한 모양이다.
DMB 수신칩 데이터 시트가 없어 관심이 없었는데 요놈이 응답을 하는걸 보니 I2C버스도 잘 동작하는듯 한다. 그런데 비디오/오디오 칩만 응답을 하지 않는다.
카메라 연동이 되어야 영상처리용 테스트 보드가 되는데...
UB-5 네비게이터 메뉴얼을 찬찬히 보니 외부 AV입력단자가 있고 영상과 음성을 4핀용 오디오 잭으로 받고 있도록 구성되어있다.
외부 AV입력 핀에서 유입된 신호로 비디오와 오디오 칩이 파손된 듯 하다.
AV가 안되서 버린 물건인듯 하다.
원본 롬으로 복원해서 진짜로 안되는지 확인해 봐야 하는데, 아...
귀찮다.
그냥 고장난걸로 보고 포팅된 리눅스나 가지고 놀아야 겠다.
Open Source 기반 FLCC-HILS 환경 구축
간만의 글이다.
이번엔 오픈소스기반의 소프트웨어들을 이용해 FLCC (Flight Control Computer) 하드웨어를 적용한 HILS (Hardware In the Loop Simulation) 환경을 구축해 간단한 항공기 제어를 해봤다.
용어가 생소한 분을 위해 간략히 소개를 하자면 FLCC는 조종사의 스틱 명령을 전달 받아 Actuator를 이용해 항공기의 조종면을 움직이는 명령을 생성하고 때에 따라서는 Autopilot 기능을 수행하거나 항공기의 안정적인 자세제어를 위한 역할을 수행하기도 한다. 컴퓨터로 제어하는 요즘 항공기에는 대부분 들어가게 되며 Fly-By-Wire 시스템을 위한 중요한 요소이다.
HILS는 시뮬레이션 환경을 말한다. 시뮬레이션이라면 소프트웨어 기반으로만 생각 할 수 있으나 실제 장착되는 장비를 시뮬레이션 루프안에 포함시켜 실제 하드웨어 장비의 동작을 검증하기 위한 목적으로 수행하기도 하는데 이를 HILS라 부른다.
우선 사용한 오픈소스 및 적용 하드웨어는 다음과 같다.
- FDM : JSBSim
- Visualizer : FlightGear
- Application : QT
- FLCC RTOS : Embedded Linux-Xenomai
- FLCC H/W : PXA270 (ARMv5, 520MHz)
- Comm. : Realtime Ethernet (UDP/IP)
각 부분별 소프트웨어 소개를 잠깐 하자면 JSBSim은 항공기 공력 시뮬레이션을 위한 물리엔진이다. 흔히 FDM (Flight Dynamic Model)이라고 하는데 항공기의 공력 파라미터인 무게, 관성, 양력계수, 항력계수 등을 xml형태로 전달 하고 항공기 제어 파라미터인 엔진 추력, 조종면 위치 각등을 입력하면 항공기의 속도, 위치, 고도, 자세등을 알려주는 오픈소스 기반 소프트웨어 이다.
FlightGear는 3D 가시화 툴로 JSBSim에서 출력된 비행체 정보를 바탕으로 지리정보 (GIS - Geographic Information System)와 함께 지형지물과 항공기, HUD등을 그려주는 역할을 한다. JSBSim 자체는 이런 가시화 툴을 제공하지 않기에 항공기 제어 결과를 3D 그래픽으로 확인 하고자 한다면 필요한 툴이다. 역시 오픈소스이며 전세계 공항 정보와 많은 항공기 모델을 가지고 있다.
FlightGear를 설치하면 JSBSim도 같이 설치되며 별도 지정을 하지 않으면 JSBSim을 기본 FDM으로 사용하게 된다. FlightGear와 연동하여 사용 가능한 FDM은 JSBSim 말고도 YASim이 있는데 둘의 차이라면 JSBSim은 항공기의 양력계수, 항력계수등 공력 파라미터를 입력 받는 반면 YASim은 항공기의 기하학 (Geometric) 정보인 날개 면적, 코드 길이, 조종면 면적, 동체 길이등을 직접 입력 받아 공력 물리엔진 연산을 수행한다.
QT는 그래픽 어플리케이션 개발용 라이브러리이며 역시 오픈소스이다. IDE 기능까지 포함하고 있어 MS의 비주얼 스튜디오와 같다고 보면 된다. 그러나 윈도우즈 뿐만 아니라 리눅스나 맥 OS에서도 사용 가능하며 심지어 리눅스기반의 임베디드 시스템에도 포팅하여 사용 가능하다. 꼭 그랙픽 관련 어플리케이션 뿐만 아니라 콘솔 기반 응용 프로그램도 작성 가능하다. 그래픽관련 라이브러리 뿐만 아니라 Multi-thread, Network등 많은, 그리고 유용한 라이브러리도 제공한다.
QT를 소개하는 이유는 FLCC측 비행 제어 어플리케이션 개발시 처음부터 FLCC하드웨어를 사용하지 않고 FlightGear가 동작하는 호스트 PC에서 Native 개발 환경으로 빠르게 동작 확인을 해볼 수 있다는 점 때문이다.
Native 개발 환경에서 동작이 확인 되면 별다른 소스 수정없이 바로 FLCC 타겟에 사용 가능 하다. 물론 Native OS가 비실시간 운영체제라면 실시간 태스크 관련 코드는 수정이 좀 필요할 것이다.
마지막으로 FLCC 하드웨어에서 사용할 RTOS인 Xenomai이다.
리눅스 기반의 실시간 커널 패치로 이전 글에서 많이 소개 되었다.
항공기 실시간 제어를 위해 FLCC 하드웨어에는 Embedded Linux-Xenomai를 사용했다.
항공기를 제어 시뮬레이션을 수행 하려면 FDM으로 부터 계산된(시뮬레이션된) 항공기 자세정보가 필요하며 제어 루프에 의해 계산된 출력물인 엔진 추력, 조종면 각도값은 다시 FDM으로 주입하여 일련의 되먹임 (Feedback) 제어루프가 형성 되어야 한다.
다행히 FlightGear에는 UDP/IP 및 RS-232통신라인을 이용해 이런 일련의 데이터 흐름을 만들 수 있는 기능이 있다.
해외 자료들 뒤져 보니 실 기체 개발시 HILS용으로 FlightGear를 많이 사용하는가 보다.
제어 루프는 RTOS기반의 FLCC 하드웨어에서 수행 하도록 구성하면 된다.
전체 시스템 구성을 보자면 아래 그림과 같다.
사용한 FLCC 하드웨어는 일전에 EtherCONN 개발시 사용한 PXA270기반 보드를 사용했다 (링크참조).
Linux-Xenomai가 이미 포팅되어 있고 UDP/IP 통신을 위한 Ethernet용 실시간 디바이스 드라이버 (RTDM)가 만들어져 있으니 바로 활용 가능 하였다.
개발시에는 [그림 1]과 같이 Native 환경에서 개발을 진행 하고 얼추 결과가 나오면 [그림 2]와 같이 실제 FLCC 하드웨어에 제어 코드를 이식해 사용 하면 된다.
HILS 환경을 구축하고 간단하게 항공기의 롤 및 피치 제어용 Auto-pilot을 구현해 돌려 봤다. 아래 동영상 결과는 실제 FLCC 하드웨어로 제어하는 모습이다.
[영상 1]은 롤/피치 제어용 Auto-pilot기능이 없는 순수 비행 화면이다.
비행 조종은 게임 패드의 조이스틱을 사용했으며 트림을 사용하지 않고 조종하는 모습이다.
조종사가 아니다 보니 항공기 조종하는게 생각 보다 어렵다.
[영상 2]는 롤/피치 제어용 Auto-pilot의 도움을 받아 비행하는 모습니다. 아케이드 게임하는 것처럼 조종하기가 참 수월해진다.
이번엔 오픈소스기반의 소프트웨어들을 이용해 FLCC (Flight Control Computer) 하드웨어를 적용한 HILS (Hardware In the Loop Simulation) 환경을 구축해 간단한 항공기 제어를 해봤다.
용어가 생소한 분을 위해 간략히 소개를 하자면 FLCC는 조종사의 스틱 명령을 전달 받아 Actuator를 이용해 항공기의 조종면을 움직이는 명령을 생성하고 때에 따라서는 Autopilot 기능을 수행하거나 항공기의 안정적인 자세제어를 위한 역할을 수행하기도 한다. 컴퓨터로 제어하는 요즘 항공기에는 대부분 들어가게 되며 Fly-By-Wire 시스템을 위한 중요한 요소이다.
HILS는 시뮬레이션 환경을 말한다. 시뮬레이션이라면 소프트웨어 기반으로만 생각 할 수 있으나 실제 장착되는 장비를 시뮬레이션 루프안에 포함시켜 실제 하드웨어 장비의 동작을 검증하기 위한 목적으로 수행하기도 하는데 이를 HILS라 부른다.
우선 사용한 오픈소스 및 적용 하드웨어는 다음과 같다.
- FDM : JSBSim
- Visualizer : FlightGear
- Application : QT
- FLCC RTOS : Embedded Linux-Xenomai
- FLCC H/W : PXA270 (ARMv5, 520MHz)
- Comm. : Realtime Ethernet (UDP/IP)
각 부분별 소프트웨어 소개를 잠깐 하자면 JSBSim은 항공기 공력 시뮬레이션을 위한 물리엔진이다. 흔히 FDM (Flight Dynamic Model)이라고 하는데 항공기의 공력 파라미터인 무게, 관성, 양력계수, 항력계수 등을 xml형태로 전달 하고 항공기 제어 파라미터인 엔진 추력, 조종면 위치 각등을 입력하면 항공기의 속도, 위치, 고도, 자세등을 알려주는 오픈소스 기반 소프트웨어 이다.
FlightGear는 3D 가시화 툴로 JSBSim에서 출력된 비행체 정보를 바탕으로 지리정보 (GIS - Geographic Information System)와 함께 지형지물과 항공기, HUD등을 그려주는 역할을 한다. JSBSim 자체는 이런 가시화 툴을 제공하지 않기에 항공기 제어 결과를 3D 그래픽으로 확인 하고자 한다면 필요한 툴이다. 역시 오픈소스이며 전세계 공항 정보와 많은 항공기 모델을 가지고 있다.
FlightGear를 설치하면 JSBSim도 같이 설치되며 별도 지정을 하지 않으면 JSBSim을 기본 FDM으로 사용하게 된다. FlightGear와 연동하여 사용 가능한 FDM은 JSBSim 말고도 YASim이 있는데 둘의 차이라면 JSBSim은 항공기의 양력계수, 항력계수등 공력 파라미터를 입력 받는 반면 YASim은 항공기의 기하학 (Geometric) 정보인 날개 면적, 코드 길이, 조종면 면적, 동체 길이등을 직접 입력 받아 공력 물리엔진 연산을 수행한다.
QT는 그래픽 어플리케이션 개발용 라이브러리이며 역시 오픈소스이다. IDE 기능까지 포함하고 있어 MS의 비주얼 스튜디오와 같다고 보면 된다. 그러나 윈도우즈 뿐만 아니라 리눅스나 맥 OS에서도 사용 가능하며 심지어 리눅스기반의 임베디드 시스템에도 포팅하여 사용 가능하다. 꼭 그랙픽 관련 어플리케이션 뿐만 아니라 콘솔 기반 응용 프로그램도 작성 가능하다. 그래픽관련 라이브러리 뿐만 아니라 Multi-thread, Network등 많은, 그리고 유용한 라이브러리도 제공한다.
QT를 소개하는 이유는 FLCC측 비행 제어 어플리케이션 개발시 처음부터 FLCC하드웨어를 사용하지 않고 FlightGear가 동작하는 호스트 PC에서 Native 개발 환경으로 빠르게 동작 확인을 해볼 수 있다는 점 때문이다.
Native 개발 환경에서 동작이 확인 되면 별다른 소스 수정없이 바로 FLCC 타겟에 사용 가능 하다. 물론 Native OS가 비실시간 운영체제라면 실시간 태스크 관련 코드는 수정이 좀 필요할 것이다.
마지막으로 FLCC 하드웨어에서 사용할 RTOS인 Xenomai이다.
리눅스 기반의 실시간 커널 패치로 이전 글에서 많이 소개 되었다.
항공기 실시간 제어를 위해 FLCC 하드웨어에는 Embedded Linux-Xenomai를 사용했다.
항공기를 제어 시뮬레이션을 수행 하려면 FDM으로 부터 계산된(시뮬레이션된) 항공기 자세정보가 필요하며 제어 루프에 의해 계산된 출력물인 엔진 추력, 조종면 각도값은 다시 FDM으로 주입하여 일련의 되먹임 (Feedback) 제어루프가 형성 되어야 한다.
다행히 FlightGear에는 UDP/IP 및 RS-232통신라인을 이용해 이런 일련의 데이터 흐름을 만들 수 있는 기능이 있다.
해외 자료들 뒤져 보니 실 기체 개발시 HILS용으로 FlightGear를 많이 사용하는가 보다.
제어 루프는 RTOS기반의 FLCC 하드웨어에서 수행 하도록 구성하면 된다.
전체 시스템 구성을 보자면 아래 그림과 같다.
[그림 1] Native 시뮬레이션 환경
[그림 2] FLCC-HILS 환경
사용한 FLCC 하드웨어는 일전에 EtherCONN 개발시 사용한 PXA270기반 보드를 사용했다 (링크참조).
Linux-Xenomai가 이미 포팅되어 있고 UDP/IP 통신을 위한 Ethernet용 실시간 디바이스 드라이버 (RTDM)가 만들어져 있으니 바로 활용 가능 하였다.
개발시에는 [그림 1]과 같이 Native 환경에서 개발을 진행 하고 얼추 결과가 나오면 [그림 2]와 같이 실제 FLCC 하드웨어에 제어 코드를 이식해 사용 하면 된다.
HILS 환경을 구축하고 간단하게 항공기의 롤 및 피치 제어용 Auto-pilot을 구현해 돌려 봤다. 아래 동영상 결과는 실제 FLCC 하드웨어로 제어하는 모습이다.
[영상 1] Roll/Pitch Auto-pilot Off
[영상 2] Roll/Pitch Auto-pilot On
[영상 3] Roll/Pitch Auto-pilot Off/On
[영상 1]은 롤/피치 제어용 Auto-pilot기능이 없는 순수 비행 화면이다.
비행 조종은 게임 패드의 조이스틱을 사용했으며 트림을 사용하지 않고 조종하는 모습이다.
조종사가 아니다 보니 항공기 조종하는게 생각 보다 어렵다.
[영상 2]는 롤/피치 제어용 Auto-pilot의 도움을 받아 비행하는 모습니다. 아케이드 게임하는 것처럼 조종하기가 참 수월해진다.
[영상 3]은 롤/피치 제어용 Auto-pilot 기능을 on/off를 반복하면서 동작 상태를 관찰하는 모습이다.
피드 구독하기:
글 (Atom)




































































