chrono를 활용한 시간 측정

|

chrono 예제

#include 
#include 

using namespace std;
using namespace chrono;

const int MAX = 200000000;

long long a[MAX];

int main() {
  cout << "init ... " << endl;
  for (int i = 0; i < MAX; i++) {
    a[i] = i;
  }

  cout << "running... " << endl;

  system_clock::time_point start = system_clock::now();
  
  for (int i = 0; i < MAX; i++) {
    a[i] = a[i] * a[i];
  }
  system_clock::time_point end = system_clock::now();
  duration sec = end - start;

  cout << "Time: " << duration_cast<std::chrono::milliseconds>(sec).count() << endl;

  return 0;
}
</pre>

클래스와 구조체 차이

|

클래스와 구조체 차이

C++에서는 클래스(class)도 구조체(struct)도 모두 상속이 가능합니다. 또한 구조체를 상속한 클래스도 구현을 할 수 있고, 그 반대도 가능합니다.

클래스와 구조체의 차이를 굳이 찾으면 다음과 같습니다.

  • 클래스 멤버 변수는 기본적으로 private이지만, 구조체는 public 입니다.
  • template<class T>는 가능하지만, template<struct T>는 가능하지 않습니다. 다만, 키워드적으로 지원하지 않는 것이기 때문에 struct 대신 typename을 사용하면(ex. template<typename T>) 템플릿을 사용할 수 있습니다.

그 외에는 크게 차이가 없지만, 특정 목적에 따라 명시적으로 구분해서 사용하기도 합니다.

  • 생성자와 소멸자가 없는 데이터 타입(POD, Plain Old Data)에는 구조체를 사용
  • 메소드가 아닌 멤버 변수 위주로 사용할 때는 구조체 사용


POD

POD(Plain Old Data)는 C++11 부터는 표준 레이아웃(Standard layout) 또는 평범한 클래스(Trivial Class)라는 이름으로 대체되었습니다. 하지만 관행적으로 POD라는 용어가 쓰이고 있습니다.

POD는 C++98에서 정의된 용어로 C언어에서 사용되는 평범한 데이터 타입을 의미합니다.

Ros2 Custom Message And Service

|

layout: post title: ROS2 커스텀 Message 및 Service category: ROS2 tag: [ROS, Python] —

ROS2 커스텀 Message 및 Service

ROS2에서 사용자 정의 Message와 Service를 정의하는 방법입니다.


package.xml

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <name>tree_service</name>
  <version>0.4.0</version>
  <description>Message and Service of Tree-Service</description>
  <maintainer email="snowdeer0314@gmail.com">snowdeer</maintainer>
  <license>Apache License 2.0</license>

  <buildtool_depend>ament_cmake</buildtool_depend>
  
  <build_depend>builtin_interfaces</build_depend>
  <build_depend>rosidl_default_generators</build_depend>
  
  <exec_depend>builtin_interfaces</exec_depend>
  <exec_depend>rosidl_default_runtime</exec_depend>

  <member_of_group>rosidl_interface_packages</member_of_group>

  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>


CMakeLists.txt

cmake_minimum_required(VERSION 3.5)

project(tree_service)

if(NOT CMAKE_CXX_STANDARD)
  set(CMAKE_CXX_STANDARD 14)
endif()

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic")
endif()

find_package(ament_cmake REQUIRED)
find_package(builtin_interfaces REQUIRED)
find_package(rosidl_default_generators REQUIRED)

set(msg_files
    "msg/TreeEvent.msg"
    "msg/TreeData.msg"
    "msg/TreeNode.msg"
)

set(srv_files
    "srv/Tree.srv"
)

rosidl_generate_interfaces(${PROJECT_NAME}
  ${msg_files}
  ${srv_files}
  DEPENDENCIES builtin_interfaces
)

ament_package()


Message는 ‘msg’라는 서브 디렉토리 밑에, Service는 ‘srv’라는 서브 디렉토리 밑에 위치시킵니다. (위 CMakeLists.txt 파일 참고)

각각의 예제 파일들은 다음과 같습니다. 상단에 상수값을 정의하면 나중에 C++이나 Python에서 해당 메시지나 서비스를 사용할 때 해당 상수값을 이용할 수 있습니다. TOPIC_NAME이라던지 이벤트 ID 등을 상수로 정의하면 편리합니다.


msg/TreeNode.msg

string NAME = "TreeNode"

string id
string parent_id
string type
string name


srv/TreeData

string NAME = "TreeData"
int64 REQUEST_TO_PUBLISH_TREE_DATA = 1

int64 request_id
---
int64 request_id
int64 response

Python Simple Service Recevier

|

layout: post title: ROS2 Simple Service Receiver on Python category: ROS2 tag: [ROS, Python] —

ROS2 Simple Service Receiver on Python

간단한 ROS2 Service를 수신하고, 커스텀 메시지 배열을 Publish 하는 예제입니다.


from simple_service.srv import SimpleService
from simple_service.msg import Position
from simple_service.msg import RoutingData

import rclpy

global g_publisher


def add_position(positions, x, y, theta):
    pos = Position()
    pos.x = x;
    pos.y = y;
    pos.theta = theta
    positions.append(pos)


def callback(request, response):
    request_id = request.request_id
    print("Simple Service Request: {0} ".format(request_id))

    if request_id == Navigation.Request.REQUEST_DEMO_MOVE_PATH_1:
        msg = RoutingData()
        msg.command = RoutingData.COMMAND_MOVE_ALONG_PATH

        add_position(msg.positions, 100, 100, 10)
        add_position(msg.positions, 500, 200, 10)
        add_position(msg.positions, 1000, 1000, 1)

        g_publisher.publish(msg)

    elif request_id == Navigation.Request.REQUEST_DEMO_MOVE_PATH_2:
        msg = RoutingData()
        msg.command = RoutingData.COMMAND_MOVE_ALONG_PATH

        add_position(msg.positions, -100, -100, 10)
        add_position(msg.positions, -500, -200, 10)
        add_position(msg.positions, -1000, -1000, 1)

        g_publisher.publish(msg)

    response.response = 200

    return response


def main(args=None):
    global g_publisher

    rclpy.init(args=args)

    node = rclpy.create_node('simple_service_receiver')
    g_publisher = node.create_publisher(RoutingData, RoutingData.NAME)

    srv = node.create_service(SimpleService, SimpleService.Request.NAME, callback)

    rclpy.spin(node)
    rclpy.shutdown()


if __name__ == '__main__':
    main()

ROS2 Simple Keyboard Publisher on Python

|

ROS2 Simple Keyboard Publisher on Python


package.xml

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
  <name>simple_publisher</name>
  <version>0.4.0</version>
  <description>Simple Publisher on Python</description>
  <maintainer email="snowdeer0314@gmail.com">snowdeer</maintainer>
  <license>Apache License 2.0</license>

  <exec_depend>rclpy</exec_depend>
  <exec_depend>std_msgs</exec_depend>
  <exec_depend>simple_message</exec_depend>

  <export>
    <build_type>ament_python</build_type>
  </export>
</package>


setup.cfg

[develop]
script-dir=$base/bin/simple_publisher
[install]
install-scripts=$base/bin/simple_publisher


setup.py

from setuptools import setup

package_name = 'simple_publisher'

setup(
    name=package_name,
    version='0.4.0',
    packages=[],
    py_modules=[
        'simple_publisher'],
    install_requires=['setuptools'],
    author='snowdeer ',
    author_email='snowdeer0314@gmail.com',
    maintainer='snowdeer',
    maintainer_email='snowdeer0314@gmail.com',
    keywords=['ROS'],
    description='Simple Publisher on Python',
    license='Apache License, Version 2.0',
    tests_require=['pytest'],
    entry_points={
        'console_scripts': [
            'simple_publisher = simple_publisher:main'
        ],
    },
)


simple_publisher.py

import threading
import rclpy
import os

from simple_message.msg import SimpleMessage

NODE_NAME = "simple_publisher"


def handle_keyboard(publisher):
    while True:
        print('\n- Simple Publisher Menu -')
        print('   1. Command (Move along path 1)')
        print('   2. Command (Move along path 2)')
        print('   99. Exit')

        menu = input('Input the menu: ')

        if menu == '1':
            msg = SimpleMessage()
            msg.command_id = SimpleMessage.COMMAND_FOR_DEMO_1
            publisher.publish(msg)
            print(" \n>>> command is published : {0}".format(msg.command_id))

        elif menu == '2':
            msg = SimpleMessage()
            msg.command_id = SimpleMessage.COMMAND_FOR_DEMO_2
            publisher.publish(msg)
            print(" \n>>> command is published : {0}".format(msg.command_id))

        elif menu == '99':
            rclpy.shutdown()
            os._exit(1)


def main(args=None):
    rclpy.init(args=args)

    node = rclpy.create_node(NODE_NAME)
    publisher = node.create_publisher(SimpleMessage, SimpleMessage.NAME)

    th = threading.Thread(target=handle_keyboard, args=(publisher,))
    th.start()

    try:
        rclpy.spin(node)
    finally:
        node.destroy_node()
        rclpy.shutdown()


if __name__ == '__main__':
    main()