Little Navmap (리틀네브맵) 에서 비행 경로 만들기

리틀네브맵은 MSFS의 비행경로(PLN)파일을 생성하는 프로그램이다. 

리틀네브맵 설치

리틀네브맵 프로젝트 페이지는 아래 링크에 있다.

https://albar965.github.io/littlenavmap.html 

 

Alex Projects - Little Navmap

Alex’ Projects ► Little Navmap Little Navmap Links ► Releases and Downloads ► Translation Packages ► Screenshots ► Screenshots of new 2.8 Features ► Screenshots of new 2.6 Features ► User manuals for Little Navmap and Little Navconnect in a

albar965.github.io

https://github.com/albar965/littlenavmap/releases

다음 깃허브 페이지에서 최신의 네브맵 설치파일을 다운로드 한다

 

Releases · albar965/littlenavmap

Little Navmap is a free flight planner, navigation tool, moving map, airport search and airport information system for Flight Simulator X, Microsoft Flight Simulator 2020, Prepar3D and X-Plane. - ...

github.com

Yes를 눌러 다음으로 진행한다.
MSFS 설치경로를 지정한다. (기본값으로 설정)

 

Little Navmap에서 생성한 플랜 모습

BushMissionGen(BMG) 프로그램으로 내보내기

이제 만들어진 PLN파일을 MSFS에서 인식할 수 있는 패키지로 만들기 위해 BMG 프로그램을 설치한다.

다운로드는 다음 경로에서 가능하다. (Flightsim.to 가입이 필요함)

https://flightsim.to/file/3681/bushmissiongen

 

BushMissionGen for Microsoft Flight Simulator | MSFS

Recent Changelog for 4.24 - poiStripHTML field to handle HTML tags in POI TTS dialogs and dialog entries. - Only create localization files for handled languages. Thanks to Frontech for bug reports, suggestions, testing and more!

flightsim.to

자세한 사용 방법은 다음 동영상을 참고한다.

https://youtu.be/JCfpbqIP2cQ?si=LU3LNlo5jhXLDJyq 

BushMissionGen(BMG)에서 plan 불러오기

미션 타입을 Landing challenge로 선택

적절한 챌린지 타입을 선택

저작자 이름, 제목, 간단한 설명등을 입력한다.

 

BushMissionGen에 넣을 인풋 파일

# Input file for BushMissonGen
#
# Auto-generated in v4.07

author=Kyubot
title=Gimhae landing VOR DME-A 18R
project=rkpk-rwy18r
version=1.0.0
location=Gimhae Intl
plane=Airbus A320 Neo Asobo
tailNumber=N9999DE
airlineCallSign=HL
flightNumber=1234
introSpeech=
simFile=runway.FLT
parkingBrake=0.00
description=Circle to land Gimhae 18R, ROK
loadingTip=Generated by BushMissionGen.
intro=Try to land one of the most challenging approach to Gimhae RWY 18. You are located 15 DME from KMH R225. Maintain heading 45 until D3 and enter downwind. Then make right turn to land runway 18R while avoiding terrains.
latitude=N35°0'11.82"
longitude=E128°43'23.49"
altitude=+4000.00
pitch=0
bank=0
heading=45
weather=.\WeatherPresets\FewClouds.WPR
season=SUMMER
year=2022
day=167
hours=12
minutes=30
seconds=0
missionType=landing
challengeType=Famous
velocity=200

#icao rw    name        type            LL                   alt
||CUST0|U|N35° 0' 11.82",E128° 43' 23.49"|+004000.00
||CUST1|U|N35° 0' 11.82",E128° 43' 23.49"|+004000.00
||CUST2|U|N35° 8' 41.63",E128° 53' 42.73"|+002700.00
||CUST3|U|N35° 11' 53.59",E128° 53' 12.74"|+001683.60
||CUST4|U|N35° 13' 17.91",E128° 55' 41.66"|+000854.25
RKPK|18R|RKPK|A|N35° 10' 50.01",E128° 56' 16.98"|+000010.00

WS2812란?

ws2812라는 명칭 보다는 네오픽셀이라는 이름으로 더 많이 알려진 이 LED는

한개의 LED 안에 빨강(R), 녹색(G), 파랑(B)색 LED 그리고 아주 작은 컨트롤러가 내장된 RGB형 LED이다.

 

일반적인 RGB형 LED들이 1개의 Common Cathod(음극) 또는 1개의 Common Anode(양극)으로 구성되어 

각각의 핀에 High 또는 Low 신호를 주어서 제어하는 방식이다. 보통은 PWM신호를 만들어서 밝기를 제어한다.

이 방식은 1개의 LED를 제어하기에는 편하지만 여러개의 LED를 제어하려면 LED갯수 x 3개 만큼의 PWM 핀이 필요하므로 MCU에 부담이 커진다.

 

WS2812는 각각의 LED에 컨트롤러를 내장하여 +, -외에 1개의 신호를 입력받아 R,G,B의 밝기를 제어할 수 있는 제품이다. 그리고 신호선에는 입력용 신호 (DI)와 출력용 신호(DO)가 있는데 이 신호선끼리 Input 과 Output을 연결하면 여러개의 LED를 동시에 제어할 수 있다.

 WS2812 연결방법

일반적인 연결 방식은 다음과 같다. 

LED3개를 일렬로 연결하는데 첫번째 LED의 DIN은 컨트롤러의 핀으로 연결하고 DOUT을 다음 LED의 DIN으로

그리고 DOUT은 다음 LED의 DIN으로 연결하는 방식이다.

이렇게 하면 몇개의 LED든 3가닥의 선으로 연결할 수 있게 되는데 이러한 연결 방식을 데이지 체인 혹은 Cascade 방식이라고도 한다.

WS2812의 연결 방식

제어 프로토콜

그럼 대체 1개의 선으로 어떻게 R,G,B 값을 보내고 또 그것을 여러개의 LED에 전달하는 것일까?

언뜻 매우 복잡한 신호가 필요할꺼 같지만 실은 단순히 0과 1의 조합일 뿐이다.

대신 1개의 선으로 보내야 하므로 0과 1을 구분하기 위해 미리 정해진 시간만큼의 High 신호와 Low 신호의 비율로 전송해야 하고 그 규격은 다음과 같다.

 

1개의 신호는 약 1.25uS +/-0.6uS로 되어있고 이 시간 안에 0.9uS만큼의 High 신호가 있으면 1로 인식하고 이보다 적은 0.35uS만큼의 High신호로 감지되면 0으로 인식한다.

RGB값은 각각 0~255까지 8bit로 표현할 수 있으므로 8x3 = 24개의 비트를 보내면 1개의 제어신호(Data)가 완성된다.

n개의 LED를 제어하는 경우 한번에 n개의 제어신호를 한꺼번에 보내야 한다. 

그리고 다음 신호는 최소 50uS 이후에 보낼 수 있다.

다음 다이어그램은 D1을 지난 신호가 DOUT을 거쳐 D2에 전달될때 첫번째 Data가 사라진 것을 확인할 수 있다.

그리고 D2를 지난 신호에는 D3의 Data만 남아있게 된다.  

이것은 마치 기차가 한개의 역을 지날때마다 객차가 1개씩 사라지는것과 같다.

이제 각각의 데이터를 살펴보면 R,G,B 순서가 아닌 G, R, B의 순서로 되어있음을 알 수 있다.

그리고 각 byte는 MSB(Most Significant Byte First)로 좌측 정렬되어있다.

제어 방법

STM32계열 MCU에서 이러한 데이터를 만드는 방법은 크게 2가지가 있다.

1. PWM을 변조하여 보내는 방법

2. SPI에서 MOSI(Master Output) 신호를 사용하는 방법

 

1번 방법을 구현하기 위해서는 PWM + DMA 방식이 주로 사용된다.

여기서는 2번 방법을 사용하여 구현하는 방법을 소개한다.

 

SPI통신은 원래 클럭신호마다 1개의 데이터를 실어서 보내는 제어 방식인데 8개의 클럭을 묶어서 High 신호와 Low 신호의 비율로 나누면 마치 PWM 신호인 것 처럼 보낼 수 있다. 

일반적인 SPI신호 방식

CubeMX 설정하기

SPI 핀을 설정하기 위해 CubeMX를 열고 SPI설정을 한다.

여기서는 STM32F429ZI 가 내장된 Nucleo F429ZI를 기준으로 한다.

클럭 설정은 다음과 같다.

그리고 SPI 설정은 다음과 같다.

RX핀은 사용하지 않으므로 Mode를 Transmit Only Master로 설정하고

 

Prescaler는 SPI 베이스 클럭을 나눈 값으로 1초당 Bit의 수를 설정한다.

SPI1, 4, 5, 6의 베이스 클럭은 APB2 클럭 또는 84MHz 클럭이 사용된다.

Figure 4. STM32F427xx and STM32F429xx block diagram

 

앞서 WS2812의 제어 방식에서 1개의 bit가 약 1.25uS가 되어야 하므로

1bit/1.25uS * 1000,000uS/1S = 800,000bit/S 또는 800KBits/s 가 된다.

그런데 실제로는 8개의 클럭을 묶어서 보내야 하므로 이 값을 8채배 하면

800K * 8 = 6.4MHz 가 된다. 최대한 근사한 값을 만들기 위해  Prescaler를 조정하면

84000000 / 16 = 5.25MHz 즉 5.25MBits/S 가 된다.

이 값을 Parameter settings에 적용한다.

DMA 설정하기

MCU는 LED제어만 하는게 아니므로 정확한 전송 타이밍을 보장하기 위해서는 DMA방식으로 전송하는 것이 권장된다.

설정 방법은 일반적인 설정과 동일하다.

코드 작성

이제 ws2812_spi.h 코드를 다음과 같이 작성한다.

#ifndef __WS2812_SPI_H_
#define __WS2812_SPI_H_

#include "stm32f4xx_hal.h"


/* Exported types ------------------------------------------------------------*/

/* Private defines -----------------------------------------------------------*/
#define WS2812_NUM_LEDS 8
#define WS2812_RESET_PULSE 60
#define WS2812_BUFFER_SIZE (WS2812_NUM_LEDS * 24 + WS2812_RESET_PULSE)
/* Exported constants --------------------------------------------------------*/

/* Exported macro ------------------------------------------------------------*/

/* Exported functions prototypes ---------------------------------------------*/
void WS2812_SPI_Init(SPI_HandleTypeDef *hspi);
void WS2812_Set(uint16_t led_no, uint8_t r, uint8_t g, uint8_t b);
void WS2812_SetAll(uint8_t r, uint8_t g, uint8_t b);
void WS2812_Refresh(void);
#endif

WS2812_NUM_LEDS는 연결된 LED의 갯수이다.

이제 ws2812_spi.c 코드를 작성한다.

#include "mcb_drv_ws2812_spi.h"

#define WS2812_FILL_BUFFER(COLOR) \
for( uint8_t mask = 0x80; mask; mask >>= 1 ) { \
	if( COLOR & mask ) { \
		*ptr++ = 0xF8; \
	} else { \
		*ptr++ = 0xC0; \
	} \
}
static SPI_HandleTypeDef *m_Hspi;
	  
uint8_t ws2812_buffer[WS2812_BUFFER_SIZE];

void WS2812_SPI_Init(SPI_HandleTypeDef *hspi)
{
 	m_Hspi = hspi;
	HAL_SPI_Transmit_DMA(m_Hspi, ws2812_buffer, WS2812_BUFFER_SIZE);
}

void WS2812_Set(uint16_t led_no, uint8_t r, uint8_t g, uint8_t b) {
	if(led_no > WS2812_NUM_LEDS-1) return;
    uint8_t * ptr = &ws2812_buffer[24 * led_no];
    WS2812_FILL_BUFFER(g);
    WS2812_FILL_BUFFER(r);
    WS2812_FILL_BUFFER(b);
}

void WS2812_SetAll(uint8_t r, uint8_t g, uint8_t b) {
    uint8_t * ptr = ws2812_buffer;
    for( uint16_t i = 0; i < WS2812_NUM_LEDS; i++) {
        WS2812_FILL_BUFFER(g);
        WS2812_FILL_BUFFER(r);
        WS2812_FILL_BUFFER(b);
    }
}

void WS2812_Refresh(void)
{
	HAL_SPI_Transmit_DMA(m_Hspi, ws2812_buffer, WS2812_BUFFER_SIZE);
}

이제 main 함수에서

WS2812_Init 함수를 SPI 핸들러(hspi1 또는 해당하는 spi 헨들러)와 함께 호출한 다음

WS2812_SPI_Init(&hspi4);

프로그램 어딘가에서 

WS2812_SetAll(R, G, B);

또는

WS2812_Set(0~(n-1) 사이의 LED 번호, R, G, B값); 

을 호출한 다음 WS2812_Refresh() 함수를 호출하면 ws2812_buffer의 값을 LED에 적용할 수 있다.

 

 

 

요즘 CAN 통신으로 장비를 제어할 일이 좀 생겨서 Ixxat 社의 USB-to-CAN 장비를 사용하게 되었다. 

외형은 아래와 같다. 

https://www.ixxat.com/products/products-industrial/can-interfaces/usb-can-interfaces/usb-to-can-v2-professional

이 장비는 윈도우 뿐 아니라 리눅스, RTOS등 다양한 OS를 지원하기때문에 사용하기 편리한데,

프로그램을 작성하기 위해서는 약간의 학습 곡선이 필요하다.

드라이버 및 SDK 설치

일단 장비 사용을 위한 드라이버를 설치하기 위해 아래 링크에서 윈도우 11, 10용 VCI V4 드라이버를 다운로드 한다.

https://www.ixxat.com/technical-support/resources/downloads-and-documentation?ordercode=1.01.0281.12001 

 

Downloads and Documentation for Ixxat Products

 

www.ixxat.com

설치하는 도중 SDK를 설치하기 위해 다음 항목을 추가 선택한다.

- SDK VCI4 (.NET)

장비 사용 확인

설치가 완료되면 일단 장비가 잘 동작하는지를 확인하기 위해 canAnalyser3 Mini  프로그램을 열어서 CAN 메세지를 확인한다.

자세한 사용 방법은 매뉴얼을 참조 할 것.

샘플 코드

 .NET용 샘플 코드는 아래 위치에 존재한다.

C:\Users\Public\Documents\HMS\Ixxat VCI 4.0\Samples\dotnet

 

프로그래밍 매뉴얼은 아래 위치의 pdf 문서를 참조한다.

C:\Program Files\HMS\Ixxat VCI\Manual\VCI-DotNetSoftwareDesignGuide_en.pdf 

 

이 코드는 크게 다음의 4가지 서브 프로젝트를 포함한다.

  • CanConNet
  • CanFdConNet
  • CanVbNet
  • LinConNet

CanConNet 프로젝트는 장치를 125kbps로 열고 들어오는 메세지를 콘솔에 표시하는 간단한 프로그램이다.

이 프로그램에서는 다음 namespace를 참조한다.

CanConNet 클래스는 main 함수에서 다음과 같은 순서로 CAN 소켓을 열고 메세지 수신 쓰레드를 실행하게 된다.

 

SelectDevice();

InitSocket(0)

rxThread = new Thread(new ThreadStart(ReceiveThreadFunc));
        rxThread.Start();

 

이 프로젝트를 실행하기 위해서는 빌드 설정을 Debug 대신 Release 로 변경하고 실행하면 정상적으로 실행된다.

 

비쥬얼 스튜디오 프로젝트 만들기

WPF 프로젝트를 하나 만들고

  • NuGet Package 설치

IXXAT VCI는 NuGet 패키지를 지원하므로 NuGet 패키지 관리자를 통해 필요한 라이브러리를 추가할 수 있다.

Tools > NuGet Package Manager > Package Manager Console을 열고

나타나는 터미널 콘솔에서 다음을 입력하여 Ixxat.Vci4.StringName 패키지를 설치한다.

> Install-Package Ixxat.Vci4.StrongName

프로그램에서 이 소켓 프로그램을 사용하기 위해서 위의 샘플 코드에 포함된 CanConNet.cs 파일을 일부 수정한 클래스 파일을 첨부한다. 

can_con_net.cs
0.02MB

사용 방법은 다음과 같다.

Forms1.cs 파일을 열고 using 항목에 다음을 추가한다.

Form1 클래스 선언부에 다음 전역변수를 추가한다.

Form1() 초기화 함수 부분에 can 포트의 동작 모드와 통신 속도를 선택하고 소켓을 열기 위해 다음 내용을 추가한다.

can.NewCanMessageEvent += 부분은 새로운 메세지가 들어오면 호출되는 콜백함수를 아래와 같이 등록한다.

 

소스 코드 다운로드

전체 코드는 다음 깃허브 페이지에서 다운로드 하기 바랍니다.

https://github.com/kyuhyong/usbcan_net

 

GitHub - kyuhyong/usbcan_net

Contribute to kyuhyong/usbcan_net development by creating an account on GitHub.

github.com

개발 환경은 Visual Studio 2019 Community Edition에서 만들어졌습니다.

+ Recent posts