센서 데이터 시각화를 할 때 다른 건 다 잘 되는데, point cloud가 잘 나오지 않는 문제가 있었다.
foxglove는 웹소켓 통신을 이용하는 만큼, 데이터 양 조절이 관건이다.
roslaunch foxglove_bridge foxglove_bridge.launch topic_whitelist:="['/cam1/point_cloud_face']" send_buffer_limit:=10000000
bridge 소스코드를 살펴보면 foxglove_bridge.launch 파일은 다음과 같이 생겼다.
<launch>
<arg name="port" default="8765" />
<arg name="address" default="0.0.0.0" />
<arg name="tls" default="false" />
<arg name="certfile" default="" />
<arg name="keyfile" default="" />
<arg name="topic_whitelist" default="['.*']" />
<arg name="param_whitelist" default="['.*']" />
<arg name="service_whitelist" default="['.*']" />
<arg name="client_topic_whitelist" default="['.*']" />
<arg name="max_update_ms" default="5000" />
<arg name="send_buffer_limit" default="10000000" />
<arg name="nodelet_manager" default="foxglove_nodelet_manager" />
<arg name="num_threads" default="0" />
<arg name="capabilities" default="[clientPublish,parameters,parametersSubscribe,services,connectionGraph,assets]" />
<arg name="asset_uri_allowlist" default="['^package://(?:\w+/)*\w+\.(?:dae|fbx|glb|gltf|jpeg|jpg|mtl|obj|png|stl|tif|tiff|urdf|webp|xacro)$']" />
<arg name="service_type_retrieval_timeout_ms" default="250" />
<node pkg="nodelet" type="nodelet" name="foxglove_nodelet_manager" args="manager"
if="$(eval nodelet_manager == 'foxglove_nodelet_manager')">
<param name="num_worker_threads" type="int" value="$(arg num_threads)" />
</node>
<node pkg="nodelet" type="nodelet" name="foxglove_bridge"
args="load foxglove_bridge/foxglove_bridge_nodelet $(arg nodelet_manager)">
<param name="port" type="int" value="$(arg port)" />
<param name="address" type="string" value="$(arg address)" />
<param name="tls" type="bool" value="$(arg tls)" />
<param name="certfile" type="string" value="$(arg certfile)" />
<param name="keyfile" type="string" value="$(arg keyfile)" />
<param name="max_update_ms" type="int" value="$(arg max_update_ms)" />
<param name="send_buffer_limit" type="int" value="$(arg send_buffer_limit)" />
<param name="service_type_retrieval_timeout_ms" type="int" value="$(arg service_type_retrieval_timeout_ms)" />
<rosparam param="topic_whitelist" subst_value="True">$(arg topic_whitelist)</rosparam>
<rosparam param="param_whitelist" subst_value="True">$(arg param_whitelist)</rosparam>
<rosparam param="service_whitelist" subst_value="True">$(arg service_whitelist)</rosparam>
<rosparam param="client_topic_whitelist" subst_value="True">$(arg client_topic_whitelist)</rosparam>
<rosparam param="capabilities" subst_value="True">$(arg capabilities)</rosparam>
<rosparam param="asset_uri_allowlist" subst_value="True">$(arg asset_uri_allowlist)</rosparam>
</node>
</launch>
10MB가 기본인데, 데이터 양이 많아지면 Send buffer limit reached 라는 경고가 나오며 속도도 느려지고 송수신 자체도 잘 안 되는 것 같다. 따라서 내가 시각화하고자 하는 토픽을 압축해서 재발행하는 노드 를 운영하고, foxglove_bridge는 해당 토픽만 포트로 넘기도록 조절해 주어야 한다.
yaml 파일 만들기
우선 apt로 설치한 foxglove_bridge를 git clone으로 받아서 컴파일해준다. 이 과정에서 websocketepp이 없다는 에러가 나오면
sudo apt-get install libwebsocketpp-dev
이걸로 깔아 준다.
yaml 파일에서 원하는 설정을 불러올 수 있도록 하자.
# /config/robot.yaml
foxglove_bridge:
topics:
- "/cam1/point_cloud_face"
- "/tf"
- "/tf_static"
send_buffer_limit: 100000000
port: 8765
address: "0.0.0.0"
그리고 launch 파일을 수정해준다.
<param name="address" value="$(eval rosparam.get('/foxglove_bridge/address'))" />
<param name="send_buffer_limit" value="$(eval rosparam.get('/foxglove_bridge/send_buffer_limit'))" />
<rosparam param="topic_whitelist" subst_value="True">$(eval rosparam.get('/foxglove_bridge/topics'))</rosparam>
Topic Compressor
foxglove는 모니터링 툴이기 때문에 팍팍 줄여도 되지 않을까 ? 그래서
topic_compressor:
topics:
- name: "point_cloud_1"
from: "/cam1/point_cloud_face"
to: "/cam1/point_cloud_face/compressed"
compression_ratio: 10
- name: "point_cloud_2"
from: "/camera/depth/points"
to: "/camera/depth/points/compressed"
compression_ratio: 10
이런 식으로 compression ratio를 지정해주면 메시지 타입에 맞게 데이터 양을 줄여주는 패키지를 만들어서 토픽을 재발행했다.
실시간성, 데이터 완전성과는 거리가 멀지만 그래도 육안으로는 딜레이가 크지 않다.
특정 토픽만 브릿지로 연결해주고 그 특정 토픽도 팍팍 줄여서 발행하면 다음과 같이 웹소켓으로도 딜레이가 좀 줄어든다.