IoT

초보자를 위한 NT-ARSv1 (Attitude Reference System)

기하 2022. 10. 26. 08:52

http://www.ntrexgo.com/archives/11947

 

초보자를 위한 NT-ARSv1 (Attitude Reference System) | NTREXGO - 디바이스마트, 엔티렉스 컨텐츠 통합 사이

초보자를 위한 NT-ARSv1 (Attitude Reference System) Posted by NTRexLAB on Friday, April 26, 2013 · Leave a Comment  * G.INS NT-ARSv1란? G.INS의 G는 관성항법장치에서 중요한 요소인 Gravity를 의미하기도 하며, 사용자에게

www.ntrexgo.com

 

G.INS NT-ARSv1란?

G.INS의 G는 관성항법장치에서 중요한 요소인 Gravity를 의미하기도 하며,

사용자에게 좀 더 나은 결과값을 제시하기 위해

Genius한 제품을 만들기 위한 저희의 의지를 의미하기도 합니다.


또한 G.INS의 INS는

관성항법장치(Inertial Navigation System)을 의미하는데,

관성항법장치는 엔코더와 같이 고정점이 있어야만

상대각도를 측정할 수 있는

자신의 자세를 측정하기 위한 필수 장비입니다

.
㈜엔티렉스는 G.INS 제품군의 첫 제품으로 NT-ARSv1을 출시하게 되었습니다.

 

 NT-ARSv1(Attitude Reference System)란?

 

자이로센서와 가속도센서를 융합하여 각도를 추정할때,

흔히 공간상의 3개 자세중에서,

z축 중심의 회전인 yaw를 제외하고,

pitch와 roll을 측정하는 장비를 ARS라고 합니다.

ARS를 만들기 위해서는

3축 가속도 센서와 2축 자이로센서에 

추가로 자이로의 온도특성을 보정하기 위한온도센서,

3개의 센서를 융합하고

필터를 설계하기 위한 MCU가 포함됩니다.

만약, Yaw까지 측정한다면, 흔히 AHRS라고 부릅니다.


ARS(Attitude Reference System)는

관성항법장치들 중에서

직행방향과 측면방향을 중심으로 회전하는

각도(Roll,Pitch)를 의미합니다.


저희 NT-ARSv1은

32 비트 ARM Cortex-M3 마이크로프로세서를 탑재하여

3축 가속도센서, 2축 자이로센서의 데이터를 사용하여

6개의 3차원 자세정보(X, Y, Z, ROLL, PITCH, YAW) 중

ROLL 과 PITCH의 각을 구하는 ARS 모듈로써,

Roll과 Pitch의 각도와 각속도를

사용자에게 RS232나 CAN통신으로 

라디안(radian) 단위로 출력해 주도록 설계되어 있습니다.
저희 NT-ARSv1은

-. 소형 항공기의 자세측정이나

-. 로봇의 특정 지점의 절대각도

-. 세그웨이와 같은 밸런싱로봇의 자세측정

등에 활용할 수 있습니다.

 

NT – ARSv1 제품 특징 

 

NT-ARSv1은 RS232통신과 CAN통신이 지원됩니다.
   흔히 쓰이는 RS232통신을 사용하여

   사용자가 쉽게 접근할 수 있고,

   장거리 멀티 통신인 CAN(Control Area Network)을 인터페이스로 사용함으로

   주 메인 컨트롤러보드에서의 장착을 벗어나,

   로봇의 중심에서 정확한 각도를 검출하여 사용자에게 알려줄 것입니다.


 NT-ARSv1은

센서 특성에 따라 오차가 발생하는 것을 줄이기 위해,

출하 단계 에서 모든 Calibration을 마치고 출고합니다.
따라서, 처음 전원 인가 시 Booting 시간을 제외하고

별도의 대기 상태가 필요 없습니다.


또한 사용자가 편의에 따라 Calibration을 할 수 있도록

Software 명령어를 준비해 두었습니다.


NT-ARSv1은

1.6T의 알루미늄 케이스 타입으로 소형화 하여 제작하였기 때문에,

큰 충격에서도 제품을 보호할 수 있습니다.

 

*NT ARS Source Code

* 비주얼 베이직 6.0에서  MSComm을 이용하여
  ARS 각도를 측정하기 위한 Form화면을 구성하였습니다.

* MSComm과 CommandButton 2개  TextBox 1개를 사용하였습니다.
  MSComm : Rs232c통신을 하기 위한 컨트롤
  CommandButton : Connect , Disconnect
  TextBox : ARS변환 각도를 보여줌

* MSComm Commport는 연결된 3번을 입력해 주었고
*  InputLen을 1로 주어 입력버퍼에서 8bit씩 받게끔 해주었습니다.

일반적인 통신 설정에서 9600 bps만 115,200 bps로 주었습니다.
1초당 115,200씩 전송된다는 의미 입니다.
따라서  14,400 byte 씩 전송이 되겠지요
* RThreshold
  이벤트가 발생되기 전에 수신할 문자의 개수를 설정하는 것인데
  여기서는 0으로 주어도 상관없습니다.

Private Sub Command1_Click()

   Dim FileName As String
   MSComm1.CommPort = 3
   MSComm1.Settings = “115200,n,8,1″
   MSComm1.PortOpen = True

     ' PC와 ARS를 연결 MSComm1을 115200 bps , Non Praity , 8bit , Stop bit 1 로 설정

 

   FileName = InputBox(“저장할 파일명을 입력하세요.”)
   If FileName = “” Then
      If MSComm1.PortOpen = False Then
          Exit Sub
      End If
    End If

       '만약 Port가 연결되지 않았다면 구동하지 않음

 

Open App.Path & “\” & FileName & “.txt” For Output As #1
Print #1, “ARS(Attitude Reference System) Pitch,Roll (각도)값의 변경에 따라 메모장.txt로 나타내기” & vbCrLf
MSComm1.Output = <CAH>

      'MSComm1에 각도값을 입력 , 각도값 : <CAH>

 

Command1.Enabled = True
Command2.Enabled = False
Exit Sub
End Sub

————————————————————

Private Sub Co

Command2_Click()

Close #1
If MSComm1.PortOpen = False Then
Exit Sub
End If
End Sub

Command2 버튼을 클릭할 경우 닫기

————————————————————

Private Sub MSComm1_OnComm()
If MSComm1.PortOpen = False Then
Exit Sub
End If

Static BUF As String
Static tmpBuf As String
tmpBuf = MSComm1.Input

정적변수로 선언한 tmpBuf를 MSComm1 수신버퍼로 선언

If tmpBuf = “<” Then
BUF = “”
End If

만약 tmpBuf = “<”라면  BUF  와 tmpBuf 문자열을 결합

BUF = BUF & tmpBuf
If tmpBuf = “>” Then
Text1.Text = Text1.Text & BUF & vbCrLf

만약 tmpBuf = “>”라면  Text1.Text에 Text1.Text 와
BUF , tmpBuf 문자열을 결합한 것을  대입

Print #1, BUF 
End If
Text1.SelStart = Len(Text1.Text) + 1
End Sub

* ARS 각도를 측정하기 위한 Source Code 입니다.
* PC 통신포트는 COM3, 통신 속도는 115200BPS , Non Parity, 8 Data Bit, 1 Stop Bit를 설정하였습니다.

* 결과

 
 

아두이노(Arduino)에서 NT-ARSv1의 데이터를 받아보자

오늘은 아주 예전에 만들었던 ARS 모듈과 아두이노 이야기를 할려고합니다.

예전에 Pitch와 Roll각을 측정하는 모듈로 NT-ARSv1이라는 작품활동을 했던 적이 있는데요.

이 아이를 요즘 제가 관심을 가지는 아두이노에서 다루는 걸 보여드릴려구요.

예전에 몇몇 분들께서 아두이노에서의 예제를 요청하셨던 적이 있는데... 이제서야 올리게 되네요. (죄송합니다.ㅠㅠ) 일단, 이 글에서 테스트 되는 아두이노 보드는 Arduino MEGA ADK[판매 페이지 바로가기]입니다.  왜 MEGA ADK 버젼을 사용했냐면, 저는 PC에서 데이터를 확인하고 싶었기 때문에 ARS와 시리얼 통신으로 연결될 여분의 시리얼 포트가 더 필요했기 때문입니다. Arduino MEGA ADK는 총 4개의 시리얼 포트를 가지고 있어서 선정했구요.

그런데 연결하다보니 약간의 문제를 만났네요. 어떤 문제냐면, NT-ARSv1의 시리얼통신 출력은 RS232신호로 나온다는 겁니다. 만약 UNO나 MEGA ADK의 기본 시리얼 포트에 연결한다면 문제가 없는데, 이 시리얼포트는 PC와의 연결및 모니터링으로 남겨두면, MEGA ADK의 나머지 시리얼포트는 UART신호로, 즉 TTL 레벨의 신호를 받는 포트들입니다. 그래서 할 수 없이 ILX232칩 처럼 RS232신호와 UART 신호를 변환하는 기능이 부가적으로 필요합니다. 직접 구현해도 되지만, LK EMBEDDED라는 회사의 변환모듈 URS232라는 모델[판매페이지 바로가기]을 그냥 사용했습니다.

그러나 이 아이도 약간 이상합니다. 판매페이지에서 이 회사가 제시하는 연결 포트들의 핀맵은 약간 혼돈이 올 수 있습니다. 일단

NT-ARSv1의 핀맵을 보면, 2번 3번의 TX, RX가 있습니다. 이걸 URS232라는 모듈의 RS의 RX, TX단자에 연결합니다. 

아래 연결도를 보시면

왜.. 왜 Fritzing에서 사용자 지정 부품 만들기가 이리도 잘 안되는 걸까요..ㅠㅠ 그래서 그냥 메모지로 URS232와 NT-ARSv1을 표현했습니다. 제가 위에서 혼돈이 있을 수 있다는 것은 URS232의 TTL측 TX는 아두이노 ADK의 TX1에, URS232의 TTL측 RX는 ADK의 RX1에 연결해야합니다. 약간 혼돈스러워서 URS232모듈에서 사용하고 있는 ILX232N이라는 칩의 데이터시트와 비교해 보니, 이 모듈의 TTL측 핀맵에서 TTL_RX라고 표기되어 있는 부분은 실제로 output of recieve data 단자였습니다. 아무튼 어떤 이윤지는 몰라도 모듈 제조사는 이렇게 표현했네요. 그래서 위 그림처럼 결선하시면 아두이노 ADK 보드와 NT-ARSv1과의 연결을 위해 URS232를 사용할 수 있습니다. 이제 준비는 되었구요.

오늘의 목적인 NT-ARSv1의 데이터를 Arduino에서 읽기 위해 Arduino IDE에서 작성한 예제 코드를 보여드리면

// initialize each variables
char incomingByte = 0;
int resultValues = 0;
int consideringMinusSign = 1;
int selectingValuesFromARS = 0;
 
// The output values of NT-ARSv1 are 1000 times in radians
float scaleFactorOfARS = 0.001;
float rad2degree = 180 / 3.141592;
 
float rollAngle = 0;
float pitchAngle = 0;
float rollVel = 0;
float pitchVel = 0;
 
void setup() {
  // initialize serial and serial1 communications at 115200 bps:
  Serial.begin(115200); 
  Serial1.begin(115200);
}
 
void loop() {
  // Command to ARS for getting result via serial communication
  // ex) '<CAO> : to get values one time.
  // ex) '<CAH> : to get values continuesly.
  // ex) '<CAE> : to stop getting values.
  Serial1.write(Serial.read());
 
  if (Serial1.available() > 0) {
    incomingByte = Serial1.read();
 
    // Operation minus sign.
    if (incomingByte == '-') {
      consideringMinusSign = -1;
    }
 
    if (incomingByte >= '0' && incomingByte <= '9') {
      resultValues = resultValues*10 + incomingByte - '0';
    }
    if (incomingByte == ',' || incomingByte == '>') {
      //Serial.println("Your Command is : " + userCommander);
 
      resultValues = resultValues * consideringMinusSign;
      consideringMinusSign = 1;
      selectingValuesFromARS += 1;
 
      switch(selectingValuesFromARS) {
        case 1 :
          // getting roll angle as degree
          rollAngle = resultValues * scaleFactorOfARS * rad2degree;
          Serial.println(" ========================= ");
          Serial.print(" Roll Degree = ");
          Serial.println(rollAngle);
          break;
        case 2 :
          // getting pitch angle as degree
          pitchAngle = resultValues * scaleFactorOfARS * rad2degree;
          Serial.print(" Pitch Degree = ");
          Serial.println(pitchAngle);
          break;
        case 3 :
          // getting roll anglular velocity as degree
          rollVel = resultValues * scaleFactorOfARS * rad2degree;
          Serial.print(" Roll Vel. Degree = ");
          Serial.println(rollVel);
          break;
        case 4 :
          // getting pitch anglular velocity as degree
          pitchVel = resultValues * scaleFactorOfARS * rad2degree;
          Serial.print(" Pitch Vel. Degree = ");
          Serial.println(pitchVel);
          Serial.println(" ========================= ");      
          break;
      }
      resultValues = 0;
    }
    if (incomingByte == '>') {
      selectingValuesFromARS = 0;
    }
  }
}

입니다.

해당 코드에 대한 설명을 잠시 드리면, 먼저 사용자가 Arduino IDE의 시리얼모니터링을 켜서 테스트한다면, ARS의 명령을 입력하도록 하고 있습니다. 23번부터 26번행까지 설명되어 있지만, <CAO>라고 입력하면 데이터를 한 번 출력해 줍니다.

NT-ARSv1은 출력되는 데이터의 형식이 괄호로 쌓여서 <roll 각, pitch 각, roll 각속도, pitch 각속도>의 형태로 됩니다. 거기다 시리얼 통신으로 텍스트로 날라왔으니 문자입니다. 또 자릿수도 생각하고 부호도 생각해야합니다. 그 부분을 고려하는 코드들입니다. 그리고, 확인을 위해 각각 해당값을 출력하고 있구요. 이미 아두이노를 사용하고 계신 분들이라면 손쉽게 NT-ARSv1을 아두이노에서 사용하실 수 있을 것입니다.

위 코드를 실행하고 난 결과는

입니다. 시리얼 모니터 도구에서 <CAO>라고 입력하고 SEND하시면 나타나는 결과입니다. 이 예제는 ARS를 대상으로 MATLAB[바로가기]과 Python[바로가기]에서 시리얼 통신을 하던 예제를 문법에 맞게 변환만 한 것입니다. (중간중간의 주석에 있는 영어 문법으로 태클걸기 없기...ㅠㅠ 이놈의 영어 울렁증이...ㅠㅠ) 마지막으로 이 글은 ntrexgo.com에도 동시 기고 되었습니다.^^


아두이노의 STRING 클래스를 이용하여 NT-ARSv1의 데이터 받아보기

 

얼마전에 NT-ARSv1이라고 하는 아주 예전에 개발했던 모듈의 데이터를 아두이노로 받아보는 것을 이야기했었습니다.[바로가기] 당시에는 그냥 ARS의 데이터가 4개의 값을 한 세트로 전송을 하니까 그걸 각각 숫자로 된 변수로 받는 아주 단순한 예제를 보였습니다. 특히 아두이노의 loop()함수를 반복문으로 그대로 사용하다보니 약간의 혼선이 있을 수도 있고, 또 아두이노의 String 클래스에 대해서도 살짝 이야기할겸, 이번에는 아두이노의 String 클래스를 이용해서 NT-ARSv1의 데이터를 받아보는 예제를 다뤄볼까 합니다.

일단, 하드웨어적인 연결은 [바로가기]와 동일합니다. Arduino ADK MEGA와 적절한 UART to RS232 컨버터를 사용하여 NT-ARSv1과 연결했습니다. 그건 동일하니 [바로가기]를 참조해 주시고요. 그래도 글이 글이니 연결도 하나는 그대로 사용하죠^^

이번에는 처음 이야기한것 처럼 몇몇개의 함수로 구현할 겁니다. 먼저 보여드릴 예제는 getARSresultAtOnce() 함수입니다.

String getARSresultAtOnece() {
  String outputValuesOfARS = "";
  
  Serial1.print("&lt;CAO&gt;");
  
  delay(2);
  
  while (Serial1.available()) {
    char incomingChar = Serial1.read();
    outputValuesOfARS += incomingChar;
  }
  
  return outputValuesOfARS;
}

이 함수는 NT-ARSv1의 데이터를 String의 형태로 저장하는 것이 목적입니다. 여러가지 형태로 다양하게 사용하실려면 이 함수만 사용하신 다음 간편하게 응용하시면 될듯합니다. 주의하실것은 반환되는 형태가 String이라는 것입니다.^^. 그리고 함수에도 나와있지만 <CAO> 명령을 사용해서 한번만 데이터를 받습니다. 아두이노에서 다양한 응용을 하시는 경우 <CAH>처럼 일정 시간간격으로 계속 데이터를 받는 것보다는 <CAO> 명령을 사용하실 경우가 더 많다는 생각이 들었을 뿐입니다.^^. 그리고  6번행의 delay()함수는 <CAO> 명령을 하달한 다음 바로 시리얼 데이터를 읽도록 하면 데이터가 도착하기 전에 지나가버려서, 사용한겁니다. 물론 데이터가 실제로 들어올때까지 기다리라는 조건문을 사용해도 되었겠지만, 이런 종류의 예제를 배포할때 그렇게하면 또 데이터가 들어오지 않는 어떤 다른 이유가 있을때의 방어도 해야할듯해서 ... 그래서 그냥 이렇게 둡니다.^^.

그리고 8번부터 11번에서는 한 문자씩 들어오는 데이터를 하나의 String으로 합쳐둡니다. 여기서도 사실 에러에 대한 방어코드를 둘수도 있겠지만, 그냥 예제니까요. 일단 생각나는 몇몇 방어대책은 <와 >로 데이터는 쌓여있는지, 콤마(,)는 세개가 다 들어왔는지 등을 확인하면 데이터가 100% 잘 들어왔는지 아닌지 확인할 수 있을 겁니다.

그리고 getARSresultAtOnce()를 이용해서 NT-ARSv1이 출력하는 <Roll, Pitch, Roll_vel, Pitch_vel>이렇게 네 개의 데이터 중 사용자가 선택할 수 있는 함수를 별도로 두었습니다.

double getRollAngle() {
  String outputValuesOfARS = getARSresultAtOnece();
  
  int firstComma = outputValuesOfARS.indexOf(',');

  String rollAngleST = outputValuesOfARS.substring(1, firstComma);
  double rollAngle = rollAngleST.toInt() * 0.001;
  
  return rollAngle;
}

그 중 위의 함수는 getRollAngle() 이름에서도 알 수 있듯이 Roll각도만 추출하는 겁니다. double형을 반환한다고 되어 있는 것처럼 반환되는 값은 라디안(Radian)단위입니다. indexOf()함수를 이용해서 첫 번째 콤마의 위치를 반환받은 다음, substring()함수를 이용해서 잘라내서 따로 저장을 한 것입니다. 그리고 NT-ARSv1은 라디안 단위를 1000을 곱해서 출력하므로, 다시 1000을 나눠줘서 깔끔하게 라디안단위로 받아 볼 수 있게 한 것입니다.

void setup() {
  // initialize serial and serial1 communications at 115200 bps:
  Serial.begin(115200);
  Serial1.begin(115200);
}

void loop() {
  
  double rad2degree = 180/3.141592;

  double rollAngle = getRollAngle();
  Serial.print(" Roll Angle is ");
  Serial.print(rollAngle*rad2degree);
  Serial.println(" degree.");
  
  double pitchAngle = getPitchAngle();
  Serial.print(" Pitch Angle is ");
  Serial.print(pitchAngle*rad2degree);
  Serial.println(" degree.");
  
  double rollAngVel = getRollAngVel();
  Serial.print(" Roll Angular velocity is ");
  Serial.print(rollAngVel*rad2degree);
  Serial.println(" degree/second.");
  
  double pitchAngVel = getPitchAngVel();
  Serial.print(" Pitch Angular velocity is ");
  Serial.print(pitchAngVel*rad2degree);
  Serial.println(" degree/second.");
  
  while(true);
}

// Getting output data of NT-ARSv1 after "&lt;CAO&gt;" commander.
// The resulting data is stored in the form of a String.
String getARSresultAtOnece() {
  String outputValuesOfARS = "";
  
  Serial1.print("&lt;CAO&gt;");
  
  delay(2);
  
  while (Serial1.available()) {
    char incomingChar = Serial1.read();
    outputValuesOfARS += incomingChar;
  }
  
  return outputValuesOfARS;
}

double getRollAngle() {
  String outputValuesOfARS = getARSresultAtOnece();
  
  int firstComma = outputValuesOfARS.indexOf(',');

  String rollAngleST = outputValuesOfARS.substring(1, firstComma);
  double rollAngle = rollAngleST.toInt() * 0.001;
  
  return rollAngle;
}

double getPitchAngle() {
  String outputValuesOfARS = getARSresultAtOnece();

  int firstComma = outputValuesOfARS.indexOf(',');
  int secondComma = outputValuesOfARS.indexOf(',', firstComma+1);
  
  String pithchAngleST = outputValuesOfARS.substring(firstComma+1, secondComma);
  double pitchAngle = pithchAngleST.toInt() * 0.001;

  return pitchAngle;
}

double getRollAngVel() {
  String outputValuesOfARS = getARSresultAtOnece();
  
  int firstComma = outputValuesOfARS.indexOf(',');
  int secondComma = outputValuesOfARS.indexOf(',', firstComma+1);
  int thirdComma = outputValuesOfARS.indexOf(',', secondComma+1);
  
  String rollAngVelST = outputValuesOfARS.substring(secondComma+1, thirdComma);
  double rollAngVel = rollAngVelST.toInt() * 0.001;

  return rollAngVel;
}

double getPitchAngVel() {
  String outputValuesOfARS = getARSresultAtOnece();
  
  int firstComma = outputValuesOfARS.indexOf(',');
  int secondComma = outputValuesOfARS.indexOf(',', firstComma+1);
  int thirdComma = outputValuesOfARS.indexOf(',', secondComma+1);
  
  String pithchAngVelST = outputValuesOfARS.substring(thirdComma+1, outputValuesOfARS.length() - 3);
  double pithchAngVel = pithchAngVelST.toInt() * 0.001;
  
  return pithchAngVel;
}

위 코드가 전체 코드입니다. 딱히 뭐 별다를 건 없습니다만, 살짝 함수로 만들었고, 좀 있어보이고 String 클래스를 쓰는 척(^^)했습니다. 그러나 저야 아두이노의 String 클래스도 한번 들여다 볼겸 이렇게 한거고, 실제로는 [바로가기]에서 한 것 처럼 간단히 구현해보는게 더 쉬울거라는 생각도 듭니다. 단, loop()문안에 있는 걸 별도로 반복문을 사용하셔서 구현하셔야 하지만 말이죠.

그렇게 구현된 것을 실행한 화면입니다. 함수로 예제를 꾸몄으니 이제 사용하시면 되지 않을까 합니다. 아 그리고, 혹시나 흉보실 까바 구구절절한 변명하나 하면, 보통 사용하는 분들은 Pitch, 혹은 Roll 이 두개의 각도중 하나만 사용하시는 경우가 더 많습니다. 그래서 4개의 값을 각 각 하나씩 함수로 만든 것입니다. 그리고, 그냥 저도 최근에 꽤나 흥미를 느끼는 이 아두이노에 대해 살짝 저 공부하고 있어요~~라고 티도 팍팍 내고 싶었구요^^. 아무튼 추석이네요. 다들 추석 잘 보내세요^^ (아참 이 글은 ntrexgo.com에도 약간 단어의 선택은 다르지만, 동시에 기고되었습니다.^^)

 

'IoT' 카테고리의 다른 글

MQTT 연동 IoT 서비스  (0) 2021.12.10