본문 바로가기

Project/Jaguar 4X4 Human Tracking

6/28 About NGIMU Protocol (미완)

728x90

- NGIMU의 Data Sheet 분석 후 작성

 

  • MGIMU의 모든 통신은 OSC로 Encode된다
    • Encode : 어떤 정보를 정해진 규칙에 따라 부호화/암호화 하는 것
    • OSC (Open Sound Control) : 사운드 관련 퍼포먼스 및 연주 정보 데이터 전송을 위해 MIDI 이후에 개발된 플렛폼
    • Network를 이용한 protocol이며 UDP를 사용한다
    • TCP(Transmission Control Protocol)/IP : Data 통신 시 확인 msg를 받은 후 전송
    • UDP(User Datagram Protocol) : 확인 과정 없이 단방향으로 data 전송
  • UDP를 통해 OSC를 사용할 경우, 사용자는 message 수신/송신할 port를 각각 정하고 Third Party device에는 그 값들이 반전되어 들어간다
    • Ex) Port 8000 for Receiving(RX), Port 8001 for Transmitting(TX) : Third Party device는 8000 port에 data를 transmit하고 8001 port에서 receive
  • USB, Serial이나 SD 카드에 기록된 data set은 SLIP packet으로 OSC Encode 됨

 

- OSC 관련 내용

  • OSC Messgae는 network를 통해 전송되므로 message를 보낼 곳과 받을 곳을 정의해야 함
  • 통신 전 미리 정의해야 할 내용들은 아래와 같다.
  • IP Address : Message를 보낼 장치의 IP address. 한 SW에서 다른 computer로 data를 보내자 하면 localhost IP address(127.0.0.1)를 사용하면 된다
    • 127.0.0.1은 localhost 또는 loopback 주소로써, network상에서 자신의 컴퓨터를 나타내는 가상적인 주소이다. 즉 자신에게 다시 network 입력이 들어오게 한다
    • 보통 Application test나 같은 computer 내에서 다른 Application끼리 통신하기 위해 사용한다

ifconfig 명령어를 통해 볼 수 있는 localhost(loopbck) 주소

  • Port : Message를 Send/Transmit 할 port number
  • Address Pattern : 보통 URL과 비슷한 형식을 가짐. 같은 port에서 나오는 서로 다른 message들을 구분하기 위해 사용
    • ex) /sensor/raw
  •  Actual Message : 실제로 전송/수신하는 message data. Data type을 정의해줘야 함
    • 통신 data는 아래처럼 /LABEL + data의 형태로 이뤄져있음. LABEL은 data 구분용
/sensors/raw/x 0.12354
/sensors/filtered/x 0.2
/sensors/linear/x 0.23
/magnitueds/gyro/ 0.132

 

 

- OSC 통신 구현 과정

  • 장치로 전송되는 OSC Message는 Interchangeable한 Numerical Argument Types (int32, float32, int64, OSC time tag, 64-bit double, character, boolean, nil, infitnitum)과 blob, string argument type을 사용한다
  • 장치로 전송되는 OSC address pattern은 '?', '*', '[]', '{}'와 같은 특수 문자를 포함하지 않는다
  • OSC Message는 OSC bundle을 통해 전송되나 message scheduling은 무시된다
    • Bundle : Map 형태로 구현된 data의 묶음

1) 장치로부터의 Data

  • 장치로부터의 data는 single OSC Messgae를 같는 timestamped OSC bundle 형태로 전송된다
  • Button, Auxiliary serial, Serial Message를 제외한 모든 Message들은 정해진 baud rate데로 지속적으로 전송된다
  • OSC bundle의 timestamp는 OSC time tag로, 총 64bit-fixed-point number이다
    • 첫 32bits는 1900년 1월 1일 00:00부터의 초, 뒤의 32bits는 초의 소숫점을 200 picoseconds(10^-12) 까지의 정밀도로 나타낸다
    • Internet NTP timestamp를 사용한다
    • Fixed Point Number : 소수부의 자릿수를 정하여 고정된 자릿수의 소수를 표현하는 방식
  • OSC time tag는 먼저 64bits unsigned integer로 변환 후 2^32로 나누는 방식을 통해 10진수로 변환 가능하다
    • 정밀도의 부족으로 인한 Error를 방지하기 위해 double-precision floating-point type(float 64)을 사용하여 계산한다

 

- OSC Send

  • 수신받을 컴퓨터의 IP Adress, Port Number 설정 후 Label을 붙여 송신
    • Ex) 택배 배달
    • IP Address : 받을 집의 주소
    • Port : 받을 사람의 방 호수
    • Label : 보낸 사람의 이름
    • 위 내용들을 적어 OSC라는 배달부를 통해 전달

- OSC Receive

  • 송신한 computer에서 보낸 Port를 설정해 개방
    • 택배 도착 후 방문(Port)를 열고 해당 message 취득

 

 

 

  • 해당 센서의 source code에서 C++17부터 도입된 <filesystem>을 사용하므로 compiler version을 C++17을 지원하는 compiler로 upgrade 하거나 C++17을 사용하게 되어있는지 확인

 

$ gcc --version

-> gcc-7 (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
  • gcc 버전 확인
  • gcc 버전이 C++17을 지원하지 않는 버전이면 upgrade

 

$ sudo apt install gcc-8 g++-8
  • 최신 버전의 gcc 설치

 

$ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 700 --slave /usr/bin/g++ g++ /usr/bin/g++-7
$ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 800 --slave /usr/bin/g++ g++ /usr/bin/g++-8
  • 최신 버전의 gcc를 defalut로 설정

 

$ gcc --version

-> gcc (Ubuntu 8.4.0-1ubuntu1~18.04) 8.4.0
  • 설정된 gcc 버전 확인

 

 

 

- Source Code 분석

https://github.com/dinimar/ros-ngimu/tree/master

 

GitHub - dinimar/ros-ngimu: ROS package for NGIMU imu

ROS package for NGIMU imu . Contribute to dinimar/ros-ngimu development by creating an account on GitHub.

github.com

 

1. NgimuReceive.cc 분석 : NGIMU로부터의 message들을 receive 하기 위한 module

 

- Include 부분

// Includes

#include "NgimuReceive.h"
#include <stddef.h>
#include <stdio.h> // snprintf
  • stddef.h : 아래의 일반적으로 사용되는 pointer, variable, type을 선언
    • ptrdiff_t : 두 pointer 차이 type에 대한 typedef
    • size_t : sizeof에서 return 하는 값 type에 대한 typedef
    • wchar_t : wide character constant에 대한 typedef

 

- Inlcude된 NgimuReceive.h : NGIMU의 각 Category() 별 data들에 대한 structure를 정의. 관련 함수들 선언

  • /sensors
  • /quaternion
  • /euler
  • /temperature
// NgimuReceive.h

#ifndef NGIMU_RECEIVE_H
#define NGIMU_RECEIVE_H

#ifdef __cplusplus
extern "C" {
#endif

//------------------------------------------------------------------------------
// Includes

#include "Osc99/Osc99.h"

//------------------------------------------------------------------------------
// Definitions

/**
 * @brief Timestamp and argument values for "/sensors" message.
 * Data about the sensor values
 */
typedef struct {
    OscTimeTag timestamp;
    float gyroscopeX;
    float gyroscopeY;
    float gyroscopeZ;
    float accelerometerX;
    float accelerometerY;
    float accelerometerZ;
    float magnetometerX;
    float magnetometerY;
    float magnetometerZ;
    float barometer;
} NgimuSensors;

/**
 * @brief Timestamp and argument values for "/quaternion" message.
 * Quaternion output of the on-board AHRS algorithm describing the 
 * orientation of the device relative to the Earth (NWU convention)
 */
typedef struct {
    OscTimeTag timestamp;
    float w;
    float x;
    float y;
    float z;
} NgimuQuaternion;

/**
 * @brief Timestamp and argument values for "/euler" message.
 * Eluer angle output of the on-board AHRS as same as quaternion
 */
typedef struct {
    OscTimeTag timestamp;
    float roll;
    float pitch;
    float yaw;
} NgimuEuler;

/**
 * @brief Timestamp and argument values for "/temperature" message.
 * Temperature measurement data of the divice`s on-board temperature sensor
 */
typedef struct {
    OscTimeTag timestamp;
    float temp1;
    float temp2;
} NgimuTemperature;

//------------------------------------------------------------------------------
// Function prototypes

void NgimuReceiveInitialise();
void NgimuReceiveSetReceiveErrorCallback(void (*newReceiveErrorCallback)(const char* const errorMessage));
void NgimuReceiveSetSensorsCallback(void (*newSensorsCallback)(const NgimuSensors ngimuSensors));
void NgimuReceiveSetQuaternionCallback(void (*newQuaternionCallback)(const NgimuQuaternion ngimuQuaternion));
void NgimuReceiveSetEulerCallback(void (*newEulerCallback)(const NgimuEuler ngimuEuler));
void NgimuReceiveSetTemperatureCallback(void (*newTemperatureCallback)(const NgimuTemperature ngimuEuler));
void NgimuReceiveProcessSerialByte(const char byte);
void NgimuReceiveProcessUdpPacket(const char * const source, const size_t sourceSize);

#ifdef __cplusplus
}
#endif

#endif

//------------------------------------------------------------------------------
// End of file

 

 

// NgimuReceive.h

#ifdef __cplusplus
extern "C" {
#endif

.....
.....
.....

#ifdef __cplusplus
}
#endif
  • extern "C" 

 

// NgimuReceive.h

// Includes

#include "Osc99/Osc99.h"
  • OSC99 : Embedded system과 함께 사용하도록 개발된 portable ANSI C99 호환 OSC library
/**
 * @file Osc99.h
 * @author Seb Madgwick
 * @brief Main header file for the library.  This is the only file that needs to
 * be included when using the library.
 *
 * OSC99 is a portable ANSI C99 compliant OSC library developed for use with
 * embedded systems.  OSC99 implements the OSC 1.0 specification including all
 * optional argument types.  The library also includes a SLIP module for
 * encoding and decoding OSC packets via unframed protocols such as UART/serial
 * as required by the OSC the 1.1 specification.
 *
 * The following definitions may be modified in OscCommon.h as required by the
 * user application: LITTLE_ENDIAN_PLATFORM, MAX_TRANSPORT_SIZE,
 * OSC_ERROR_MESSAGES_ENABLED.
 */

#ifndef OSC99_H
#define OSC99_H

//------------------------------------------------------------------------------
// Includes

#ifdef __cplusplus
extern "C" {
#endif

#include "OscAddress.h"
#include "OscError.h"
#include "OscPacket.h"
#include "OscSlip.h"

#ifdef __cplusplus
}
#endif

#endif
//------------------------------------------------------------------------------
// End of file

 

 

// NgimuReceive.h

//------------------------------------------------------------------------------
// Definitions

/**
 * @brief Timestamp and argument values for "/sensors" message.
 * Data about the sensor values
 */
typedef struct {
    OscTimeTag timestamp;
    float gyroscopeX;
    float gyroscopeY;
    float gyroscopeZ;
    float accelerometerX;
    float accelerometerY;
    float accelerometerZ;
    float magnetometerX;
    float magnetometerY;
    float magnetometerZ;
    float barometer;
} NgimuSensors;

/**
 * @brief Timestamp and argument values for "/quaternion" message.
 * Quaternion output of the on-board AHRS algorithm describing the 
 * orientation of the device relative to the Earth (NWU convention)
 */
typedef struct {
    OscTimeTag timestamp;
    float w;
    float x;
    float y;
    float z;
} NgimuQuaternion;

/**
 * @brief Timestamp and argument values for "/euler" message.
 * Eluer angle output of the on-board AHRS as same as quaternion
 */
typedef struct {
    OscTimeTag timestamp;
    float roll;
    float pitch;
    float yaw;
} NgimuEuler;

/**
 * @brief Timestamp and argument values for "/temperature" message.
 * Temperature measurement data of the divice`s on-board temperature sensor
 */
typedef struct {
    OscTimeTag timestamp;
    float temp1;
    float temp2;
} NgimuTemperature;

//------------------------------------------------------------------------------
// Function prototypes

void NgimuReceiveInitialise();
void NgimuReceiveSetReceiveErrorCallback(void (*newReceiveErrorCallback)(const char* const errorMessage));
void NgimuReceiveSetSensorsCallback(void (*newSensorsCallback)(const NgimuSensors ngimuSensors));
void NgimuReceiveSetQuaternionCallback(void (*newQuaternionCallback)(const NgimuQuaternion ngimuQuaternion));
void NgimuReceiveSetEulerCallback(void (*newEulerCallback)(const NgimuEuler ngimuEuler));
void NgimuReceiveSetTemperatureCallback(void (*newTemperatureCallback)(const NgimuTemperature ngimuEuler));
void NgimuReceiveProcessSerialByte(const char byte);
void NgimuReceiveProcessUdpPacket(const char * const source, const size_t sourceSize);
  • NGIMU의 category별 data들을 struct 형식으로 묶어놓음
    • /sensor
    • /quaternion
    • /euler
    • /temperature
  • 그리고 data receiving에 필요한 여러 함수들의 prototype들이 정의되어 있음

 

// NgimuReceive.cc

//------------------------------------------------------------------------------
// Variable declarations

static OscSlipDecoder oscSlipDecoder;
static void (*receiveErrorCallback)(const char* const errorMessage);
static void (*sensorsCallback)(const NgimuSensors ngimuSensors);
static void (*quaternionCallback)(const NgimuQuaternion ngimuQuaternion);
static void (*eulerCallback)(const NgimuEuler ngimuEuler);
static void (*temperatureCallback)(const NgimuTemperature ngimuTemperature);
  • Variable 선언 부분

 

 

- 변수 분석

1) OscSlipDecoder : SLIP 관련 부분

// OscSlip.h

/**
 * @brief OSC SLIP decoder buffer size.  If a packet size exceeds the buffer
 * size then all bytes in the decoder buffer will be discarded.
 */
#define OSC_SLIP_DECODER_BUFFER_SIZE (MAX_TRANSPORT_SIZE)

/**
 * @brief OSC SLIP decoder structure.  Structure members are used internally and
 * should not be used by the user application.
 */
typedef struct {
    char buffer[OSC_SLIP_DECODER_BUFFER_SIZE];
    unsigned int bufferIndex;
    void ( *processPacket)(OscPacket * const oscPacket);
} OscSlipDecoder;
  • 내부적으로 사용되는 structure
  • SLIP(Serial Line Internet Protocol) : TCP/IP가 Serial Communication을 통해 작동할 때 사용하는 Protocol
  • MAX_TRANSPORT_SIZE는 OscCommon.h file에 정의되어 있다
// OscCommon.h

/**
 * @brief Maximum packet size permitted by the transport layer.  Reducing this
 * value will reduce the amount of memory required.
 */
#define MAX_TRANSPORT_SIZE (1472)
  • UDP의 최대 수신 용량이 1472byte

 

2) 나머지 variable들은 Callback function을 receive할 때 새로운 값을 저장하는데 쓰임

 

 

- 함수 분석

1) NgimuReceiveInitialise

/**
 * @brief Initialises module.  This function should be called once on system
 * start up.
 */
void NgimuReceiveInitialise() {
    OscSlipDecoderInitialise(&oscSlipDecoder);
    oscSlipDecoder.processPacket = ProcessPacket;
}

 

 

2)  ~~ Callback

  • 다양한 값들에 대한 Callback function들을 receive함
// NgimuReceive.cc

/**
 * @brief Sets receive error callback function.
 * @param newReceiveErrorCallback Receive error callback function.
 */
void NgimuReceiveSetReceiveErrorCallback(void (*newReceiveErrorCallback)(const char* const errorMessage)) {
    receiveErrorCallback = newReceiveErrorCallback;
}

/**
 * @brief Sets receive "/sensors" callback function.
 * @param newSensorsCallback "/sensors" callback function.
 */
void NgimuReceiveSetSensorsCallback(void (*newSensorsCallback)(const NgimuSensors ngimuSensors)) {
    sensorsCallback = newSensorsCallback;
}

/**
 * @brief Sets receive "/quaternion" callback function.
 * @param newQuaternionCallback "/quaternion" callback function.
 */
void NgimuReceiveSetQuaternionCallback(void (*newQuaternionCallback)(const NgimuQuaternion ngimuQuaternion)) {
    quaternionCallback = newQuaternionCallback;
}

/**
 * @brief Sets receive "/euler" callback function.
 * @param newEulerCallback "/euler" callback function.
 */
void NgimuReceiveSetEulerCallback(void (*newEulerCallback)(const NgimuEuler ngimuEuler)) {
    eulerCallback = newEulerCallback;
}

/**
 * @brief Sets receive "/temperature" callback function.
 * @param newTemperatureCallback "/temperature" callback function.
 */
void NgimuReceiveSetTemperatureCallback(void (*newTemperatureCallback)(const NgimuTemperature ngimuEuler)) {
    temperatureCallback = newTemperatureCallback;
}

 

 

3) NgimuReceiveProcessUdpPacket : Wifi Communication Related

// NgimuReceive.cc

/**
 * @brief Process UDP packet received from NGIMU via Wi-Fi.
 * @param source Address of source byte array.
 * @param sourceSize Source size.
 */
void NgimuReceiveProcessUdpPacket(const char * const source, const size_t sourceSize) {
    OscPacket oscPacket;
    OscPacketInitialiseFromCharArray(&oscPacket, source, sourceSize);
    oscPacket.processMessage = &ProcessMessage;
    OscPacketProcessMessages(&oscPacket);
}
  • OscPacket : OSC 통신의 Packet을 설정하는 structure
  • OscPacket.h에 정의되어 있음
// OscPacket.h

/**
 * @brief Maximum OSC packet size.  The OSC packet size is limited by the
 * maximum packet size permitted by the transport layer.
 */
#define MAX_OSC_PACKET_SIZE (MAX_TRANSPORT_SIZE)

/**
 * @brief OSC packet structure.  Structure members are used internally and
 * should not be used by the user application.
 */
typedef struct {
    char contents[MAX_OSC_PACKET_SIZE];		// 1472
    size_t size;				// Defined in stddef.h
    void ( *processMessage)(const OscTimeTag * const oscTimeTag, OscMessage * const oscMessage);
} OscPacket;
  • MAX_OSC_PACKET_SIZE는 MAX_TRANSPORT_SIZE와 마찬가지로 OscCommon.h file에 1472정의되어 있다
  • OscMessgae는 OscMessage.h file에 정의되어 있다
// OScMessgae.h

/**
 * @brief Maximum string length (excludes terminating null characters) of an OSC
 * address pattern.  This value may be modified as required by the user
 * application.
 */
#define MAX_OSC_ADDRESS_PATTERN_LENGTH (64)

/**
 * @brief Maximum length of an OSC type tag string (includes comma but not
 * terminating null characters).
 */
#define MAX_OSC_TYPE_TAG_STRING_LENGTH (1 + MAX_NUMBER_OF_ARGUMENTS)

/**
 * @brief Maximum combined size (number of bytes) of all arguments that may be
 * contained within an OSC message.  The calculation assumes the worst case of
 * and extra 4 null characters for both the OSC address pattern and the OSC type
 * tag string.
 */
#define MAX_ARGUMENTS_SIZE (MAX_OSC_MESSAGE_SIZE - (MAX_OSC_ADDRESS_PATTERN_LENGTH + 4) - (MAX_OSC_TYPE_TAG_STRING_LENGTH + 4))

/**
 * @brief OSC message structure.  Structure members are used internally and
 * should not be used by the user application.
 */
typedef struct {
    char oscAddressPattern[MAX_OSC_ADDRESS_PATTERN_LENGTH + 1]; // must be first member so that first byte of structure is equal to '/'.  Null terminated.
    char oscTypeTagString[MAX_OSC_TYPE_TAG_STRING_LENGTH + 1]; // includes comma.  Null terminated
    char arguments[MAX_ARGUMENTS_SIZE];
    size_t oscAddressPatternLength; // does not include null characters
    size_t oscTypeTagStringLength; // includes comma but not null characters
    size_t argumentsSize;
    unsigned int oscTypeTagStringIndex;
    unsigned int argumentsIndex;
} OscMessage;
  • OscMessage : OSC Message를 구성하는 Structure
  • oscAddressPattern : 65bytes length. Structure의 첫번째 byte가 '/'와 같아져야 하므로  해당 변수가 반드시 첫번째 member이어야 함
  • oscTypeTagString : 17bytes legnth. ',' 포함

 

  • OscPacketInitialiseFromCharArray : OscPacket.c에 정의되어 있음
  • 실제로 source로부터 받아온 data를 OSC Packet에 저장하는 부분
/**
 * @brief Initialises an OSC packet from byte array.
 *
 * An OSC packet must be initialised before use.  This function is used to
 * initialise an OSC packet from a byte array and is typically of use when
 * constructing an OSC packet from received bytes.
 *
 * Example use:
 * @code
 * OscPacket oscPacket;
 * const char source[] = "/example\0\0\0\0,\0\0"; // string terminating null character is part of OSC message
 * OscPacketInitialiseFromCharArray(&oscPacket, source, sizeof(source));
 * @endcode
 *
 * @param oscPacket OSC packet to be initialised.
 * @param source Byte array.
 * @param numberOfBytes Number of bytes in byte array.
 * @return Error code (0 if successful).
 */
OscError OscPacketInitialiseFromCharArray(OscPacket * const oscPacket, const char * const source, const size_t numberOfBytes) {
    oscPacket->size = 0;		// Initialize oscPacket`s size to zero
    if (numberOfBytes > MAX_OSC_PACKET_SIZE) {
        return OscErrorPacketSizeTooLarge; // error: size exceeds maximum packet size
    }
    while (oscPacket->size < numberOfBytes) {
        oscPacket->contents[oscPacket->size] = source[oscPacket->size];
        oscPacket->size++;	// Put data by source to oscPacket`s contents sequenitally
    }
    oscPacket->processMessage = NULL;	// Make OscPacket`s communication related values to NULL
    return OscErrorNone;	// 0
}
  • OscError는 OscError.h file에 정의되어 있다
    • OscError.h : 모든 Error에 대한 경우 정의

 

static void ProcessMessage(const OscTimeTag * const oscTimeTag, OscMessage * const oscMessage);
  • OscTimeTag는 OscCommon.h file에 정의되어 있다
// OscCommon.h

/**
 * @brief OSC time tag.  Same representation used by NTP timestamps. 64-bit argument
 */
typedef union {
    uint64_t value;

    struct __attribute__((__packed__)) {
        uint32_t fraction;
        uint32_t seconds;
    }
    dwordStruct;

    struct __attribute__((__packed__)) {
#ifdef LITTLE_ENDIAN_PLATFORM
        char byte0; // LSB
        char byte1;
        char byte2;
        char byte3;
        char byte4;
        char byte5;
        char byte6;
        char byte7; // MSB
#else
        char byte7; // MSB
        char byte6;
        char byte5;
        char byte4;
        char byte3;
        char byte2;
        char byte1;
        char byte0; // LSB
#endif
    }
    byteStruct;
} OscTimeTag;
  • OscPacketProcessMessages는 OscPacket.c에 정의되어 있다
// OscPacket.c

/**
 * @brief Processes the OSC packet to provide each OSC message contained within
 * the packet to the user application with the associated OSC time tag (if the
 * message is contained within a bundle).
 *
 * A ProcessMessage function must be implemented within the application and
 * assigned to the OSC packet structure after initialisation.  The
 * ProcessMessage function will be called for each OSC message found within the
 * OSC packet.
 *
 * Example use:
 * @code
 * void ProcessMessage(const OscTimeTag * const oscTimeTag, OscMessage * const oscMessage) {
 * }
 *
 * void Main() {
 *     OscPacket oscPacket;
 *     const char source[] = "/example\0\0\0\0,\0\0\0";
 *     OscPacketInitialiseFromCharArray(&oscPacket, source, sizeof(source) - 1);
 *     oscPacket.processMessage = ProcessPacket;
 *     OscPacketProcessMessages(&oscPacket);
 * }
 * @endcode
 *
 * @param oscPacket OSC packet to be processed.
 * @return Error code (0 if successful).
 */
OscError OscPacketProcessMessages(OscPacket * const oscPacket) {
    if (oscPacket->processMessage == NULL) {
        return OscErrorCallbackFunctionUndefined; // error: user function undefined
    }
    return DeconstructContents(oscPacket, NULL, oscPacket->contents, oscPacket->size);
}
  • Packet 내의 각 OSC message에 OSC Packet을 관련된 OSC time tag와 함께 user Application에 제공하기 위해 OSC Packet을 처리하는 부분 (Message가 bundle 내에 포함되어 있는 경우)
  • ProcessMessage function은 initialization 후 application 내에서 실행되어야 하며 OSC Packet Structure에 할당되어야 한다

-> 실제 data 할당 부분 종료

 

 

 

4) ProcessPacket : Receive한 OSC packet내의 각 message를 위해 실행되는 Callback Function

5) ProcessAddress : OSC Address Pattern에 따라 OSC message를 처리

// NgimuReceive.cc

/**
 * @brief Callback function executed for each message found within received OSC
 * packet.
 * @param oscTimeTag OSC time tag associated with message.
 * @param oscMessage Address of OSC message.
 */
static void ProcessMessage(const OscTimeTag * const oscTimeTag, OscMessage * const oscMessage) {
    const OscError oscError = ProcessAddress(oscTimeTag, oscMessage);
    if ((oscError != OscErrorNone) && (receiveErrorCallback != NULL)) {
        receiveErrorCallback(OscErrorGetMessage(oscError));
    }
}

/**
 * @brief Process OSC message according to OSC address pattern.
 * @param oscTimeTag OSC time tag associated with message.
 * @param oscMessage Address of OSC message.
 * @return Error code (0 if successful).
 */
static OscError ProcessAddress(const OscTimeTag * const oscTimeTag, OscMessage * const oscMessage) {

    // Process known message types
    if (OscAddressMatch(oscMessage->oscAddressPattern, "/sensors")) {
        return ProcessSensors(oscTimeTag, oscMessage);
    }
    if (OscAddressMatch(oscMessage->oscAddressPattern, "/quaternion")) {
        return ProcessQuaternion(oscTimeTag, oscMessage);
    }
    if (OscAddressMatch(oscMessage->oscAddressPattern, "/euler")) {
        return ProcessEuler(oscTimeTag, oscMessage);
    }
    if (OscAddressMatch(oscMessage->oscAddressPattern, "/temperature")) {
        return ProcessTemperature(oscTimeTag, oscMessage);
    }

    // OSC address not recognised
    if (receiveErrorCallback != NULL) {
        static char string[256];
        snprintf(string, sizeof (string), "OSC address pattern not recognised: %s", oscMessage->oscAddressPattern);
        receiveErrorCallback(string);
    }
    return OscErrorNone;
  • OscAddressMatch는 OscAddress.c file에 정의되어 있음
// OscAddress.c

/**
 * @brief Matches an OSC address pattern with a target OSC address.
 *
 * Returns true if the OSC address pattern matches the target OSC address.  The
 * target OSC address cannot contain any special characters: '?', ' *', '[]', or
 * '{}'.
 *
 * Example use:
 * @code
 * OscMessage oscMessage;
 * OscMessageInitialise(&oscMessage, "/example/oscAddress/pattern");
 * if(OscAddressMatch(oscMessage.oscAddressPattern, "/example/oscAddress/pattern") == true) {
 *     printf("Match!");
 * }
 * @endcode
 *
 * @param oscAddressPattern OSC address pattern.
 * @param oscAddress Target OSC address.
 * @return True if the OSC address pattern and target oscAddress match.
 */
bool OscAddressMatch(const char * oscAddressPattern, const char * const oscAddress) {
    return MatchLiteral(oscAddressPattern, oscAddress, false);
}
  • Receive받은 OSC Address를 target OSC address와 비교
  • Address가 일치할 경우 'true'를 return
  • MatchLiteral function은 동일한 file 내에 선언되어있음
// OscAddress.c

/**
 * @brief Matches literal OSC address pattern with target OSC address.
 *
 * The OSC address pattern is initially assumed to be literal and not to contain
 * any special characters: '?', ' *', '[]', or '{}'.  If a special character is
 * found then the result of MatchExpression is returned.  Matching literal OSC
 * address patterns is faster than matching OSC address patterns that contain
 * special characters.
 *
 * This is an internal function and cannot be called by the user application.
 *
 * @param oscAddressPattern First character of OSC address pattern.
 * @param oscAddress First character of target OSC address.
 * @param isPartial Flag indicating if a partial match is acceptable.
 * @return True if OSC address pattern and target OSC address match.
 */
static bool MatchLiteral(const char * oscAddressPattern, const char * oscAddress, const bool isPartial) {
    while (*oscAddressPattern != '\0') {
        if (*oscAddress == '\0') {
            if (isPartial == true) {
                return true;
            } else {
                return MatchExpression(&oscAddressPattern, &oscAddress, isPartial); // handle trailing 'zero character' expressions
            }
            return false; // fail: OSC address pattern too short
        }
        switch (*oscAddressPattern) {
            case '?':
            case '*':
            case '[':
            case '{':
                return MatchExpression(&oscAddressPattern, &oscAddress, isPartial);
            default:
                if (*oscAddressPattern != *oscAddress) {
                    return false; // fail: character mismatch
                }
                break;
        }
        oscAddressPattern++;
        oscAddress++;
    }
    if (*oscAddress != '\0') {
        return false; // fail: OSC address pattern too long
    }
    return true;
}

 

 

6) ProcessSensors : /sensors message 처리 부분

// NgimuReceive.cc

/**
 * @brief Process "/sensors" message.
 * @param oscTimeTag OSC time tag associated with message.
 * @param oscMessage Address of OSC message.
 * @return Error code (0 if successful).
 */
static OscError ProcessSensors(const OscTimeTag * const oscTimeTag, OscMessage * const oscMessage) {

    // Do nothing if no callback assigned
    if (sensorsCallback == NULL) {
        return OscErrorNone;
    }

    // Get timestamp
    NgimuSensors ngimuSensors;
    ngimuSensors.timestamp = *oscTimeTag;	// Messgae의 timestamp를 assign

    // Get gyroscope X axis
    OscError oscError;
    oscError = OscMessageGetArgumentAsFloat32(oscMessage, &ngimuSensors.gyroscopeX);
    if (oscError != OscErrorNone) {
        return oscError;
    }

    // Get gyroscope Y axis
    oscError = OscMessageGetArgumentAsFloat32(oscMessage, &ngimuSensors.gyroscopeY);
    if (oscError != OscErrorNone) {
        return oscError;
    }

    // Get gyroscope Z axis
    oscError = OscMessageGetArgumentAsFloat32(oscMessage, &ngimuSensors.gyroscopeZ);
    if (oscError != OscErrorNone) {
        return oscError;
    }

    // Get accelerometer X axis
    oscError = OscMessageGetArgumentAsFloat32(oscMessage, &ngimuSensors.accelerometerX);
    if (oscError != OscErrorNone) {
        return oscError;
    }

    // Get accelerometer Y axis
    oscError = OscMessageGetArgumentAsFloat32(oscMessage, &ngimuSensors.accelerometerY);
    if (oscError != OscErrorNone) {
        return oscError;
    }

    // Get accelerometer Z axis
    oscError = OscMessageGetArgumentAsFloat32(oscMessage, &ngimuSensors.accelerometerZ);
    if (oscError != OscErrorNone) {
        return oscError;
    }

    // Get magnetometer X axis
    oscError = OscMessageGetArgumentAsFloat32(oscMessage, &ngimuSensors.magnetometerX);
    if (oscError != OscErrorNone) {
        return oscError;
    }

    // Get magnetometer Y axis
    oscError = OscMessageGetArgumentAsFloat32(oscMessage, &ngimuSensors.magnetometerY);
    if (oscError != OscErrorNone) {
        return oscError;
    }

    // Get magnetometer Z axis
    oscError = OscMessageGetArgumentAsFloat32(oscMessage, &ngimuSensors.magnetometerZ);
    if (oscError != OscErrorNone) {
        return oscError;
    }

    // Get barometer
    oscError = OscMessageGetArgumentAsFloat32(oscMessage, &ngimuSensors.barometer);
    if (oscError != OscErrorNone) {
        return oscError;
    }

    // Callback
    sensorsCallback(ngimuSensors);
    return OscErrorNone;
}

 

 

 

 

 

 

 

 

 


참고 자료 :

https://github.com/ericlai0323/ros-ngimu

 

GitHub - ericlai0323/ros-ngimu: ROS package for NGIMU imu

ROS package for NGIMU imu . Contribute to ericlai0323/ros-ngimu development by creating an account on GitHub.

github.com

 

https://x-io.co.uk/ngimu/

 

NGIMU – x-io Technologies

 

x-io.co.uk

 

https://x-io.co.uk/downloads/NGIMU-User-Manual-v1.6.pdf

 

http://mwultong.blogspot.com/2006/08/qna-encoding-decoding.html

 

[QnA] 인코딩(Encoding) / 디코딩(Decoding) 의 의미는?

컴퓨터에서 인코딩(Encoding) 그리고 디코딩(Decoding)이란 말은 여러 가지 의미로서 사용됩니다. 그러나 어떤 경우든, 인코딩이란 "정보를 부호화/암호화시킨다"입니다. 디코딩이란 정반대로, 그 부

mwultong.blogspot.com

https://learn.newmedia.dog/courses/physical-computing/week-04/lesson-02/

 

Wireless: WiFi, Bluetooth

Wireless: WiFi, Bluetooth # WiFi # OSC (Open Sound Control) # OSC (Open Sound Control) is a protocol for communicating among applications and hardware over a network connection. It was originally developed for realtime musical performances. I like to think

learn.newmedia.dog

 

https://change-words.tistory.com/entry/127001-%EC%82%AC%EC%9A%A9%EC%9D%B4%EC%9C%A0

 

127.0.0.1 주소를 사용하는 이유

특수한 IP 주소인 127.0.0.1은 애플리케이션을 로컬 컴퓨터를 통해 테스트하기 위해 자주 사용됩니다. 자신이 가지고 있는 컴퓨터를 마치 제3자가 되어 원격으로 조작하는 방식으로 활용할 수 있습

change-words.tistory.com

 

https://wildeveloperetrain.tistory.com/182

 

루프백 ip란? (127.0.0.1 / localhost)

루프백(Loopback) ip란? 루프백 ip, 루프백 주소는 네트워크상에서 자신을 나타내는 가상적인 주소이며, 자신에게 다시 네트워크 입력이 들어온다고 하여 루프백(Loopback) 주소라고 합니다. IPv4에서의

wildeveloperetrain.tistory.com

 

https://roads22.wordpress.com/2012/02/26/open-sound-control-osc/

 

Open Sound control (osc)

-Open sound control- 사운드관련 퍼포먼스 및 연주정보 데이터 전송을 위해 미디이후에 개발된 플랫폼 (제스춰, 파라메터, 노트시퀀스등) -특징- 네트워크를 이용한 통신 규약이며 UDP를 사용한다. a)

roads22.wordpress.com

 

https://support.etcconnect.com/ETC/Consoles/Eos_Family/Software_and_Programming/TCP_port_for_OSC_communication_with_Eos_Software

 

TCP port for OSC communication with Eos Software

 

support.etcconnect.com

https://jtrimind.github.io/troubleshooting/filesystem/

 

[해결법] fatal error: filesystem: No such file or directory

C++의 <filesystem>은 C++17에 도입되었다. 따라서 C++17을 지원하지 않는 컴파일러의 경우 사용할 수 없다. 혹은 C++17을 사용하도록 하는 컴파일러 옵션이 빠졌을 수도 있다.

jtrimind.github.io

 

https://www.ibm.com/docs/ko/aix/7.1?topic=communications-serial-line-internet-protocol 

 

SLIP(Serial Line Internet Protocol)

SLIP(Serial Line Internet Protocol)는 TCP/IP가 직렬 연결을 통해 작동할 때 사용하는 프로토콜입니다. 이 프로토콜은 일반적으로 최저 1200bps에서 최고 19.2Kbps 이상의 속도로 작동하는 전화 접속 연결과 전

www.ibm.com

 

'Project > Jaguar 4X4 Human Tracking' 카테고리의 다른 글

[Jaguar 4x4 Human Tracking] 8/17 ~18  (0) 2023.08.18
[Jaguar 4x4 Human Tracking] 7/28  (0) 2023.07.28
[Jaguar 4x4 Human Tracking] 3/22  (0) 2023.03.22