Windows 10 IoT Core, Raspberry PI, Arduino and enuSpace Platform


IoT 통합 플랫폼 연계 작업 내역 (enuSpace for mars - ver 2.0)

Raspberry PI에 윈도우즈 10 IoT Core를 설치하고 Arduino의 센서 Analog 신호를 시리얼 통신으로 입력 받아 enuSpace Platform에 http 통신을 이용하여 데이터를 받아서 처리하는 일련의 작업과정을 설명합니다.

아래 동영상은 enuSpace 통합 플랫폼 웹서버와 라즈베리 파이에 Windows 10 IoT Core App간의 연동 내용을 포함하고 있습니다.


Step1. Windows 10 iot core 설치

https://developer.microsoft.com/ko-kr/windows/iot/GetStarted

위 링크의 내용을 기반으로 단계별로 설치 절차를 진행합니다.  

Dashboad를 다운 받아 프로그램을 설치합니다.

이미지를 다운 받아서 Flash Memory에 이미지를 저장합니다.

Flash Memory를 라으베리 파이에 삽입하고 전원을 연결하면 모든 설치가 완료됩니다.

설치가 끝난후 개발자 모드 설정을 수행합니다.


윈도우 Edge 또는 웹브라우져를 이용하여 Window 10 iot core가 설치된 Raspberry PI에 접속을 수행합니다.

Windows 10 IoT Core의 기본 App의 IoTCoreDefaultApp 실행 화면입니다.


아래 그림과 같이 Raspberry PI 3와 Arduino 디바이스간에 USB Serial을 통하여 연결을 수행하고 아두이노에 센서 2종을 연결한 화면입니다.

라즈베리 파일에 Windows 10 IoT Core 를 설치, 아두이노를 연결 및 센서 2종 음향 및 플래어 센서 연결을 마무리 하였다면 아두이노 프로그램밍을 수행합니다.


Step 2. 아두이노 프로그래밍

Arduino를 USB로 연결하고 Arduino IDE에서 예제 AnalogOutSerial을 참조하여 코드를 수정하여 컴파일 및 배포를 수행합니다.


const int analogInPin1 = A0;  

const int analogInPin2 = A1; 

int sensorValue = 0;       

int sensorValue2 = 0;       

String Buffer ;

void setup() {

  Serial.begin(250000);

}

 

void loop() {

  // read the analog in value:

  sensorValue = analogRead(analogInPin1);

sensorValue2 = analogRead(analogInPin2);

 

  // print the results to the serial monitor:

  Buffer = "";

  Buffer += sensorValue;

  Buffer += ":";

  Buffer += sensorValue2;

Serial.println(Buffer);

}


Step 3. 라즈베리 파이(Raspberry PI)에 WinRT 응용프로그램을 개발(WinRT C#) 절차

Microsoft Visual Studio 2015 다운로드 사이트

https://developer.microsoft.com/ko-kr/windows/downloads

Microsoft Visual Studio 2015를 이용하여 IoT C# 프로젝트를 생성합니다.


아래 사이트에 가시면 시리얼 통신에 적합한 샘플을 구할수 있습니다.

https://developer.microsoft.com/en-us/windows/iot/samples/serialuart

위 사이트에서 샘플을 다운 받아서 간단하게 C#용으로 시리얼 통신을 수행합니다.

시리얼 통신으로 부터 전달받은 데이터를 차트에 표현하도록 하겠습니다. 

차트를 드로잉하기 위해서 nuget에 있는 https://www.nuget.org/packages/WinRTXamlToolkit.Controls.DataVisualization.UWP/

Toolkit을 이용하는 방법이 있습니다.  

Window 10 iot core 용으로 다운 받을 경우 UWP 버젼으로 다운 받아야 한다. 정상적으로 받았을 경우 xaml 파일과 cs 소스 코드를 이용하여 개발을 수행합니다. 

        <WinRT_Charting:Chart x:Name="LineChart1" Title="My Chart">

            <WinRT_Charting:LineSeries Title="T1"

                        ItemsSource="{Binding Items}"

                        IndependentValueBinding="{Binding Name}"

                        DependentValueBinding="{Binding Value}"

                        IsSelectionEnabled="True"/>

            <WinRT_Charting:LineSeries Title="T2"

                        ItemsSource="{Binding Items}"

                        IndependentValueBinding="{Binding Name}"

                        DependentValueBinding="{Binding Value}"

                        IsSelectionEnabled="True"/>

        </WinRT_Charting:Chart>


private void updateChart_Click(object sender, RoutedEventArgs e)

        {

            try

            {

                List<NameValueItem> newitems1 = new List<NameValueItem>();

                List<NameValueItem> newitems2 = new List<NameValueItem>();

 

                int num = items1.Count / 250;

                int con = 0;

                int value1 = 0;

                int value2 = 0;

                string name;

                for (var i = 0; i < items1.Count; i++)

                {

                     name = Convert.ToString(newitems1.Count);

                     newitems1.Add(new NameValueItem { Name = name, Value = items1[i].Value });

                     newitems2.Add(new NameValueItem { Name = name, Value = items2[i].Value });


                }

                ((LineSeries)this.LineChart1.Series[0]).ItemsSource = newitems1;

                ((LineSeries)this.LineChart1.Series[1]).ItemsSource = newitems2;

 

                newitems1 = null;

                newitems2 = null;

            }

            catch (Exception ex)

            {

                status.Text = ex.Message;

            }

        } 

센서값을 차트로 표현결과, 라즈베리 파이에서 그래픽 리소스를 많이 잡아먹는 WinRTXamlToolkit.Controls.DataVisualization를 이용할 경우에는 많은 양의 데이터를 표현은 어렵다는것을 확인하였습니다. 약 1000개의 데이터를 현시할 경우, 약 30초정도 소요됩니다. 아래 그림은 1000개의 데이터를 차트에 표현하여 보았습니다. 

실시간으로 데이터 표현이 어렵기 때문에, 데이터를 취득하는 버튼과 데이터 취득 종료버튼을 별도로 이용하여 데이터를 분석하는 모듈로 구성하였습니다. 

만약 실시간으로 차트를 표현하고자 한다면, Canvas를 이용하여 직접 Drawing을 수행하면 빠른 현시가 가능합니다. 


Canvas객체를 이용하 WinRT C# Chart 드로잉

private void DrawChart(Canvas canGraph, List<NameValueItem>[] pList, double axisx_min, double axisx_max, double data_min, double data_max)

        {

            canGraph.Children.Clear();


            double[] RectWall;

            RectWall = new double[4];

            RectWall[0] = 0;                // left 

            RectWall[1] = 0;                // top

            RectWall[2] = canGraph.ActualWidth;   // right

            RectWall[3] = canGraph.ActualHeight;  // bottom


            double[] RectGap;

            RectGap = new double[4];

            RectGap[0] = 30;    // left 

            RectGap[1] = 20;    // top

            RectGap[2] = 20;    // right

            RectGap[3] = 20;    // bottom


            double[] RectChart;

            RectChart = new double[4];

            RectChart[0] = RectWall[0] + RectGap[0]; // left 

            RectChart[1] = RectWall[1] + RectGap[1]; // top

            RectChart[2] = RectWall[2] - RectGap[2]; // right

            RectChart[3] = RectWall[3] - RectGap[3]; // bottom


            double fChartWidth = RectChart[2] - RectChart[0];

            double fChartHeight = RectChart[3] - RectChart[1];


            int xGridNum = 5;

            int yGridNum = 10;

            double fGridGapX = fChartWidth / xGridNum;

            double fGridGapY = fChartHeight / yGridNum;


            // 차트 그리기.

            Rectangle pChartRect = new Rectangle();

            pChartRect.StrokeThickness = 1;

            pChartRect.Fill = new SolidColorBrush(Colors.Black);

            pChartRect.Stroke = new SolidColorBrush(Colors.Yellow);

            pChartRect.Width = fChartWidth;

            pChartRect.Height = fChartHeight;

            Canvas.SetLeft(pChartRect, RectChart[0]);

            Canvas.SetTop(pChartRect, RectChart[1]);

            canGraph.Children.Add(pChartRect);


            // x축 그리기.

            int iCount = 0;

            GeometryGroup xaxis_geom = new GeometryGroup();

            for (double x = 0; x <= fChartWidth; x += fGridGapX)

            {

                LineGeometry xtick = new LineGeometry();

                xtick.StartPoint = new Point(x + RectChart[0], RectChart[3] + 5);

                xtick.EndPoint = new Point(x + RectChart[0], RectChart[1]);

                xaxis_geom.Children.Add(xtick);


                TextBlock xlabel = new TextBlock();

                int ivalue = (int)axisx_min + (int)(axisx_max - axisx_min) / xGridNum * iCount;

                xlabel.Text = ivalue.ToString();

                xlabel.FontSize = 10;

                Canvas.SetLeft(xlabel, x + RectChart[0]);

                Canvas.SetTop(xlabel, RectChart[3] + 5);

                canGraph.Children.Add(xlabel);

                iCount = iCount + 1;

            }


            Path xaxis_path = new Path();

            xaxis_path.StrokeThickness = 1;

            xaxis_path.Stroke = new SolidColorBrush(Colors.Green);

            xaxis_path.Data = xaxis_geom;

            canGraph.Children.Add(xaxis_path);


            // y축 그리기.

            iCount = 0;

            GeometryGroup yxaxis_geom = new GeometryGroup();

            for (double y = 0; y <= fChartHeight; y += fGridGapY)

            {

                LineGeometry ytick = new LineGeometry();

                ytick.StartPoint = new Point(RectChart[0] - 5, RectChart[3] - y);

                ytick.EndPoint = new Point(RectChart[2], RectChart[3] - y);

                yxaxis_geom.Children.Add(ytick);


                TextBlock ylabel = new TextBlock();

                int ivalue = (int)data_min + (int)(data_max - data_min) / yGridNum * iCount;

                ylabel.Text = ivalue.ToString();

                ylabel.FontSize = 10;

                Canvas.SetLeft(ylabel, RectChart[0] - 20);

                Canvas.SetTop(ylabel, RectChart[3] - y - ylabel.FontSize);

                canGraph.Children.Add(ylabel);

                iCount = iCount + 1;

            }


            Path yaxis_path = new Path();

            yaxis_path.StrokeThickness = 1;

            yaxis_path.Stroke = new SolidColorBrush(Colors.Green);

            yaxis_path.Data = yxaxis_geom;

            canGraph.Children.Add(yaxis_path);


            // data 그리기.

            double x1 = 0;

            double y1 = 0;

            double x2 = 0;

            double y2 = 0;

            

            int idim = 0;

            idim = pList.Length;

            if (idim > 0)

            {

                for (int i = 0; i < idim; i++)

                {

                    GeometryGroup data_geom = new GeometryGroup();


                    List<NameValueItem> newitems = pList[i];

                    double xstep = fChartWidth / newitems.Count;


                    for (int j = 0; j < newitems.Count-1; j++)

                    {

                        LineGeometry vline = new LineGeometry();


                        x1 = RectChart[0] + xstep * j;

                        y1 = RectChart[3] - fChartHeight * ((newitems[j].Value- data_min) / (data_max - data_min));

                        if (y1 < RectChart[1])

                            y1 = RectChart[1];

                        if (y1 > RectChart[3])

                            y1 = RectChart[3];

                        x2 = RectChart[0] + xstep * (j+1);

                        y2 = RectChart[3] - fChartHeight * ((newitems[j+1].Value - data_min) / (data_max - data_min));

                        if (y2 < RectChart[1])

                            y2 = RectChart[1];

                        if (y2 > RectChart[3])

                            y2 = RectChart[3];

                        vline.StartPoint = new Point(x1, y1);

                        vline.EndPoint = new Point(x2, y2);

                        data_geom.Children.Add(vline);

                    }


                    Path value_path = new Path();

                    value_path.StrokeThickness = 1;

                    if (i == 0)  

                        value_path.Stroke = new SolidColorBrush(Colors.Red);

                    else if (i == 1)

                        value_path.Stroke = new SolidColorBrush(Colors.Green);

                    else if (i == 2)

                        value_path.Stroke = new SolidColorBrush(Colors.Blue);

                    else

                        value_path.Stroke = new SolidColorBrush(Colors.Yellow);

                    value_path.Data = data_geom;

                    canGraph.Children.Add(value_path);

                }

            }

        }

위와 같이 직접 Canvas에 직접 차트를 그릴경우에는 약 3000개의 데이터를 현시하는데 있어 2~3초정도 소요됨을 확인하였습니다. 

차트를 이용하여 대용량을 현시하고자 할 경우에는 Canvas에 직접 그리는 것을 권고합니다.

Canvas를 이용하여 WinRT용 C# 차트 응용프로그램 실행 화면.


Step 4. enuSpace 서버(웹 서버)에 데이터를 연동

enuSpace for mars 버젼은 다기능 통합 소프트웨어 플랫폼입니다. enuSpace(엔유스페이스) 웹서버와 데이터를 연동하도록 하겠습니다. 웹서버에 연동시 라즈베리 파이에서 1초에 약 2700샘플링 데이터를 취득합니다. 이때 모든 데이터를 서버에 연동하는 것은 서버에 큰 부담을 안겨줄수 있습니다. 이에 1초에 2회의 대표값 데이터를 전송하도록 구성 하였습니다.

라즈베리 파이에서 Windows 10 IoT Core App에 웹 통신을 이용한 디바이스 등록, 변수 등록 페이지를 추가하여 센서값을 연결하기 용이하도록 구성하여 보았습니다. 

알람 설정과 서버에 전송 설정을 수행하는 UI도 함께 구성하였습니다. 


Windows 10 IoT Core용 WinRT C# 을 이용한 웹 통신 처리 코드는 아래와 같이 사용할 수 있습니다. 

enuSpace 서버(웹 서버)에 데이터를 전송하는 샘플 코드입니다. 

WinRT C# http request POST 전송 처리.

        public async void SendSensorData(int iVal1, int iVal2)

        {

            if (m_bSendValue)

            {

                String url = "http://169.254.60.226:8080/setvalue_package";

                var text = "{\"" + "@" + m_DeviceID + ".A0" + "\":\"" + iVal1.ToString() + "\",\"" + "@" + m_DeviceID + ".A1" + "\":\"" + iVal2.ToString() + "\"}";

                var strParam = "tagid_list=" + text;

                String response = await getResponse(url, strParam);

                status.Text = response;

            }

        } 


        private async Task<String> getResponse(String url, string data)

        {

            try

            {

                WebRequest request = WebRequest.Create(url);


                request.ContentType = "application/json";

                byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(data);

                request.ContentType = "application/x-www-form-urlencoded";

                request.Method = "POST";


                using (var requestStream = await request.GetRequestStreamAsync())

                {

                    System.IO.StreamWriter writer = new System.IO.StreamWriter(requestStream);

                    writer.Write(data);

                    writer.Flush();


                    using (WebResponse response = await request.GetResponseAsync())

                    {

                        using (System.IO.Stream responseStream = response.GetResponseStream())

                        {

                            System.IO.StreamReader reader = new System.IO.StreamReader(responseStream);

                            String answer = reader.ReadToEnd();

                            return answer;

                        }

                    }

                }

            }

            catch (Exception ex)

            {

                status.Text = ex.Message;

                return "";

            }

        }

웹 서버에 POST 명령으로 데이터를 전송하기 위해서 WebRequest를 이용한다. 그리고 비동기식 처리를 통하여 데이터 취득에 영향을 최소화 합니다.


Step 5. enuSpace 통합 플랫폼을 이용하여 데이터 현시를 위한 픽쳐 화면을 구성합니다. 

enuSpace 통합 플랫폼에서 제공하는 웹 서버를 구동하고, 라즈베리 파이의 응용프로그램을 통하여 디바이스 추가 및 변수 추가를 수행합니다.

라즈베리 파이의 응용 프로그램에서 추가한 디바이스와 변수 정보를 DB 관리자를 통하여 확인하실수 있습니다.

라즈베리 파이의 응용 프로그램으로부터 주기적으로 데이터 들어오는 확인합니다. 정상적으로 데이터가 전달되는 값을 확인하였다면, 픽쳐를 생성하고 아날로그 Value와 알람 Value값을 차트를 추가하여 현시합니다.

차트는 시리즈 2개를 추가하고, 각각의 DB Tag 정보를 연결을 수행하면 아래 그림과 같이 센서 아날로그 신호 값을 실시간 데이터로 확인 할 수 있습니다.

아래 그림은 라즈베리파이에서 전송한 센서 데이터가 enuSpace 서버에서 현시되는 결과의 모습입니다.


추가 팁 

Windows IoT Core Remote Server 사용 Tip.

라즈베리 파이 응용 프로그램을 리모트 컨트롤을 수행하기 위해서 아래 그림의 링크를 따라서, 어플을 설치후 라즈베리 파이의 IP주소를 입력하여 실행을 수행하면, 리모트 컨트롤이 가능합니다.


enuSpace for Mars의 기능중 하나인 Web Data 인터페이스 작업 및 Big data 처리


아래 동영상을 확인하시면, 대용량 객체현시에 대한 각 브라우져의 특성을 보실수 있습니다. (16,384개 데이터)


Web Data Visualization 동영상 보기.

Step 1. Wave Model Task 생성 및 등록.

enuSpace에서 제공되는 Task 생성 SDK를 이용하여 Wave 데이터 파일을 생성하는 dll 파일을 생성합니다. 


double pinpower[8][8][26][16][16];

float initValue = 1.0f;

void MAIN()

{

initValue = initValue + 0.1;

//////////////////////////////////////////////////////////////

for (int x = 0; x < 8; x++)

{

for (int y = 0; y < 8; y++)

{

for (int k = 0; k < 26; k++)

{

for (int i = 0; i < 16; i++)

{

for (int j = 0; j < 16; j++)

{

pinpower[x][y][k][i][j] = 1.0 + sin(double((x * 16) + i + (y * 16) + j) / 3.141592 / 5 + initValue);

}

}

}

}

}

SetArrayValue(L"@CORE.pinpower[0][0][0][0][0]", pinpower, DEF_DOUBLE, 8 * 8 * 26 * 16 * 16);

}


배열변수를 이용하여 sin() 함수의 값을 매 주기마다 업데이트를 수행합니다.

저장된 배열 정보는 enuSpace의 데이터 베이스 메모리에 SetArrayValue() 함수를 이용하여 고속 복사를 수행합니다.


Step 2. 데이터베이스 매니져를 이용하여 배열 변수를 생성하여 Task의 연산 결과와 연동할 수 있도록 등록을 수행합니다.


Step 3. enuSpace의 Project Explorer의 팝업메뉴를 이용하여 Add 3d picture item을 이용하여 3D 픽쳐를 생성합니다.

생성한 픽쳐에 배열 변수값을 확인할 수 있는 Terrain 객체를 추가합니다.


생성한 객체의 Taskview() 함수에 그래픽 객쳍와 연동을 위한 루아 스크립트를 추가합니다. 루아 스크립트는 enuSpace에서 고속 데이터 처리를 수행합니다.

function _ontaskview()

memcpy(&data[0][0],&@CORE.pindis[0][0],128*128)

end


데이터 베이스의 메모리 주소와 복사하고자 하는 데이터의 주소값을 위 코드와 같이 입력합니다. Run 버튼을 이용하여 Wave 데이터 값을 업데이트 수행합니다.


Step 4. enuSpace에 Add new picture item을 선택하여 2D 화면 구성을 위한 페이지를 새성합니다.

사각형 객체를 16 by 16으로 나열하여 새성을 수행합니다. 생성된 객체를 선택후 Taskview() 함수에 Javascript 함수를 추가합니다.

직접 객체를 생성하기 어려운 경우에는 스크립트를 이용하여 동적으로 객체를 생성하고 스크립트 내용을 동적으로 적용하면 간단하게 생성할 수 있습니다. 

function _ontaskview()

{

var value_obj = document.getElementById("ID00_13_9_7");

var tag_val = GetTagValue("@CORE.pinpower[0][0][13][9][7]");

value_obj.setAttribute("fill", GetValueColor(tag_val));

}

// 전역 javascript 함수 => 리본 메뉴의 Edit Java Script 를 이용하여 추가 수행.

function GetValueColor(fValue)

{

fValue = fValue * 50;

var color;


if (fValue<0) 

{ color = "rgb(0,0,0)"; }

else if (fValue>0 && fValue <=5) 

{ color = "rgb(15,75,165)"; }

else if( fValue>5 && fValue <=10 )

{color = "rgb(30,110,200)"; }

else if( fValue>10 && fValue <=15 )

{color = "rgb(60,160,240)"; }

else if( fValue>15 && fValue <=20 )

{color = "rgb(80,180,250)"; }

else if( fValue>20 && fValue <=25 )

{color = "rgb(130,210,255)"; }

else if( fValue>25 && fValue <=30 )

{color = "rgb(160,240,255)"; }

else if( fValue>30 && fValue <=35 )

{color = "rgb(200,250,255)"; }

else if( fValue>35 && fValue <=40 )

{color = "rgb(230,255,255)"; }

else if( fValue>40 && fValue <=45 )

{color = "rgb(255,250,220)"; }

else if( fValue>45 && fValue <=50 )

{color = "rgb(255,232,120)"; }

else if( fValue>50 && fValue <=55 )

{color = "rgb(255,192,60)"; }

else if( fValue>55 && fValue <=60 )

{color = "rgb(255,160,0)"; }

else if( fValue>60 && fValue <=65 )

{color = "rgb(255,96,0)"; }

else if( fValue>65 && fValue <=70 )

{color = "rgb(255,50,0)"; }

else if( fValue>70 && fValue <=75 )

{color = "rgb(225,20,0)"; }

else if( fValue>75 && fValue <=80 )

{color = "rgb(192,0,0)"; }

else

{color = "rgb(150,0,0)"; }

return color

}


사각형 객체의 ID값을 이용하여 객체를 획득후, 색상값을 표현하기 위한 데이터베이스 메모리 데이터의 값을 가져옵니다. 가져온 데이터를 이용하여 값을 Color 로 변환하는 함수를 통하여 내부 색상값을 변경합니다.

스크립트를 이용하여 동적 객체 생성 및 스크립트 등록.

Step 5. Web publish 메뉴를 이용하여 Web publish 수행.

Web browser를 이용하여 enuSpace 서버에 접속을 수행합니다. 웹 브라우져 Chrome, Firefox, MS edge를 이용하여 접속하여 서버 데이터의 그래픽 가시화를 수행합니다.

웹 브라우져를 이용한 대용량 데이터 처리를 위해서는 enuSpace에서 제공하는 API  gatvalue_package 함수를 활용하였으며 Web Worker를 이용합니다. 16 * 16 * 8 = 2048개의 묶음데이터에서 대하여 8회(2048*8 = 16384개) 분활하여 서버에 데이터를 요청하여 전송받아서 처리를 수행합니다.


enuSpace for Mars Terrain 객체의 데이터 가시화 작업


Terrain 객체의 속성 설정에 따른 가시화 결과.


DB 등록 및 Task 모델 생성.

* enuSpace for Mars에서 제공되는 모델 Scheduling 기능을 이용하여 변수값을 생성합니다. C++, Fortran 을 이용하여 모델을 생성할 수 있습니다. 

3D 그래픽 객체 Terrain 객체를 생성합니다.

* Terrain 객체의 subdivision_x, y의 값을 각각 15, 24로 설정합니다. 

* 생성된 Terrain 객체의 주기적인 데이터 업데이트를 수행하는  _ontaskview() 함수에 인터페이스 내용을 추가합니다.

* 객체의 데이터 인터페이스를 위해서는 data_0_0에서 부터 data_14_23 변수명을 통하여 인터페이스를 수행합니다.


function _ontaskview()


    data_0_0=@CORE.flux_1_1_1

    data_1_0=@CORE.flux_2_1_1

    data_2_0=@CORE.flux_3_1_1

    data_3_0=@CORE.flux_4_1_1 

   ~~~~

   data_12_23=@CORE.flux_13_1_24

   data_13_23=@CORE.flux_14_1_24

   data_14_23=@CORE.flux_15_1_24


end


data_0_0=@CORE.flux_1_1_1 // DB의 변수값을 Terrain 객체의 변수값에 할당을 수행합니다.


RUN 버튼을 클릭하여, 결과를 확인합니다. 


Terrain 객체의 속성

transparency : 1.0

terrainType = contour

elevationType = color+height

minElevation : 0

maxElevation : 1

colorElevation : 

rgb(10,50,120); 

rgb(15,75,165); 

rgb(30,110,200); 

rgb(60,160,240); 

rgb(80,180,250); 

rgb(130,210,255); 

rgb(160,240,255); 

rgb(200,250,255);

rgb(230,255,255);

rgb(255,250,220);

rgb(255,232,120);

rgb(255,192,60);

rgb(255,160,0);

rgb(255,96,0);

rgb(255,50,0);

rgb(225,20,0);

rgb(192,0,0);

rgb(165,0,0)




Terrain 객체의 속성

transparency : 1.0

terrainType = contour bar

elevationType = color+height

minElevation : 0

maxElevation : 1



Terrain 객체의 속성

transparency : 0.5

terrainType = contour bar

elevationType = color+height

minElevation : 0

maxElevation : 1



Terrain 객체의 속성

transparency : 1

terrainType = bar

elevationType = color+height

minElevation : 0

maxElevation : 1



Terrain 객체의 속성

transparency : 1

terrainType = point

elevationType = color+height

minElevation : 0

maxElevation : 1



solid : false



enuSpace for Mars를 이용한 2D, 3D Data Visualization 작업


실행 결과 동영상


샘플 Task 생성 및 등록.

* enuSpace for Mars는 뛰어난 Timing Scheduling 기능을 제공합니다. C++, Fortran 을 이용하여 생성한 dll을 정확한 타이밍 스케쥴러를 통하여 Task 연산이 가능하도록 적용하였습니다.

* 연산된 결과는 메모리 기반의 데이터베이스와 연계되어 빠른 인터페이스가 가능하도록 적용하였습니다. 

* 생성된 모델을 스케쥴링 타임 설정값을 지정합니다.


DB 등록.

간단하게 작성된 모델 변수를 DB에 등록합니다.

샘플 모델을 0~1사이의 값으로 값을 생성하여 타이밍 스케쥴러에 따라서 연산을 수행합니다.


화면 픽쳐 객체 생성.

페이지 로딩시 2D 객체를 루아 스크립트를 이용하여 동적으로 생성합니다. 생성된 객체에 데이터 바인딩을 수행할 스크립트도 같이 등록하여 줍니다.

function _onload()

local tx = 300

local ty = 200

local i = 1

local j = 1

local k = 1

local id_text

for i=1,24,1 do 

for j=1,15,1 do

id_text = string.format("ID_%d_1_%d_H", j,i)

CreateRect(id_text, 0, 0, 15, 15, 20*j+tx, 20*i+ty)

end

end


local strScript

for i=1,24,1 do 

for j=1,15,1 do

id_text = string.format("ID_%d_1_%d_H", j, i)

strScript = string.format("function _ontaskview()\nfill=GetValueColor(@CORE.flux_%d_1_%d)\nend", j, i)

RegisterLuaScriptById(id_text, "_ontaskview", strScript)

end

end

local tx = 800

local ty = 300


local k = 2

for i=1,15,1 do 

for j = 1,15,1 do

id_text = string.format("ID_%d_%d_%d", i, j, k)

CreateRect(id_text, 0, 0, 15, 15, i*20+tx, j*20+ty)

end

end

for i=1,15,1 do 

for j = 1,15,1 do

id_text = string.format("ID_%d_%d_%d", i, j, k)

strScript = string.format("function _ontaskview()\nfill=GetValueColor(@CORE.flux_%d_%d_%d)\nend", i, j, k)

RegisterLuaScriptById(id_text, "_ontaskview", strScript)

end

end

end 


페이지 로딩시 3D 객체를 루아 스크립트를 이용하여 동적으로 생성합니다. 생성된 객체에 데이터 바인딩을 수행할 스크립트도 같이 등록하여 줍니다.

function _onload()

local tx = 75

local ty = 75

local tz = 150

local i = 1

local j = 1

local k = 1

local id_text

for i=1,15,1 do 

for j = 1,15,1 do

for k = 1,24,1 do

id_text = string.format("ID_%d_%d_%d", i, j, k)

Create3DBox(id_text, 7, i*10-tx,j*10-ty,tz-k*10)

end

end

end

local strScript

for i=1,15,1 do 

for j = 1,15,1 do

for k = 1,24,1 do

id_text = string.format("ID_%d_%d_%d", i, j, k)

strScript = string.format("function _ontaskview()\ndiffuseColor=GetValueColor(@CORE.flux_%d_%d_%d)\nend", i, j, k)

RegisterLuaScriptById(id_text, "_ontaskview", strScript)

end

end

end

end


function GetValueColor(fValue)


fValue = fValue * 50

local color


if fValue<0 then

color = string.format("rgb(0,0,0)")

elseif fValue>0 and fValue <=5 then

color = string.format("rgb(15,75,165)")

elseif fValue>5 and fValue <=10 then

color = string.format("rgb(30,110,200)")

elseif fValue>10 and fValue <=15 then

color = string.format("rgb(60,160,240)")

elseif fValue>15 and fValue <=20 then

color = string.format("rgb(80,180,250)")

elseif fValue>20 and fValue <=25 then

color = string.format("rgb(130,210,255)")

elseif fValue>25 and fValue <=30 then

color = string.format("rgb(160,240,255)")

elseif fValue>30 and fValue <=35 then

color = string.format("rgb(200,250,255)")

elseif fValue>35 and fValue <=40 then

color = string.format("rgb(230,255,255)")

elseif fValue>40 and fValue <=45 then

color = string.format("rgb(255,250,220)")

elseif fValue>45 and fValue <=50 then

color = string.format("rgb(255,232,120)")

elseif fValue>50 and fValue <=55 then

color = string.format("rgb(255,192,60)")

elseif fValue>55 and fValue <=60 then

color = string.format("rgb(255,160,0)")

elseif fValue>60 and fValue <=65 then

color = string.format("rgb(255,96,0)")

elseif fValue>65 and fValue <=70 then

color = string.format("rgb(255,50,0)")

elseif fValue>70 and fValue <=75 then

color = string.format("rgb(225,20,0)")

elseif fValue>75 and fValue <=80 then

color = string.format("rgb(192,0,0)")

elseif fValue > 80 then

color = string.format("rgb(150,0,0)")

end

return color

end






lua script를 이용한 logic 심볼 만들기



※ AND Gate


function _ontask()

if(input1 == true and input2 == true) then

output = true

else

output = false

end

end


※ OR Gate

function _ontask()

if(input1 == false and input2 == false) then

output = false

else

output = true

end

end


※ NAND Gate

function _ontask()

if(input1 == true and input2 == true) then

output = false

else

output = true

end

end


※ NOR Gate


function _ontask()
if(input1 == false and input2 == false) then
output = true
else
output = false
end
end

※ XOR Gate


function _ontask()
local icount = 0
if(input1 == true) then
icount = icount + 1
end
if(input2 == true) then
icount = icount + 1
end
if(icount%2 ~= 0) then
output = true
else
output = false
end
end

※ XNOR Gate

function _ontask()
local icount = 0
if(input1 == true) then
icount = icount + 1
end
if(input2 == true) then
icount = icount + 1
end
if(icount%2 ~= 0) then
output = false
else
output = true
end
end

※ INVERTOR Gate

function _ontask()

if(input == false) then

output = true

elseif(input == true) then

output = false

end

end


※ BUFFER Gate

function _ontask()

if(input == false) then

output = true

elseif(input == true) then

output = false

end

end


※ 3 STATE BUFFER Gate

function _ontask()

if(state == true) then

if(input == true) then

output = true

elseif(input == false) then

output = false

end

elseif(state == false) then

output = false

end

end


※ MUX Gate



function _ontask()
if(select1 == false) then
output = input1
elseif(select1== true) then
output = input2
end
end

※ HALF ADDER Gate


function _ontask()
local icount = 0
if(x_value == true) then
icount = icount + 1
end
if(y_value == true) then
icount = icount + 1
end
if(icount%2 ~= 0) then
s_value = true
else
s_value = false
end
if(x_value == true and y_value == true) then
c_value = true
else
c_value = false
end
end

※ HALF SUBTRACTOR Gate


function _ontask()
local icount = 0
if(x_value == true) then
icount = icount + 1
end
if(y_value == true) then
icount = icount + 1
end
if(icount%2 ~= 0) then
d_value = true
else
d_value = false
end
if(x_value == false and y_value == true) then
b_value = true
else
b_value = false
end
end


※ 사용자가 제작한 심볼을 이용한 로직 프로세싱.


다기능 그래픽 솔루션 : enuSpace 이엔유 주식회사 




엔유스페이스 소개 자료 V1.0 (pdf) 파일 다운

enuSpace 팜플렛.pdf








엔유스페이스 HMI/SCADA/IOT/APPLICATION 솔루션 소개



About enuSpace ?


엔유스페이스는 HMI/SCADA/DCS/IOT분야에서 활용되는 다기능 통합 개발자 솔루션입니다. 그래픽 편집 및 런타임 뷰어 기능을 포함하고 있으며, 동적 데이터 가시화 도구를 제공합니다. 객체 지향 프로그래밍(Object Oriented Programming:OOP) 개념을 도입한 사용자 정의 라이브러리를 생성하여 그래픽 컴포넌트로 적용 가능합니다.

엔유스페이스는 동적 디스플레이와 시뮬레이션 도구가 통합되어 로직 및 알고리즘 라이브러리 블럭을 이용하여 데이터 연결선만으로 플로우베이스 프로그래밍(Flowbased Programming)이 가능합니다. 연산결과는 동적 디스플레이 객체를 통하여 표현합니다.

엔유스페이스는 소프트웨어 개발자 도구(Software Development Kit :SDK)를 제공하며, SDK 그래픽 기능을 활용하여 빠르고 수려한 윈도우 그래픽 프로그램을 개발할 수 있습니다


HMI/LOGIC Total Solution Overview


Design symbol and drawing pictures for simulation and monitoring

Advanced GUI Programming (Flowbased Programming)

Extended file format(Scalable Vector Graphics + Lua Script Language)

Versatile software tool to develop and display dynamic graphical user interfaces

Graphic Component (Easy to development User Application Program)

Making Dynamic Symbols & Logic Symbols


Graphics Designer

엔유스페이스 편집기는 직관적 사용이 가능한 사용자 편의 편집 기능을 제공합니다. 모든 객체의 속성은 동적표현을 위한 인자로 활용될 수 있습니다.

스크립트 언어를 이용하여 모든 인자에 대한 속성 변경을 수행함으로서 유연한 인터페이스가 가능합니다. 편집과정 중에 실제 런타임 뷰어를 통한 실행 결과값을 확인 및 디버깅할 수 있습니다.


Flowbased Programming


엔유스페이스는 사용자가 로직 컴포넌트를 제작하여 시뮬레이션 알고리즘을 개발 및 적용할 수 있습니다. 적용범위는 단순로직에서 부터 복잡한 수식까지 적용 가능합니다.

Connect to your data using enuSpace APIs

응용 프로그램 개발 수행시 엔유스페이스 API를 이용하여 데이터 인터페이스를 수행할 수 있습니다. 뿐만 아니라, 각 개별 객체를 API를 이용하여 생성, 수정, 제거를 수행할 수 있습니다. 각 객체에 스크립트 함수등을 동적으로 추가 등록할 수 있는 API를 제공합니다.


Application Areas


엔유스페이스는 교육 및 연구용 시뮬레이션, 산업용 모니터링 및 제어분야 등 전범위 적용이 가능합니다. 발전소, 항공, 전기 생산, 분산 제어 시스템 분야에 있어 광범위하게 사용가능한 솔루션 입니다.

 



이엔유 주식회사에서 소프트웨어 개발자 채용공고 입니다.





근무환경 : 

   근무형태 : 정규직 (주5일 근무)

   근무지 : 대전 유성 관평동


접수기간 및 방법 :

   마감일 : 채용시 마감

   접수방법 : 서류-면접


제출서류 :

  이력서, 자기소개서 제출

  최종합격 후 졸업증명서, 공인시험 및 기타 자격증 사본(소지자에 한함)


제출처 및 연락처 :

    email : master@enu-tech.co.kr

       tel  : 070-4244-2268


기타 유의사항 :

  허위사실이 발견될 경우 채용이 취소될 수 있습니다.


★ 소프트웨어는 항상 새로운 기술이 나타나고, 새로운 기술을 배워 나아가야 하는 분야입니다. 소프트웨어는 지금의 실력보다, 얼마나 성장할 수 있는지가 중요합니다. 소프트웨어의 감을 살릴수 있는 개발자분을 모십니다. 많은 지원 바랍니다.



이엔유 주식회사.

void enuSetSvgPageView() method



bool enuSetSvgPageView(

[in] HVIEW hView,

[in] wchar_t* Filename

};


Parameters

hView [in]

Type:HVIEW

enuSpace View Handle


Filename [in]

Type:wchar_t*

로드된 svg 파일이름을 입력한다.


Return value

Type : bool

뷰와 파일이 정상적으로 연결이 수행되었을 경우 리턴 true값을 반환하며, 연결이 수행되지 않았을 경우에는 false값을 반환을 수행한다.


Remarks

 



Examples


enuSpace SDK


HVIEW ViewHandle = NULL;

void CSampleView::OnInitialUpdate()
{
	CView::OnInitialUpdate();

	enuCreateProject();
	enuLoadProjectFile(L"Project\\sample.enup");
	ViewHandle = enuCreateView(this->m_hWnd);

	// New Page Create.
	CString strPicture = L"picture\\KoreaAIP.svg";
	HSVG SvgHandle = enuNewSvgPageFile(strPicture.GetBuffer(0));
 
	// ENU View Attach Set Page
	enuSetSvgPageView(ViewHandle , strPicture.GetBuffer(0));
}


Reference





'enuSpace SDK API > enuSpace SDK API 2D' 카테고리의 다른 글

enuSpace :: enuNewSvgPageFile()  (0) 2016.02.23
enuSpace :: enuSetViewID()  (0) 2016.02.23
enuSpace :: enuSetWindowPos()  (0) 2016.02.23
enuSpace :: enuSetSelectObject()  (0) 2016.02.17
enuSpace :: enuSetSelectZOrder()  (0) 2016.02.17

void enuNewSvgPageFile() method



HSVG enuNewSvgPageFile(

[in] wchar_t* Filename

};


Parameters

Filename [in]

Type:wchar_t*

Filename


Return value

Type : HSVG

svg 파일 핸들 리턴.


Remarks

본 API를 이용하여 svg 파일을 생성한다. 생성된 파일은 기본 속성 설정 캔버스로 설정 



Examples


enuSpace SDK


HVIEW ViewHandle = NULL;

void CSampleView::OnInitialUpdate()
{
	CView::OnInitialUpdate();

	enuCreateProject();
	enuLoadProjectFile(L"Project\\sample.enup");
	ViewHandle = enuCreateView(this->m_hWnd);

	// New Page Create.
	CString strPicture = L"picture\\sample.svg";
	HSVG SvgHandle = enuNewSvgPageFile(strPicture.GetBuffer(0));
	
	// ENU View Attach Set Page
	enuSetSvgPageView(ViewHandle , strPicture.GetBuffer(0));
}


Reference





'enuSpace SDK API > enuSpace SDK API 2D' 카테고리의 다른 글

enuSpace :: enuSetSvgPageView()  (0) 2016.02.23
enuSpace :: enuSetViewID()  (0) 2016.02.23
enuSpace :: enuSetWindowPos()  (0) 2016.02.23
enuSpace :: enuSetSelectObject()  (0) 2016.02.17
enuSpace :: enuSetSelectZOrder()  (0) 2016.02.17

void enuSetViewID() method



void enuSetViewID(

[in] HVIEW hView,

[in] wchar_t* id

};


Parameters

hView [in]

Type:HVIEW

enuSpace View Handle


id [in]

Type:wchar_t*

뷰의 아이디


Return value

Type : void


Remarks

뷰의 ID값을 문자열로 설정한다. 내부 스크립트에서 설정된 ID값을 이용하여 윈도우 설정값을 가져오거나 설정을 수행한다. 



Examples


enuSpace SDK

void CSampleView::OnInitialUpdate()
{
	CView::OnInitialUpdate();

	enuCreateProject();
	enuLoadProjectFile(L"Project\\sample.enup");
	ViewHandle = enuCreateView(this->m_hWnd);

	enuSetViewID(ViewHandle, L"MainWindow");
}




Reference



'enuSpace SDK API > enuSpace SDK API 2D' 카테고리의 다른 글

enuSpace :: enuSetSvgPageView()  (0) 2016.02.23
enuSpace :: enuNewSvgPageFile()  (0) 2016.02.23
enuSpace :: enuSetWindowPos()  (0) 2016.02.23
enuSpace :: enuSetSelectObject()  (0) 2016.02.17
enuSpace :: enuSetSelectZOrder()  (0) 2016.02.17

+ Recent posts