ROS2 package란?

  • ROS2 코드의 컨테이너
  • 최소 패키지 구조
    • package.xml : 패키지에 대한 메타 정보가 포함된 파일
    • CMakeLists.txt : 패키지 내에서 코드를 빌드하는 방법을 설명하는 파일
  • 보통 저장공간은 ~/dev_ws/src/패키지 로 구성함

 

실습

1. Create a package

--node-name NODE_NAME : name of the empty executable

cd ~/dev_ws/src
ros2 pkg create --build-type ament_cmake <package_name>
ros2 pkg create --build-type ament_cmake --node-name <node_name> <package_name>

 

2. Build a package

같은 workspace root에 존재하는 package들은 "colcon build"로 한 번에 빌드가 가능하다.

다른 workspace root에 존재한다면 개별적으로 빌드를 해야한다.

 

현재는 ~/dev_ws가 workspace이므로 이 경로에서 빌드를 해준다.

cd ~/dev_ws
colcon build

 

이렇게 하면 하위 경로의 패키지들은 전부 빌드가 된다. 패키지가 많다면 시간이 오래 걸릴 수 있다.

하나의 패키지만 빌드하고 싶다면 다음과 같은 명령어를 사용하면 된다.

colcon build --packages-select <package_name>

 

3. Source the setup file

새로운 패키지를 사용하고 실행시키기 위해서는 빌드한 것과 다른 터미널에서 ~/dev_ws에서 다음과 같은 명령어를 사용한다.

이 명령어는 작업 공간을 경로에 추가시켜준다.

. install/setup.bash

 

4. Use the package

아래와 같은 명령어로 패키지를 실행시킨다.

ros2 run <package_name> <node_name>

 

아래와 같은 결과가 출력된다.

 

5. Examine package contents

dev_ws/src/<package_name> 내부에서 ros2 pkg create ~ 명령어로 자동으로 생성된 파일과 폴더를 확인할 수 있다.

 

6. Customize package.xml

1단계에서 맨 마지막 명령어를 입력했을 때 패키지의 정보가 반환된 것을 볼 수 있다.

이 때 description: TODO: Package description 이라고 적힌 것을 볼 수 있다.

이 부분은 자동적으로 설정되지 않고 패키지를 릴리즈할 때 작성하면 된다.

maintainer 부분도 마찬가지다.

 

텍스트 에디터로 ~/dev_ws/src/<package_name>/package.xml을 수정해서 바꿀 수 있다.

 

예제에서는 다음과 같이 바꿨다.

<description> ~ </description> 부분과

<license> ~ </license> 부분만 변경하면 된다.

<?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>my_package</name>
 <version>0.0.0</version>
 <description>TODO: Package description</description>
 <maintainer email="user@todo.todo">user</maintainer>
 <license>TODO: License declaration</license>

 <buildtool_depend>ament_cmake</buildtool_depend>

 <test_depend>ament_lint_auto</test_depend>
 <test_depend>ament_lint_common</test_depend>

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

ros2 bag 이란?

  • topic에 pub된 데이터를 기록하기 위한 도구
  • 여러가지 topic에 대해 전달된 데이터를 누적하여 데이터베이스에 저장함 

 

실습

1. 설정

- 터미널 1

ros2 run turtlesim turtlesim_node

- 터미널 2

ros2 run turtlesim turtle_teleop_key

- 터미널 3 ( 저장 디렉토리 생성 및 이동 )

mkdir bag_files
cd bag_files

 

2. Choose a topic

- 터미널 3 ( topic 목록 )

ros2 topic list

 

이해를 쉽게 하기 위해서 rqt_graph를 띄워보았다.

아래에서 볼 수 있듯이 /turtle_teleop node가 거북이를 움직이게 하기 위해서 /turtle1/cmd_vel topic을  pub한다.

 

이 데이터를 보기 위해서는 다음과 같은 명령어를 사용할 수 있다. (필수는 아님 그냥 시각화)

ros2 topic echo /turtle1/cmd_vel

 

3. ros2 bag record

데이터를 기록하려면

- ros2 bag record <topic_name>

이라는 명령어를 사용한다.

 

- 터미널 3

ros2 bag record /turtle1/cmd_vel

 

터미널 2를 활성화 시킨 후 거북이를 움직인다. 

^C(Ctrc+C)를 눌러 종료한다.

 

3.1 Record multiple topics

-o 옵션을 추가하면 파일의 이름을 지정할 수 있다.

- 터미널 3

ros2 bag record -o subset /turtle1/cmd_vel /turtle1/pose

 

추가로 한 번에 여러 topic을 기록하려면 각 topic을 공백으로 구분해서 나열하면 된다.

 

-a 옵션을 추가하면 시스템의 모든 topic을 기록할 수 있다.

 

4. ros2 bag info

- ros2 bag info <bag_file_name>

이 명령어를 사용해서 세부정보를 볼 수 있다.

 

- 터미널 3

ros2 bag info subset

 

 

5. ros2 bag play

터미널 2를 Ctrl+C를 눌러 종료시킨다.

 

- 터미널 3

ros2 bag play subset

 

거북이가 앞서 움직였던 것과 비슷하게 움직이는 모습을 볼 수 있다.

rqt_console이란?

ROS2에서 log 메시지를 검사하는 데 사용되는 GUI 도구

 

실습

1. 설정

- 터미널 1

ros2 run rqt_console rqt_console

- 터미널 2

ros2 run turtlesim turtlesim_node

 

2. Messages on rqt_console

log 메시지를 만들기 위해 거북이를 벽에 부딪히게 한다.

- 터미널 3

ros2 topic pub -r 1 /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0,y: 0.0,z: 0.0}}"

 

아래의 사진처럼 터미널의 log가 rqt_console에 출력되는 것을 볼 수 있다.

 

 

3. Logger levels

  • Fatal : 시스템이 손상되지 않기 위해 종료
  • Error : 시스템을 반드시 손상시키지는 않지만 제대로 작동하지 못하게 하는 문제
  • Warn : 기능에 해를 끼치지는 않지만 비이상적인 결과 / 심각한 문제 발생할 수 있음을 경고
  • Info : 시스템이 예상대로 실행되고 있음을 시각적으로 확인하는 역할
  • Debug : 시스템 실행의 전체 단계별 프로세스를 자세히 설명. 숨겨짐

 

3.1 Set the default logger level

아래와 같은 명령어를 사용하면 Warn 미만의 log는 출력되지 않는다.

Warn 대신에 Error를 쓰면 Warn log 메시지가 출력되지 않는다.

ros2 run turtlesim turtlesim_node --ros-args --log-level WARN

Action이란?

  • 장기 실행 작업을 위한 ros2의 통신 방법
  • topic & service 기반
  • client-server 모델 사용

 

 

실습

1. 설정

터미널 2개를 열고 다음과 같은 명령어를 실행한다.

(참고 : ros2 run <package_name> <executable_name>)

- 터미널 1

ros2 run turtlesim turtlesim_node

- 터미널 2

ros2 run turtlesim turtle_teleop_key

 

2. Use actions

터미널 2 에 명령어를 입력했을 때 G|B|V~ 라는 출력을 볼 수 있다.

이는 키보드에서 F를 둘러싼 키들인데 각각 거북이의 머리를 어디로 둘 것이냐 하는 키다.

F는 거북이가 회전하는 도중에 누르면 거북이가 회전하다가 멈춘다.

 

 

3. ros2 node info

- 터미널 3

ros2 node info /turtlesim

 

위와 같은 명령어를 치면 /turtlesim의 subscriber, publisher, service, action server, action client list가 출력된다.

/turtlesim
  Subscribers:
    /parameter_events: rcl_interfaces/msg/ParameterEvent
    /turtle1/cmd_vel: geometry_msgs/msg/Twist
  Publishers:
    /parameter_events: rcl_interfaces/msg/ParameterEvent
    /rosout: rcl_interfaces/msg/Log
    /turtle1/color_sensor: turtlesim/msg/Color
    /turtle1/pose: turtlesim/msg/Pose
  Services:
    /clear: std_srvs/srv/Empty
    /kill: turtlesim/srv/Kill
    /reset: std_srvs/srv/Empty
    /spawn: turtlesim/srv/Spawn
    /turtle1/set_pen: turtlesim/srv/SetPen
    /turtle1/teleport_absolute: turtlesim/srv/TeleportAbsolute
    /turtle1/teleport_relative: turtlesim/srv/TeleportRelative
    /turtlesim/describe_parameters: rcl_interfaces/srv/DescribeParameters
    /turtlesim/get_parameter_types: rcl_interfaces/srv/GetParameterTypes
    /turtlesim/get_parameters: rcl_interfaces/srv/GetParameters
    /turtlesim/list_parameters: rcl_interfaces/srv/ListParameters
    /turtlesim/set_parameters: rcl_interfaces/srv/SetParameters
    /turtlesim/set_parameters_atomically: rcl_interfaces/srv/SetParametersAtomically
  Action Servers:
    /turtle1/rotate_absolute: turtlesim/action/RotateAbsolute
  Action Clients:

 

여기서 /turtle1/rotate_absolute이 Action Server인 것을 알 수 있는데 이건 /turtlesim이 /turtle1/rotate_absolute action에 대해 응답하고 피드백한다는 것을 의미한다.

 

 

반대로 아래 명령어의 출력을 확인해보면

ros2 node info /teleop_turtle

Action Clients 아래에 /turtle1/rotate_absolute 가 존재하는 것을 알 수 있는데 이건 이 action에 대해 goal을 보낸다는 것을 의미한다.

 

--- 주관적 해석 ---

/teleop_turtle에서 goal을 설정해주면

/turtlesim에서 응답 및 피드백을 보내준다.

 

 

4. ros2 action list

action list를 확인하려면 다음과 같은 명령어를 사용한다.

ros2 action list

 

현재는 /turtle1/rotate_absolute 이 결과를 반환할 것이다.

 

추가적으로 다음 명령어를 사용하면 action의 type도 함께 알아낼 수 있다.

ros2 action list -t

 

현재는 /turtle1/rotate_absolute [turtlesim/action/RotateAbsolute] 을 반환한다.

 

 

 

5. ros2 action info

- 터미널 3

ros2 action info /turtle1/rotate_absolute

 

출력은 다음과 같다.

Action: /turtle1/rotate_absolute
Action clients: 1
    /teleop_turtle
Action servers: 1
    /turtlesim

 

 

6. ros2 interface show

action goal을 직접 보내거나 실행하기 위해선 구조를 알아야한다. 다음 명령어를 사용한다.

ros2 interface show turtlesim/action/RotateAbsolute

 

출력은 다음과 같다.

# The desired heading in radians
float32 theta
---
# The angular displacement in radians to the starting position
float32 delta
---
# The remaining rotation in radians
float32 remaining

 

section1 : goal request의 구조

section2 : result의 구조

section3 : feedback의 구조

더보기

예를 들어 10을 보냈는데 8만큼 돌았다고 가정해보자.

goal request : 10

result : 8

feedback : 2

 

7. ros2 action send_goal

action goal을 터미널에서 실행하는 명령어는 다음과 같다.

ros2 action send_goal <action_name> <action_type> <values>

 

- 터미널 3

ros2 action send_goal /turtle1/rotate_absolute turtlesim/action/RotateAbsolute "{theta: 1.57}"

 

다음과 같은 결과가 반환된다.

Waiting for an action server to become available...
Sending goal:
     theta: 1.57

Goal accepted with ID: 87cff62b6d97438b87d5433048a3ba34

Result:
    delta: 0.0

Goal finished with status: SUCCEEDED

 

 

여기에 피드백을 추가하려면 feedback 옵션을 추가한다.

ros2 action send_goal /turtle1/rotate_absolute turtlesim/action/RotateAbsolute "{theta: -1.57}" --feedback

 

목표가 완료될 때까지 피드백을 계속해서 받는다.

parameter란?

  • node의 구성 값 ( = node 설정 )
  • int, float, bool, string, list로 저장 가능'

 

실습

1. 설정

터미널 2개를 열고 다음과 같은 명령어를 실행한다.

(참고 : ros2 run <package_name> <executable_name>)

- 터미널 1

ros2 run turtlesim turtlesim_node

- 터미널 2

ros2 run turtlesim turtle_teleop_key

 

2. ros2 param list

node에 속한 parameter를 보려면 다음과 같은 명령어를 입력한다.

- 터미널 3

ros2 param list

 

아래와 같이 출력된다.

/teleop_turtle:
  scale_angular
  scale_linear
  use_sim_time
/turtlesim:
  background_b
  background_g
  background_r
  use_sim_time

 

 

3. ros2 param get

매개변수 값을 확인하기 위해선 아래와 같은 명령어를 사용한다.

ros2 param get <node_name> <parameter_name>

 

예를 들어 다음과 같이 명령어를 실행해서 배경의 rgb 중 g 값을 알아낼 수 있다.

- 터미널 3

ros2 param get /turtlesim background_g

 

 

4. ros2 param set

런타임 시에 매개변수 값을 변경하려면 다음 명령을 사용한다.

ros2 param set <node_name> <parameter_name> <value>

 

/turtlesim의 배경색을 변경하기 위해선 아래와 같은 명령어를 사용하면 된다.

ros2 param set /turtlesim background_r 150

아래 사진처럼 배경색이 바뀐다.

 

이 명령은 영구적으로 저장되지 않고 현재 세션에만 저장된다.

 

 

5. ros2 param dump

file로 변경한 명령을 저장할 수 있는 명령어이다.

ros2 param dump <node_name>

 

아까 바꿨던 설정을 저장하기 위해선 아래와 같은 명령어를 사용한다.

ros2 param dump /turtlesim

 

./turtlesim.yaml에서 변경된 값을 확인할 수 있다.

 

 

6. ros2 param load

방금 저장한 파일을 이용해서 파라미터를 변경한다.

ros2 param load <node_name> <parameter_file>

 

- 터미널 3

ros2 param set /turtlesim background_r 0
ros2 param load /turtlesim ./turtlesim.yaml

 

결과는 아래와 같다.

 

 

7. Load parameter file on node startup

저장한 파라미터로 동일한 노드를 실행하려면 다음과 같은 명령어를 사용한다.

ros2 run <package_name> <executable_name> --ros-args --params-file <file_name>

 

- 터미널 3

ros2 run turtlesim turtlesim_node --ros-args --params-file ./turtlesim.yaml

 

service란?

  • topic 이외의 노드 간 통신 방법
  • topic을 통해 node는 데이터 스트림을 구독해 지속적인 업데이트를 얻을 수 있지만 service는 client가 특별히 호출한 경우에만 데이터를 요청

 

실습

1. 설정

- 터미널 1

ros2 run turtlesim turtlesim_node

- 터미널 2

ros2 run turtlesim turtle_teleop_key

 

2. ros2 service list

현재 활성화 된 service list 확인 명령어는 아래와 같다.

- 터미널 3

ros2 service list

아래와 같이 출력된다.

/clear
/kill
/reset
/spawn
/teleop_turtle/describe_parameters
/teleop_turtle/get_parameter_types
/teleop_turtle/get_parameters
/teleop_turtle/list_parameters
/teleop_turtle/set_parameters
/teleop_turtle/set_parameters_atomically
/turtle1/set_pen
/turtle1/teleport_absolute
/turtle1/teleport_relative
/turtlesim/describe_parameters
/turtlesim/get_parameter_types
/turtlesim/get_parameters
/turtlesim/list_parameters
/turtlesim/set_parameters
/turtlesim/set_parameters_atomically

 

3. ros2 service type

service type은 topic과 비슷하게 정의되지만 요청과 응답 두 부분이 존재한다.

 

service type은 다음 명령으로 찾을 수 있다.

- 특정 service 확인

ros2 service type <service_name>

ex) ros2 service type /clear

 

- 전체 service 확인

ros2 service list -t

 

 

4. ros2 service find

특정 타입을 사용하는 서비스를 찾고 싶다면, 다음과 같은 명령어를 사용하면 된다.

ros2 service find <type_name>

예를 들어 std_srvs/srv/Empty 형식을 사용하는 서비스를 찾고 싶다면 아래와 같은 명령어를 입력한다.

- 터미널 3

ros2 service find std_srvs/srv/Empty

그러면 다음과 같이 출력된다.

 

 

5. ros2 interface show

topic 예제에서 했던 것처럼 service type을 구체적으로 확인해보자.

 

-터미널3 (ros2 interface show <type_name>.srv)

ros2 interface show turtlesim/srv/Spawn.srv

아래와 같이 출력된다.

 

--- 위의 4줄은 /spawn을 호출하려면 필요한 인자들을 말한다. 

이 경우는 아니지만 보통 --- 라인 아래는 호출에서 받은 응답의 데이터 유형을 이해하는 데 도움이 된다.

 

 

6. ros2 service call

ros2 service call <service_name> <service_type> <arguments>

위와 같은 명령어를 이용해서 터미널에서도 서비스를 호출할 수 있다.

 

- ros2 interface show std_srvs/srv/Empty.srv

이 명령어를 통해서 이 서비스에는 인자가 없다는 것을 알 수 있다.

따라서 다음과 같은 명령어를 사용하면 거북이가 그린 선을 모두 지울 수 있다.

ros2 service call /clear std_srvs/srv/Empty

 

또한 아래의 명령어를 이용해서 새로운 거북이를 만들 수 있다.

ros2 service call /spawn turtlesim/srv/Spawn "{x: 2, y: 2, theta: 0.2, name: ''}"

 

https://ropiens.tistory.com/41?category=828450 

 

ROS2 foxy 튜토리얼3 - ROS2 노드(node) 이해하기

그동안은 ROS2의 학습용 패키지인 turtlesim 패키지만을 돌려봤습니다. 이번 차 부터는 그 것들이 어떻게 돌아가는 지 내부를 알아보면서 다시 한 번 학습을 해 보겠습니다. 오늘은 노드(node)에 대해

ropiens.tistory.com

 

이 블로그를 보고 따라해보다가 뒷부분을 이어서 써본다.

 

 

Topic이란?

  • node가 메시지를 교환하는 버스 역할
  • 여러 topic에 데이터를 게시 및 구독할 수 있음.
  • 데이터가 node 간에 이동하는 주요 방법 중 하나

 

 

실습

1. 설정

터미널 2개를 열고 다음과 같은 명령어를 실행한다.

(참고 : ros2 run <package_name> <executable_name>)

- 터미널 1

ros2 run turtlesim turtlesim_node

- 터미널 2

ros2 run turtlesim turtle_teleop_key

 

2. rqt_graph

또 다른 터미널을 열고 rqt_graph를 실행한다.

- 터미널 3

rqt_graph

 

 

위와 같은 창을 볼 수 있다.

이 그래프는 방금 실행시킨 /turtlesim 노드와 /teleop_turtle 노드가 topic에 대해 서로 통신하는 모습을 보여준다.

/teleop_turtle node는 키 데이터를 /turtle1/cmd_vel topic에 pub하고 /turtlesim node는 그 topic을 sub해서 데이터를 받아온다.

 

3. ros2 topic list

새로운 터미널에서 다음과 같은 명령어를 입력해 현재 활성화된 topic list를 확인한다.

- 터미널 4

ros2 topic list

그러면 다음과 같은 list가 반환된다.

/parameter_events
/rosout
/turtle1/cmd_vel
/turtle1/color_sensor
/turtle1/pose
더보기

참고로 $ ros2 node info /turtlesim 을 입력했을 때도 

Subscribers와 Publishers에 같은 topic이 출력된다.

 

4. ros2 topic echo

pub되는 data를 확인하려면 다음과 같은 명령어를 사용한다.

- ros2 topic echo <topic_name>

위 그림의 /turtle1/cmd_vel topic을 확인해볼 것이다.

- 터미널 4

ros2 topic echo /turtle1/cmd_vel

 

터미널 4가 실행되는 채로 놔두고 터미널 2를 클릭해서 활성화 시킨 후 turtle을 방향키로 조작해본다.

그러면 터미널 4에 다음과 같이 출력될 것이다.

 

다시 rqt_graph로 가서 Debug의 체크를 해제한 후 왼쪽 상단의 새로고침을 누른다.

그러면 창이 아래와 같이 바뀌는데 /turtle1/cmd_vel topic을 다른 node가 sub하고 있는 것을 알 수 있다.

아래의 /_ros2cil_17865 가 터미널 4에서 실행한 노드이다.

 

 

5. ros2 topic info

topic의 정보를 보고 싶다면 다음과 같은 명령어를 사용하면 된다.

- ros2 topic info <topic_name>

- 터미널 5

ros2 topic info /turtle1/cmd_vel

그러면 아래와 같이 Topic Type과 Publisher, Subscription count가 출력된다.

 

6. ros2 interface show

ros2 topic list -t 라는 명령어를 사용하면 현재 topic의 message type을 알려준다.

- 터미널 5

ros2 topic list -t

아래의 사진에서 확인할 수 있듯이 /turtle1/cmd_vel은 geometry_msgs/msg/Twist를 사용한다.

이것은 geometry_msgs 안에 Twist라고 불리는 msg가 있다는 걸 의미한다.

 

이 메시지 구조에 대해 자세히 알고 싶다면 다음과 같은 명령어를 이용한다.

- 터미널 5

ros2 interface show geometry_msgs/msg/Twist

다음과 같이 출력된다.

4번째 과정에서 확인한 것과 같은 형식으로 구성되어 있는 것을 확인할 수 있다.

 

 

7. ros2 topic pub

6번째 과정에서 메시지 구조를 알 수 있었다.

메시지 형식만 맞춘다면 터미널에서 직접 데이터를 게시하는 것이 가능하다.

ros2 topic pub <topic_name> <msg_type> <args> 꼴로 작성하면 된다.

 

-터미널 5

ros2 topic pub --once /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 1.8}}"

거북이가 호를 그리는 것을 확인할 수 있다.

 

여기서 --once 는 하나의 메시지를 게시한 후 종료하는 옵션이다. 만약 이 옵션을 추가하지 않는다면 ^C를 누르기 전까지 계속해서 거북이가 빙글빙글 돈다.

 

ros2 topic pub --rate 1 /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 1.8}}"

이 명령어는 --once를 제거한 후 --rate 1 옵션을 추가한 명령어인데 1Hz로 메시지를 게시하는 것이다.

 

 

8. ros2 topic hz

아래와 같은 명령어를 사용해서 topic이 게시되는 hz를 볼 수 있다.

ros2 topic hz <topic_name>

목표

목표.

이번 작품의 목표는 다량의 데이터가 들어왔을 때 두 개의 서버에서 나누어서 처리하는 분산 처리 서버 구현이었다.

원래 계획했던 작품은 웹페이지로 클라이언트에게 이미지 파일이 압축된 zip 파일을 받고, 메인 서버에서 zip 파일을 압축 해제하며 파일을 byte로 서브 서버에게 전송한다. 그러면 서브 서버가 ocr을 진행한 후 DB에 저장하는 작품이었다.

시스템 아키텍쳐
BARAM_21년도_후반기_제안서_28기_19김다현.hwp
1.36MB

 

문제점

문제점 1.

web으로 클라이언트의 요청을 받으려했는데 그러면 MAIN server를 spring을 이용해 web server로 구현해야 했었다. spring을 사용하기 때문에 java를 사용했다. 근데 sub server는 C로 구현해서 통신이.... 너무 어려웠다.

이미지 하나의 전송까지는 성공했지만 2개부터 잘 되지 않았다..ㅠㅠ

문제점 2.

sub server는 AWS에서 무료로 제공하는 서비스를 이용했다. 근데 AWS에서 무료로 제공하는 서버의 성능이 너무 좋지 않았다. 어느 정도였냐면 tesseract를 사용하기 위해서는 opencv를 설치해야했는데 opencv의 컴파일이 되지 않았다. tesseract 진행 후 DB 구현하는 걸 구현은 해두었는데 서버에 올릴 수 없었다.

 

결과

결과.

그래서 결과적으로는 3개의 서버를 모두 C 서버로 구현해서 소켓통신을 했다.

결과물로는 클라이언트와 로드밸런싱과 DB 저장 정도? 계획했던 작품에 비해서는 결과가 제대로 나오지는 않았지만 load balancing과 socket 통신을 구현해볼 수 있는 기회였다.

설명.

AWS에서 2개의 서버를 대여한 후 아래의 "server.c" 코드(데이터 수신 및 DB 저장)를 각각 서버에 넣어주고 실행파일을 만든 후 서버를 실행시켜준다.

main server의 9999 port를 이용해서 로드밸런서를 구현했으므로 client는 main server의 9999 포트에 접속해서 이미지를 전송한다. 이때 파일 전송은 스레드로 구현해서 속도를 향상시켰다.

클라이언트는 같은 주소로 파일을 전송하지만 서버 두 개가 데이터를 번갈아서 받는 모습을 볼 수 있다. round robbin으로 로드밸런싱을 구현했기 때문에 순차적으로 데이터를 전송받는 것이다.

전송이 끝나면 이미지들이 DB에 저장된다.

 

코드

최종 코드.

https://github.com/ekgus2222/multiserver

 

GitHub - ekgus2222/multiserver: testset

testset. Contribute to ekgus2222/multiserver development by creating an account on GitHub.

github.com

결과 코드는 여기서!

 

 

[HAProxy] TCP 로드밸런싱
https://hyunisland.tistory.com/71

 

[HAProxy] TCP 로드밸런싱

/* * ubuntu 18.04 - 서버 3개 & 클라이언트 * HA-Proxy version : 1.8.40 */ 총 서버는 3개를 준비했다. 하나의 클라이언트에서 HAProxy 서버에 접속하면 HAProxy 서버가 연결된 2개의 서버에 로드밸런싱을 해준..

hyunisland.tistory.com

TCP 로드밸런싱은 여기서!

 

 

 

추가 코드.

[socket 통신] java client & c server 간 이미지 전송
https://hyunisland.tistory.com/68

 

[Tesseract + DB]

OCR + Tesseract
DB 결과

#include<string>
#include<tesseract/baseapi.h>
#include<leptonica/allheaders.h>
#include<opencv4/opencv2/opencv.hpp>

#include "/usr/include/mysql/mysql.h"
#include <string.h>
#include <stdio.h>


void main(int argc, char *argv[])
{
    char* impath = argv[1]; // path 설정
    string outText, imPath = impath;
    Mat im = cv::imread(imPath, IMREAD_COLOR);
    tesseract::TessBaseAPI *api = new tesseract::TessBaseAPI();

    api->Init(NULL, "eng", tesseract::OEM_LSTM_ONLY);
    api->SetPageSegMode(tesseract::PSM_AUTO);
    api->SetImage(im.data, im.cols, im.rows, 3, im.step);
    outText = string(api->GetUTF8Text());
    cout<<outText;
    api->End();

    MYSQL       *connection=NULL, conn;
    MYSQL_RES   *sql_result;
    MYSQL_ROW   sql_row;
    int       query_stat; 

    char text[20];
    strcpy(text, outText.c_str());
    char time[80] = "230";
    char query[255];
    
    mysql_init(&conn);

    connection = mysql_real_connect(&conn, DB_HOST,
                                    DB_USER, DB_PASS,
                                    DB_NAME, 3306,
                                    (char *)NULL, 0);

    if (connection == NULL)
    {
        fprintf(stderr, "Mysql connection error : %s", mysql_error(&conn));
        return;
    }

    // query_stat = mysql_query(connection, "select * from text");
    // if (query_stat != 0)
    // {
    //     fprintf(stderr, "Mysql query error : %s", mysql_error(&conn));
    //     return 1;
    // }
    
    // sql_result = mysql_store_result(connection);
    
    // printf("%-11s %-11s %-11s\n", "id", "텍스트", "시간");
    // while ( (sql_row = mysql_fetch_row(sql_result)) != NULL )
    // {
    //     printf("%-11s %-11s %-11s\n", sql_row[0], sql_row[1], sql_row[2]);
    // }

    mysql_free_result(sql_result);

    printf("input text : %s\n", text);
    //fgets(text, 12, stdin);
    CHOP(text);

    printf("input time : %s\n", time);
    //fgets(time, 80, stdin);
    CHOP(time);

    printf("\n");

    sprintf(query, "insert into text(text,time) values ('%s', '%s')",
                   text, time);

    query_stat = mysql_query(connection, query);
    if (query_stat != 0)
    {
        fprintf(stderr, "Mysql query error : %s", mysql_error(&conn));
        return;
    }
    else {
	printf("insert ok\n");
    }

    mysql_close(connection);
}

+ Recent posts