Phase 1 | ROS로 조명 및 공조 시스템 제어하기 |
roslibjs설치로 웹페이지에 생명 불어넣기
지금까지 HTML +CSS로 웹페이지를 꾸몄습니다. 이전 포스팅들에서 종종 비유했듯, 지금까지 그냥 기초공사와 외벽만 세우고, 인테리어만 했습니다. 전기 없고, 인터넷 없고, 수도와 하수구 없는 집에 사람이 살 수 없듯, HTML과 CSS자체만으로는 어떤 역할도 수행하지 못합니다. 이제 여기에 javascript를 통해 생명을 불어 넣어 ros와 웹페이지가 연동될 수 있도록 해보겠습니다.
rosbridge, roscore, django, roslibjs
전에 리눅스에서 ROS 환경 세팅하기 글에서 언급하였듯, roslibjs는 웹 브라우저에서 ROS와 상호작용하기 위한 javascript 라이브러리입니다. roslibjs는 웹브라우저를 통해 실행하며, 리눅스에서 ROS 환경 세팅하기에서 설치한 rosbridge_suite의 rosbridge_websocket과 통신합니다. 말하자면 이들의 연결을 위해 지금 3개의 웹서버를 돌리고 있다는 뜻입니다. 조금은 복잡할 수 있으니 각 서버의 역할을 설명드리겠습니다.
rosbridge_websocket (ws://0.0.0.0:9090) | roslibjs가 시스템의 ROS에 접근하는 경로입니다. 유저가 브라우저로 접속해도 할 수 있는 게 없습니다.
roscore (ROS_MASTER_URI) | rosserial을 사용하는 NodeMCU가 ROS에 진입하는 경로입니다.
Django (127.0.0.1:8000) | 유저가 roslibjs를 조작하기 위한 경로입니다. 여기서 제어를 할 수 있습니다.
여기에서는 rosbridge_websocket을 설치하고, roslibjs 를 설치해서 웹페이지와 ROS 간 상호작용을 할 수 있도록 해 보겠습니다.
리눅스 터미널을 열어 ~catkin_ws/cranberry_web/dashboard/static/js 에서 다음의 명령어를 실행합니다.
git clone https://github.com/RobotWebTools/roslibjs
roslibjs에 관한 자세한 정보는 여기에서 확인할 수 있습니다.
roslibjs를 다운로드 했으니, html에서 불러올 수 있도록 index.html파일의 <head> 태그에 있던 주석을 해제합니다.
<!-- ~/catkin_ws/src/cranberry_web/dashboard/templates/index.html -->
{% load static %}
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Cranberry</title>
<link rel="stylesheet" href="{% static 'css/style.css' %}">
<script src="{% static 'js/roslibjs/build/roslib.js' %}"></script>
<script src="{% static 'js/script.js' %}"></script>
...
</head>
이제 roslibjs를 사용할 수 있습니다. 예제를 한 번 사용해 보고 싶으시다면 clone한 경로 내에 examples/simple.html을 사용해보셔도 좋습니다. 자세한 내용은 ROS 카테고리에서 한번 더 다루도록 하겠습니다.
javascript 코딩
~catkin_ws/cranberry_web/dashboard/static/js에 scripts.js 파일을 생성해 아래의 내용을 작성합니다.
// ~/catkin_ws/src/Cranberry/Cranberry_web/dashboard/static/js/scripts.js
// Written 2020-10-09 by whiteknight
// https://whiteknight3672.tistory.com
var ros = new ROSLIB.Ros();
// rosbridge websocket server와의 연결을 생성합니다.
ros.connect('ws://0.0.0.0:9090');
///////////////////ros 상태 관련 구문///////////////////
// ros와의 연결 상태에 따라 상단 액션바의 색깔이 녹색, 회색, 빨간색으로 변동됩니다.
// 이상이 생길 경우 다음 구문이 실행됩니다.
ros.on('error', function (error) {
console.log(error);
document.getElementById('header').style.backgroundColor = "#f03737";
});
// 정상 연결
ros.on('connection', function () {
console.log('Connection made!');
document.getElementById('header').style.backgroundColor = "#07a666";
});
// 연결 닫힘
ros.on('close', function () {
console.log('Connection closed.');
document.getElementById('header').style.backgroundColor = "#a0a0a0";
});
// 서비스 및 변수 선언
var iLightClient = new ROSLIB.Service({
ros: ros,
name: '/comm_light',
serviceType: 'cranberry_topic/CommLight'
});
var state = 0;
// 창이 불러와졌을 때 다음 구문을 실행합니다.
window.onload = function () {
// index.html에서 id가 light_01인 요소를 클릭했을 때, update_light 함수가 실행합니다.
document.getElementById("light_01").onclick = function () { update_light("light_01"); }
}
function update_light(light_id) {
// html에 존재하는 요소 자체의 값을 읽어와 처리합니다.
if (document.getElementById(light_id).innerHTML == 0) { state = 1; document.getElementById(light_id).innerHTML = 1; }
else if (document.getElementById(light_id).innerHTML == 1) { state = 0; document.getElementById(light_id).innerHTML = 0; }
//문자열 데이터 'light_id'를 숫자 데이터로 변환합니다.
var light_num = Number(light_id.split('_')[1]);
//target과 state에 대한 정보를 포함하는 toggle_light Request를 만듭니다.
//이 request 값은 한 번 선언되면 변치 않는 것 같습니다. 따라서 매 update_light 함수가 실행될 때마다 선언합니다.
var toggle_light = new ROSLIB.ServiceRequest({
target: light_num,
state: state
});
//위에서 선언한 서비스를 호출합니다.
iLightClient.callService(toggle_light, function (result) {
console.log("result : " + toggle_light.target + ':' + result.result)
// 시각적으로 상태를 파악하도록 ROS에서 준 response에 따라 CSS 스타일을 업데이트합니다.
if (result.result == 1) {
document.getElementById(light_id).style.backgroundColor = "#FFE600";
document.getElementById(light_id).style["boxShadow"] = "0 0 12px 4px rgba(187, 137, 0, 0.5)";
}
else if (result.result == 0) {
document.getElementById(light_id).style.backgroundColor = "#808080";
document.getElementById(light_id).style["boxShadow"] = "0 0 6px 3px rgba(0, 0, 0, 0.5)";;
}
else {
document.getElementById(light_id).style.backgroundColor = "#ff0000";
document.getElementById(light_id).style["boxShadow"] = "0 0 6px 3px rgba(0, 0, 0, 0.5)";;
}
})
Done!
이제 웹페이지 단에서 할 일은 끝났습니다. 우선 서버를 실행시켜 rosbridge_websocket과 Django 위에서 돌아가는 roslibjs 가 잘 작동하는지 확인합니다.
// 웹소켓 서버
roslaunch rosbridge_server rosbridge_websocket.launch
// Django 웹서버
cd ~/catkin_ws/src/Cranberry/cranberry_web && source web-env/bin/activate && python manage.py runserver
127.0.0.1:8000으로 웹페이지에 접속한 후, F12를 눌러 개발자 도구에 들어갑니다. console 탭을 클릭했을 때, connection made! 라고 표시되면 성공적입니다.
긴 글 읽어주셔서 감사합니다.
글이 도움이 되셨다면 왼쪽 아래의 공감버튼과 광고 클릭 부탁드립니다. 고마움을 표현할 수 있는 가장 쉬운 방법입니다.