본문 바로가기

Hardware/Arduino and Friends

아두이노의 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("<CAO>");
  
  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에도 약간 단어의 선택은 다르지만, 동시에 기고되었습니다.^^)

반응형