3. Hanwhabot 만들기

최준혁·2022년 1월 18일
0

2021_project

목록 보기
5/5

한화봇은 다음과 같이 구성되어 있다.

sensor - Intel realsense d435i, YDlidar X4, mpu6050
actuator - MD750T
MCU - arduino mega
board - Jetson nano
main github link


1. MD750T Control

먼저 로봇 구동부를 살펴보자.
터틀봇은 OpenCR을 통해 로봇을 구동하고 있다. 그렇다면 OpenCR 내부에서는 어떤 코드가 작동하고 있을까?
https://github.com/ROBOTIS-GIT/OpenCR/tree/master/arduino/opencr_arduino/opencr/libraries/turtlebot3/examples/turtlebot3_burger/turtlebot3_core
참고해서 보면 되겠지만, 정확히 모터랑 serial 통신을 하는 모습은 보이지 않는다. 하지만 모터 값을 다루는 코드는 확인할 수 있는데, 특별히 odometry를 계산하는 방법이 다른것도 아니다. 그렇다면 나 또한 MD750T를 다룰 때, 동일한 방식으로 하면 되겠다라는 생각했다.

1-0. MD750T ROS src, manual 다운로드 링크

http://www.mdrobot.co.kr/tech-support/?q=YToyOntzOjEyOiJrZXl3b3JkX3R5cGUiO3M6MzoiYWxsIjtzOjc6ImtleXdvcmQiO3M6MzoiUk9TIjt9&bmode=view&idx=6051407&t=board
버전이 계속해서 바뀌는 것 같은데, 실험을 통해서 현재 작성자와 같은 버전인지 확인할 필요 있다. 확인 내용은 odometry값이다.

1-1. MD750T 통신

먼저 MD750T와의 통신이다. 정말 많은 통신을 고려했지만, RS232 통신이 가장 간단하여 그 통신을 채택하였다. RS232 통신을 할때는 md에서 수정해줘야 할 것이 몇가지 없다. 먼저 launchfile의 baudrate를 9600으로 해주고 com.cpp 파일의 38번째 줄을 다음과 같이 수정해주었다.

serial::Timeout to = serial::Timeout::simpleTimeout(1000);

이후에 RS232 통신 성공했다.

1-2. MD750T odometry

하지만 MD750T의 코드는 문제가 없지만, 막상 확인을 해보면 전혀 다른 odom 값을 돌려주고 있다.
정면으로 가면 ROS 좌표계상 x좌표 값이 증가해야하는데, y값이 증가를 한다거나, theta는 deg값을 돌려주는 일이 발생했다. 사실 좌표축이 바뀌면서 값 자체에 대한 신뢰도가 떨어졌지만, 전화상담을 통해 얘기해보니, 절대값에는 문제가 없는 것으로 나온것 같다. 그렇다면 나는 어떻게 문제를 해결했나? 다음과 같이 cmd_main.cpp에서 odom.pose, odom.twist를 결정해주었다.

typedef struct RightOdom{
  double posx, posy, posth;
  double velx, angz;
} rightOdom;
rightOdom r_odom;

void monitorCallBack(const md::monitor_msg::ConstPtr& monitor)
{
  ~
  MD.lPosiX = monitor->lPosiX;
  MD.lPosiY = monitor->lPosiY;
  // my custom, x, y 바뀜. 180도 회전 정도로 생각하자.
  r_odom.posx = (double)-monitor->lPosiY/1000; // mm -> m
  r_odom.posy = (double)-monitor->lPosiX/1000; // mm -> m
  r_odom.posth = monitor->sTheta ? (double)(360-(float)(monitor->sTheta/10))*3.141592/180.0 : 0;
  r_odom.velx = (double)-monitor->sRealLinearVel/1000; // mm/s -> m/s
  r_odom.abgz = (double)(-monitor->sReanAngularVel/10.0*3.141592/180.0); // 10deg/sec -> rad/sec
  //  
}

ros의 angular 은 +x축을 0으로 잡고 왼쪽 으로 가며 -x에 도달했을 때 180, 반대 방향으로 출발했을 때는 -180이다. 하지만 +z로 회전하여 x축에 도달하여도, 360으로 취급하여도 상관이 없다. 하지만 만일 본인이 생각하기엔 다른 방식의 각도를 생각하고 싶다면 위 방식 말고 다음과 같이 선택하여도 상관없는 듯 하다. 실험결과 동일하였다.

r_odom.posth = MD.fTheta-90 ; // 이후에 각도 바꾸기.

이후에는 동일하게 odom을 publish 해주면 되겠다. 관련 코드 링크는 아래에 내 깃헙에 올려두었다.
이외에 수정해야할 파라미터는 launch 파일에 다 있다. Manual과 함께 읽어보면 알겠지만, PC, MDUI, MDT, RMID값은 꼭 확인하길 바란다. 왜냐면 중간에 다른 하드웨어를 사용한다면 방금 값들이 바뀌기 때문이다. 그 다음 본인 모터에 해당하는 값들을 바꿔주도록 하자.


2. YDLidar X4

YDLidar는 저가 2d 라이다로 학생들이 구매하기 좋은 제품이라 생각한다. 사용법 또한 간단하나 아쉬운점은 생각보다 센서값이 꽉차지 못했다는 것. +x 정면값이 laser[360]이다. 사용법은 아래에 간단히 적어놓겠다.

2-1. YDLidar X4 ros 설치

1) Clone this project to your catkin's workspace src folder
	(1). git clone https://github.com/YDLIDAR/ydlidar_ros
	(2). git chectout master
2) Running catkin_make to build ydlidar_node and ydlidar_client
3) Create the name "/dev/ydlidar" for YDLIDAR
--$ roscd ydlidar_ros/startup
--$ sudo chmod 777 ./*
--$ sudo sh initenv.sh

위 같은 방식을 통해 설치가 되었다면(udev rule 또한 설치됨), launch 폴더에 가서 본인에게 맞는 lidar를 실행해보자. 정말 다양한 라이다가 존재한다.


3. Intel Realsense d435i

Intel RealSense 설치는 정말 힘들지만 JetsonHack라는 분이 정말 쉽게 만들어놓으신 것들이 많다. 나 또한 OpenCV나 ROS설치는 여기서 작성한 스크립트를 사용한다.

3-1. Intel Realsense d435i install

여기서 중요한 것은 버전이다. 너무 낮은 버전을 사용하면 그건 그거나름대로 실행이 안된다. 너무 높은 버전 또한 ROS와 호환이 안될 수 있다. 적당한 버전을 찾아서 설치해야하는데, 어떻게 할까? 먼저 다음의 링크에서 확인을 하자.

위 링크에서 버전을 확인하는데, 너무 높은 버전은 피하자. 2022-01-18일 최신 버전은 2.50.v인데, 내가 설치할때 당시만 해도 2.48이 최신버전이였다. 하지만 내가 생각하기에 안전한 버전은 2.45.0v라 생각하고 그것에 맞는 ros 버전을 찾아준다. 찾아보니 2.3.0 버전이다.
필요한 버전을 파악했으니, 이제 jetsonhacks의 버전을 바꿔주자.
확인하면 두가지 실행파일이 존재하는데, installLibrealsense.sh를 하면 가장 최신버전이 설치되니 build로 가자.

$ ./buildLibrealsense.sh [ -v | --version <version> ] [ -j | -jobs <number of jobs> ] [ -n | --no_cuda ]

위와 같은 방식으로 진행된다는데, 우리는 cuda도 존재하고 하니 버전만 잘 설정해주면 된다.

$ ./buildLibrealsense.sh -v v2.45.0

설치가 다 되었다면, 다음은 ros wrapper설치이다. 설치 스크립트 중 13번째 줄을 본인의 버전에 맞게 바꿔주면 되겠다.

REALSENSE_ROS_VERSION=2.2.11 # -> 2.3.0

4. mpu6050 ros

중간에 계단을 오르는 미션이 있어서 탱크가 계단을 다 올랐는지 아닌지에 대한 판단을 하기위해 imu 센서를 사용하기로 했다.

4-1. mpu6050 ros install

mpu6050 ros의 경우 다음과 같은 링크를 참고하였다.


위 링크의 Set Up the Communication Protocol 까지만 실행 한 뒤 바로 아래에 내려가서 아래의 깃헙을 사용하는 링크로 가자. 그 후 실행되는지 확인한 후 설치를 마치면 되겠다.
https://github.com/bandasaikrishna/orientations_from_IMU_MPU_6050.git


5. ROS1 Navigation Setting

ROS1의 navigation은 참고자료가 정말 많다.

ROS1 navigation stack은 다음과 같다.
여기서 만약 본인 만의 path planning을 만드는 것이 아니라, 말 그대로 자신의 로봇에 ROS navigation을 사용하는 방법에 대해 알고 싶다면 다음과 같은 calibration을 해줘야 한다.

  • odometry calibration
  • amcl calibration
  • dwa path planner calibration

위의 calibration을 하기 전에 일단 로봇의 차체가 완성되었다는 전제하에 움직여야 한다. 그렇다는 것은 로봇의 tf가 다 나와있어야 한다는 것인데, 이는 어떻게 해결할 수 있는가? tf에 대한 이해는 http://wiki.ros.org/tf 이 링크에서 하고, 나는 실질적으로 어떻게 tf broadcasting을 쉽게 하는지만 얘기하고 싶다. 링크에서의 tutorial은 tf를 굉장히 불편하게 broadcasting하고 있다. 물론 tf 변환이 필요하다면 그 의미가 다르겠지만, 만일 본인이 navigation에 필요한 tf 변환만 필요하다면, 다음과 같이 간단하게 사용하자.

  1. urdf 파일 작성
  2. launch 파일 작성

본인이 만일 urdf를 작성할 줄 모른다면 다음의 링크를 확인해서 작성하자. http://wiki.ros.org/urdf 여기서 재밌는 점은, turtlebot이나 다른 판매하는 로봇들은 제대로된 urdf를 작성했지만, 나는 그렇게 하진 못했다. 캐터필러의 정확한 stl 파일 확보를 못했을 뿐더러, 이 과정자체도 정말 어려운 것이기에 편법을 사용했다. 정말로 navigation stack에서 요구하는 urdf만 작성을 한 것이다. 그 다음 launch file에서 urdf parser를 사용해서 urdf를 tf broadcasting 해주는 것을 사용하면 되겠다. 관련 파일은 깃헙 링크, hanwhabot_description 폴더에서 찾아볼 수 있다.
위에서 odom_combined를 odom으로만 바꾸어서 tf tree를 만들면 되겠다. 참고로 odom부분은 위의 md에서 만들어줘야 한다. urdf는 로봇에 대한 것만(정적인 것만) 작성하는 것처럼 보인다.

tf가 세팅되었다면 다음은 calibration이다. 그 중 첫번째로 해야되는 것은 odometry calibration이다. 그게 어떤 의미일까?

5-1. odometry calibration

보통 두가지로 나뉜다. 한가지는 x축 이동에 대한 calibration. 다른 한가지는 theta에 대한 calibration이다. 전자에 대해 설명하자면, 로봇이 정면으로 움직였을 때, 로봇에게 1m를 움직이라 하였을 때, 실제 1m를 움직였는가? 실제로는 0.9m정도 움직였을 것이다. 어차피 추후에 filter를 거칠것이긴 하지만, 어느정도 정확해야지 filter값이 작아질 것이고, 작은 값일 수록 navigation을 돌리는데 정확해진다. 어떤 filter값인지는 아래에서 설명할 것이다.

5-1-1. x calibration

간단하다. 실제 움직인 거리를 확인하면 되겠다. 만일 그 값이 어느정도 정확하다 싶으면 그 다음은 lidar calibration을 하면 되겠다. lidar calibration이란, 전방의 벽에 라이다를 키면서 앞으로 나아가면, lidar frame 기준으로는 laser pcl이 frame으로 가깝게 올 것이다. 그것이 실제로 되는지 rviz 상에서 확인하면 되겠다.

5-1-2. angular calibration

제자리 회전을 한 후 나오는 odometry 값과 실제 회전각을 비교하면 되겠다. 나같은 경우에는 이부분에서 굉장히 애를 먹었는데, 캐터필러를 사용하다 보니 kinematics가 정확히 나오지 않아 2wheel 모델을 그대로 사용했다. 그 부분 때문에 md.launch 파일의 wheelLength 값을 계속해서 바꾸었다. 실제로 확인했을 때 360 회전을 했는데, 계산상으로는 320도 혹은 380도 이런식을 나오는 것을 수정하라는 것이다. 더 정확히 하고 싶다면 실제로 n바퀴 + a를 회전하고 그것의 계산 값을 비교하면서 calibration을 하라는 것이다. 이는 정형화된 방법은 없을 것이다. 각자에게 맞는 방식으로 calibration을 하면 되겠다.

5-2. amcl calibration

amcl이란 laser기반으로 현재 pose를 추정하는 패키지이다. 이중에는 위에서 odometry calibration은 하였지만, 그래도 완벽하게 동일하진 않을 것이다. 일단 launch 파일과 링크를 통해 각각의 parameter가 어떤 것을 의미하는 지 알아보자.
http://wiki.ros.org/amcl

<launch>
  <!-- Arguments -->
  <arg name="scan_topic"     default="scan"/>
  <arg name="initial_pose_x" default="0.0"/>
  <arg name="initial_pose_y" default="0.0"/>
  <arg name="initial_pose_a" default="0.0"/>

  <!-- AMCL -->
  <node pkg="amcl" type="amcl" name="amcl">

    <param name="min_particles"             value="500"/>
    <param name="max_particles"             value="3000"/>
    <param name="kld_err"                   value="0.02"/>
    <param name="update_min_d"              value="0.20"/>
    <param name="update_min_a"              value="0.20"/>
    <param name="resample_interval"         value="1"/>
    <param name="transform_tolerance"       value="0.5"/>
    <param name="recovery_alpha_slow"       value="0.00"/>
    <param name="recovery_alpha_fast"       value="0.00"/>
    <param name="initial_pose_x"            value="$(arg initial_pose_x)"/>
    <param name="initial_pose_y"            value="$(arg initial_pose_y)"/>
    <param name="initial_pose_a"            value="$(arg initial_pose_a)"/>
    <param name="gui_publish_rate"          value="50.0"/>

    <remap from="scan"                      to="$(arg scan_topic)"/>
    <param name="laser_max_range"           value="3.5"/>
    <param name="laser_max_beams"           value="180"/>
    <param name="laser_z_hit"               value="0.5"/>
    <param name="laser_z_short"             value="0.05"/>
    <param name="laser_z_max"               value="0.05"/>
    <param name="laser_z_rand"              value="0.5"/>
    <param name="laser_sigma_hit"           value="0.2"/>
    <param name="laser_lambda_short"        value="0.1"/>
    <param name="laser_likelihood_max_dist" value="2.0"/>
    <param name="laser_model_type"          value="likelihood_field"/>

    <param name="odom_model_type"           value="diff"/>
    <param name="odom_alpha1"               value="0.1"/>
    <param name="odom_alpha2"               value="0.1"/>
    <param name="odom_alpha3"               value="0.1"/>
    <param name="odom_alpha4"               value="0.1"/>
    <param name="odom_frame_id"             value="odom"/>
    <param name="base_frame_id"             value="base_footprint"/>

  </node>
</launch>

5-2-1. amcl odom parameter calibration

여기서 odometry에 관한 filter 설정 파라미터를 알아보자. odom_alpha1~4까지 있는데, 이 값들이 필터값이다. 각각에 대해 이해해보자.

  • odom_alpha1: 로봇의 회전으로 인한 rotation odometry noise 필터
  • odom_alpha2: 로봇의 translation으로 인한 rotation odometry noise 필터
  • odom_alpha3: 로봇의 회전으로 인한 translation odometry noise 필터
  • odom_alpha4: 로봇의 translation 인한 translation odometry noise 필터

우리팀의 로봇은 특히 회전값이 안맞았으므로 odom alpha1, 2값을 크게 주었다(0.4, 0.4). 하지만 마냥 크게 주면 그거때문에 또 값을 제대로 인식하지 못한다. 적절한 값을 선정하는 실험을 거치도록 하자.

5-2-2. amcl laser parameter calibration

그 다음은 laser에 대한 calibration이다. 먼저 라이다 부착 위치와 주변 프레임으로 인해 lidar의 범위가 상당히 좁아졌다. 이는 내 개인 github에서 확인할 수 있다.
lidar launch file 넣기

좁아진 범위를 생각한다면 laser max beams 파라미터를 바꿔야 함을 알 수 있다.

  • laser_max_beams: How many evenly-spaced beams in each scan to be used when updating the filter

즉 필터 업데이트시 사용할 수 있는 beams의 개수인데, 현재 값이 180으로 매우 높은 수준이다. 그러므로 X4.launch 파일에서 설정한 각도의 절반 값을 주자.

5-3. DWA Path planner calibration

  • http://wiki.ros.org/navigation/Tutorials/RobotSetup
    movebase.launch 파일을 통해 어떤 파일을 수정해줘야 하는지 확인해보자.
    모든 파라미터에 대해 알아 보진 않을 것이다. 먼저 move_base.launch 파일을 보면

  • costmap_common_params.yaml

  • global_costmap_params.yaml

  • local_costmap_params.yaml

  • dwa_local_planner_params.yaml

각 폴더의 내용을 보자.

5-3-1. costmap_common_params.yaml

수정해줘야 하는 값들은 다음과 같다.
footprint, inflation radius, cost_scaling_factor

obstacle_range: 2.5
raytrace_range: 3.0
footprint: [[x0, y0], [x1, y1], ... [xn, yn]]
#robot_radius: ir_of_robot
inflation_radius: 0.55

observation_sources: laser_scan_sensor point_cloud_sensor

laser_scan_sensor: {sensor_frame: frame_name, data_type: LaserScan, topic: topic_name, marking: true, clearing: true}

point_cloud_sensor: {sensor_frame: frame_name, data_type: PointCloud, topic: topic_name, marking: true, clearing: true}
  • obstacle_range

    The "obstacle_range" parameter determines the maximum range sensor reading that will result in an obstacle being put into the costmap

2.5가 의미하는건 2.5m 내부의 값들만 장애물로 costmap에 넣을 것이라는 뜻이다.

  • raytrace_range

    The "raytrace_range" parameter determines the range to which we will raytrace freespace given a sensor reading.

3.0이 의미하는 것은 3.0m 이상의 값은 어떤 식으로든 고려하지 않을 것이라는 뜻이다. 위 두가지 값을 본인의 lidar 수준에 맞게 설정하면 되겠다.

  • footprint
    차체의 xy평면상에서의 사이즈를 의미한다. 로봇이 지나가면서 로봇의 크기만큼 공간을 차지하는데, 이를 두고 footprint라고 한다. 무게중심을 0,0으로 생각하고 나머지 점들을 채워주면 되겠다. 보통은 사각형으로 설정하고 원한다면 robot_radius라고 하며 원형으로 설정하여도 되겠다.

  • inflation radius
    inflation radius는 navigation 중, lidar가 벽을 scanning 할 것이다. 로봇이 벽에 얼마나 붙어서 갈것인지 정하고 싶다면 수정해줘야하는 값이다. 0.55의 의미는 로봇이 obstacle로 부터 0.55m 떨어진 상태에서 path를 계획할 것이라는 뜻이다. 나는 좁은 곳에서 로봇을 움직여야 해서 값을 정말 많이 줄였다.

  • cost scaling factor
    다음의 함수에 적용되는 요소이다. 음수와 곱해짐으로, 값이 커질 수록 cost value가 작아진다. 값을 작게 한다면 cost value가 커진다는 뜻. cost가 높아진다면 그쪽길로 가는 것을 피할 것이다.

exp(-1.0 * cost_scaling_factor * (distance_from_obstacle - inscribed_radius)) * (costmap_2d::INSCRIBED_INFLATED_OBSTACLE - 1),

그림으로 본다면 다음과 같은 그림이 존재한다.
빨간색pcl이 lidar sensor값, 파란색이 inflation radius에 의한 그림이다. 빨간 box가 footprint이다.

만약 좁은곳에서 navigation을 실행하는데, inflation radius값을 크게 준다면 로봇은 움직이지 못할 것이다. 그러니 위의 파라미터들을 정말 세심하게 수정해주자.

5-3-2. global_costmap_params.yaml

global costmap의 configuration을 위한 파일이다.

global_costmap:
  global_frame: /map
  robot_base_frame: base_footprint
  update_frequency: 5.0
  publish_frequency: 5.0
  static_map: true
  transform_tolerance: 0.5

global_frame과 robot_base_frame은 costmap이 고려할 frame을 정의하는 부분이다. 그 다음 costmap의 update loop을 5.0 HZ로 설정한 모습이다. 이부분은 10.0으로 바꾸어서 작성했다. 동일하게 costmap을 publish하는 HZ이다. update와 publish는 다르다. static_map부분이 중요한데, map server로 부터 받은 맵을 초기화할 필요가 있는지 없는지 판단하는 것이다.

5-3-3. local_costmap_params.yaml

local_costmap:
  global_frame: odom
  robot_base_frame: base_footprint
  update_frequency: 10.0
  publish_frequency: 10.0
  static_map: false
  rolling_window: true
  width: 6.0
  height: 6.0
  resolution: 0.05

이번에는 local costmap인데, update, publish는 최대한 동일한 값을 사용해주도록 하자. rolling_window는 다음과 같은 설명이 붙는다.

Setting the "rolling_window" parameter to true means that the costmap will remain centered around the robot as the robot moves through the world

간단히 해석 가능하다.

5-3-4. dwa_local_costmap_params.yaml

DWAPlannerROS:

# Robot Configuration Parameters
  max_vel_x: 0.22
  min_vel_x: -0.22

  max_vel_y: 0.0
  min_vel_y: 0.0

# The velocity when robot is moving in a straight line
  max_vel_trans:  0.22
  min_vel_trans:  0.11

  max_vel_theta: 2.75
  min_vel_theta: 1.37

  acc_lim_x: 2.5
  acc_lim_y: 0.0
  acc_lim_theta: 3.2 

# Goal Tolerance Parameters
  xy_goal_tolerance: 0.05
  yaw_goal_tolerance: 0.17
  latch_xy_goal_tolerance: false

# Forward Simulation Parameters
  sim_time: 1.5
  vx_samples: 20
  vy_samples: 0
  vth_samples: 40
  controller_frequency: 10.0

# Trajectory Scoring Parameters
  path_distance_bias: 32.0
  goal_distance_bias: 20.0
  occdist_scale: 0.02
  forward_point_distance: 0.325
  stop_time_buffer: 0.2
  scaling_speed: 0.25
  max_scaling_factor: 0.2

# Oscillation Prevention Parameters
  oscillation_reset_dist: 0.05

# Debugging
  publish_traj_pc : true
  publish_cost_grid_pc: true

DWA Path planning 알고리즘 configuration 파일이다. navigation 중 로봇의 속도/가속도를 파라미터로 줄 수 있다. 본인이 원하는 값으로 세팅해주면 되겠다.

중요한 파라미터라 생각하는 것은 ~ tolerance라고 생각한다. 우리는 로봇이 완벽히 정확하다고 생각하지 않는다. 그렇기에 로봇이 목표지점에 가까이 가도, 완벽하게 goal안에 들어갈 수 없다. 하지만 tolerance parameter를 통해 그 정도를 정할 수 있다. 값을 키울 수록 더 완벽하게 goal안에 들어가야 한다. 본인이 원하는 값을 세팅해주도록 하자.

5-4. chrony time synchronize

ROS1 Navigation을 사용하다 보면 시간 동기 에러가 나올때가 많다.

[ WARN] [1638649873.141034902]: Clearing both costmaps outside a square (3.00m) large centered on the robot.
[ WARN] [1638649878.240998667]: Rotate recovery behavior started.
[ERROR] [1638649879.541438854]: Rotate recovery can't rotate in place because there is a potential collision. Cost: -1.00
[ WARN] [1638649884.642048298]: Clearing both costmaps outside a square (1.84m) large centered on the robot.
[ WARN] [1638649889.742037155]: Rotate recovery behavior started.
[ERROR] [1638649889.742448519]: Rotate recovery can't rotate in place because there is a potential collision. Cost: -1.00
[ERROR] [1638649894.842041682]: Aborting because a valid plan could not be found. Even after executing all recovery behaviors

특히 host pc와 master pc가 나뉜 상태에서 하려면 그렇다. 전의 한컴 아카데미에서는 다른 팀원들은 시간 동기화를 위해서 wifi 공유기를 장착한 걸로 기억한다(ntp방식). 그 후 인터넷 접속하여 시간을 동기화 하였다. 하지만 그 방법이 실제 자율주행을 해야하는 로봇이 시간 동기화를 위해 인터넷 접속을 한다는 것이 이해가 안되었다. 그래서 찾은 방법이 chrony를 이용한 시간동기화 방식이다.

5-4-1. jetson nano hotspot mode

먼저 젯슨 나노를 wifi hot spot모드로 만들어주자. 그렇게 한다면 ip주소가 10.42.0.1로 될 것이다. 물론 이같은 방법이 맘에 안든다면 본인이 원하는 방식으로 하면 된다. 특히 보안같은 것을 중요하게 여긴다면 다른 방식을 선택하자.

5-4-2. install chrony in jetson nano(Master PC)

sudo apt install chrony
sudo vim /etc/chrony/chrony.conf

설정파일 바꾸기

pool <기준PC IP주소> iburst maxsources 1 # <기준PC IP주소> = 10.42.0.1

keyfile /etc/chrony/chrony.keys
driftfile /var/lib/chrony/chrony.drift

local stratum 10
allow 192.168.0.0/16

logdir /var/log/chrony
maxupdateskew 100.0
rtcsync
makestep 1 3

실행

sudo systemctl restart chronyd.service
sudo systemctl restart chrony.service
watch chronyc tracking # 실행대기

5-4-3. install chrony in labtop(Host PC)

chrony 설치 동일

설정파일 바꾸기.

$ sudo vi /etc/chrony/chrony.conf

pool <기준PC IP주소> iburst maxsources 1 # 10.42.0.1

keyfile /etc/chrony/chrony.keys
driftfile /var/lib/chrony/chrony.drift

logdir /var/log/chrony
maxupdateskew 100.0
rtcsync
makestep 1 3
sudo systemctl restart chrony.service

chrony 동작 확인

watch chronyc tracking

6. gmapping

  • http://wiki.ros.org/slam_gmapping/Tutorials/MappingFromLoggedData
    map을 만들기 위해선 다양한 방법이 있다. lidar를 사용하는 slam에서는 cartographer, gmapping 등등이 있고, camera를 이용하는 방법 또한 다양하다. 하지만 대회에 나간다는 생각이면 가장 간단한 방법을 사용하여 많은 테스트를 하는 것이 좋다고 생각한다.

6-1. setting

위에서 calibration을 했다면 필요한 세팅은 다 끝났다 생각한다. 그보다는 설치가 더 중요할 듯 하다.

6-2. 설치 및 사용법

sudo apt-get install ros-melodic-gmapping
rosmake gmapping
# 본인만의 launch file을 만들자. 관련 자료는 github에 있다.
roslaunch hanwhabot_slam hanwhabot_slam.launch
# map이 어느정도 완성이 되었다고 생각되면 아래의 명령어로 map을 저장한다.
rosrun map_server map_saver -f <map_name>

이렇게 설치한 map을 navigation에서 사용하면 되겠다.


7. Navigation start

roslaunch hanwhabot_bringup hanwhabot_robot.launch
roslaunch hanwhabot_navigation hanwhabot_navigation_map.launch

이후 rviz 상에서 원하는 곳에 점을 찍으며 이동시키는 것을 확인하면 되겠다. rviz 세팅은 본인이 따로 해주도록 하자.

내가 추가적으로 목적지를 설정해 준 파일이 있다. mission5를 위한 것이며, 이는 거기서 직접 맵을 만든 후 initial point와 first goal, second goal을 한 스크립트 안에서 실행하기 위해 넣어준 파이썬 파일이다. hanwhabot_send_goal에서 확인할 수 있다.

rosrun hanwhabot_send_goal map5.py

핵심은 본인이 만든 맵에서 rviz 상으로 목적지의 좌표를 확인하는 것이다. 이를 알아낼 수 없다면 목표지점 자체를 모르는 것이니 이걸 할 이유가 없는 것!


8. Line Detection

line detection은 정말 많은 레퍼런스를 봤지만, 가장 중요한 것은 안의 내부 코드보다 카메라의 pose라고 생각한다. 우리는 이부분에 대해서 실험할 시간이 부족했고, 그로인해 내부 코드와 별개로 실패했다고 생각한다. 먼저 본인 차량의 속도와 주변 line의 길이를 고려해보자. 그리고 camera의 FoV를 고려한다면 camera의 높이가 몇이 나와야 하는지도 생각하면 얼추 그림이 나올 것이다. 나같은 경우에는 속도는 엄청 느린데, 카메라 시야에는 80cm 전방의 line만 보이고 높이 또한 낮아서 line이 제대로 보이지 않았다. 높이 약 30cm에 그런일이 있었다고 생각하면 꽤나 가슴아픈 일이다. 하지만 여기에는 코드만 설명하는 곳이므로 코드만 설명해보자.
참고자료이다.

다른 레퍼런스들도 많았지만, 대부분 위 두가지에서 같은 뿌리를 갖고 있었다. 후자부터 분석하면 허프라인디텍션을 이용하여 라인을 추출하고 있다. 전자는 이미지를 색으로 분류하여 라인을 추출하고, 두 라인에 대해 x = ay^2 + by + c 식을 만들어 a, b, c를 구하여 평균 라인을 구한다. 그 후 평균 라인의 한 픽셀과 이미지 중앙선 차이로 pid 계산을 하여 속도를 조절한다.

8-1. Feedback

위 방식의 안타까운 점 두가지가 있다. 첫번째는 굵은 선 부분이다. 굳이 따지자면, 2차식을 구할 필요가 없이 그냥 두 픽셀의 평균 값만 구해도 되는 부분이였다. 두번째로 안타까운 것은 정지선의 색 유무이다. turtlebot autorace를 살펴보니 정지선의 색이 빨강색으로 기억한다. 하지만 한화디펜스 대회는 정지선이 흰색이다. 이렇다보니 왼쪽과 오른쪽을 구분할 수 없게 된다. 그렇다고 후자의 코드 또한 단점은 있다. 필요한 라인만 선택하는 것이 아닌 좌우 그리고 정지선을 모두 추출한다는 것이다. 각각의 선에 의미를 부여하는 일 또한 필요하다는 것이다. 물론 이는 조금만 수정한다면 쉬울 듯 하다. 세번째로 안타까운 것은 계산량이다. 이것은 첫번째 부분과 어느정도 연관이 되는데, 2차식을 구하는 방식이 전체 히스토그램을 이용하는 것이 조금 안타까웠다. 개인적인 피드백으로는 RANSAC을 이용하여 피드백을 구하는 것은 어땠을까? 물론 계산량은 줄이겠지만 파라미터 세팅하는데에도 시간이 걸렸을 것이다.


Project Feed Back

전체적으로 아쉬운 프로젝트였다. 12월 중순 대회인데 10월 중순부터 차체를 만든거 치곤 잘했다곤 생각하나, 실제 코드를 테스트해보고 파라미터를 수정하는데 성공한건 미션 5번 뿐이라는 것이 안타까웠다.

전체 미션에 대한 피드백을 준다면 다음과 같다.

  • mission1: 카메라의 높이 조절을 통한 좀 더 수월한 line detection, 혹은 fov가 더 넓은 fisheye camera를 사용해볼것, RANSAC을 사용해서 계산량을 줄여볼 것.
  • mission2: 캐터필러의 탈선이 문제였다. 만일 탈선이 안되었다면 좀 더 수월 했을것.
  • mission3: 시뮬레이션을 통해 디자인을 수정했다면 만드는 시간이 좀 더 짧았을 것. 시뮬레이션을 통한 피드백이 아니라 실제 만들면서 피드백을 주다보니 시간이 배로 걸렸다.
  • mission4: 로봇 팔을 다룰줄 몰랐다는 점. 매니퓰레이터를 다룰줄 아는 팀원을 구해서 도전?!
  • mission5: 캐터필러의 탈선으로 인해 rotation calibration을 계속 해줘야 한다는 점이 아쉬웠다. 더 간단한 kinematics를 가진 로봇을 만든다면 이러한 걱정 없을 듯 하다.

결론 - 시뮬레이션과 매니퓰레이터를 할줄 아는 친구가 필요하다~!

profile
3D Vision, VSLAM, Robotics, Deep_Learning

1개의 댓글

comment-user-thumbnail
2022년 3월 17일

안녕하세요 도움이 엄청 많이 됬습니다.
혹시 git 코드를 받아서 더 자세히 공부하고 싶은데 공유 가능할까요?
git 코드를 받아보니 메인 파일들이 블락 되어있는것 같습니다.

답글 달기