REP (ROS Enhancement Proposals) ของ ROS
REP คือ กฏเกณฑ์ให้คนที่ใช้ ROS ทำตาม เพื่อจะได้มีมาตรฐานตรงกัน
http://www.ros.org/reps/rep-0000.html
โดยการสร้าง Package ใน ROS จะมี Layout องค์ประกอบดังนี้
อ้างอิง http://www.ros.org/reps/rep-0128.html#recommended-layout
1. Package Manifest — ตัวที่จะบอกว่า Package นี้ มีรายละเอียดยังไง ต้องการไปพึ่งพิง Code คนอื่นไหม (ตัวช่วย Compile Code , Reference Code ใน Level สูงๆ จะอ่านตรงนี้ และไปอ้างอิงให้)
2. CMakeLists.txt — เป็น พิมพ์เขียวของงานนี้ โดยจะเก็บรายละเอียดว่า เรา Run Code ไฟล์ไหนเป็นจุดเริ่มต้นของงาน, Code ต่างๆอ้างอิงกันยังไง , เราอ้างอิง Code Library ของชาวบ้านคนอื่นๆมาใช้กับ Code เราไฟล์ไหนบ้าง
* CMakeLists (MakeFile) ตัวนี้สำคัญ *
3. Codeของเรา จะเก็บใน Folder ดังนี้
(อ้างอิงตาม REP ซึ่งก็คือข้อควรปฏิบัติตามของ ROS ซึ่งควรจะทำตาม )
3.1. “src” — จะเก็บ Source Code ภาษา C++ ที่เป็นส่วน Implementation
(ส่วนของ Header จะเก็บแยก)
3.2. “include/ชื่อPackage/”- จะเก็บ Header ภาษา C++
3.3. “scripts” — จะเก็บ Code Python
3.4. Config ต่างๆ อันนี้ไม่ซีเรียสมาก แต่ปกติจะสร้าง Folder ชื่อ param , config บ้าง แล้วแต่คนชอบ
4. ตัวสร้าง Message , Service , Action ของ ROS หรือที่เรียก Message Structure , Message Prototype
4.1. ROS Message — จะอยู่ใน Folder “msg”
4.2. ROS Service — จะอยู่ใน Folder “srv”
4.3. ROS Action — จะอยู่ใน Folder “action”
โดย Catkin build system จะให้ ROS มาคว้า “หน้าตา” ของ Message Service และ Action จากบริเวณนี้ Auto เลย
Python ไม่มี header เหมือนกับ C++ เลยใช้แค่ Folder ในการเก็บ Code แค่บริเวณเดียว
ถึงตอนนี้ พอสรุปได้ดังนี้
1 Workspace สามารถจะมีหลายๆ Packages
ใน 1 Package สามารถจะมีได้หลายๆ Node
และ ใน 1 Node มักจะทำหน้าที่ขั้นต่ำ 1 หน้าที่ ขึ้นไป
โครงสร้าง ก็หน้าตาประมาณนี้
การสร้าง Package ด้วยภาษา C++
เริ่มแรก เรามาออกแบบกันก่อน เรากำลังจะทำ Node 2 อัน ที่ทำหน้าที่พูดคนนึง และ รับฟังคนนึง
Package ชื่อ : chatter_subscriber_tutorial
โดยใช้ Dependencies ดังนี้:
1. catkin (build system)
2. roscpp (ROS ภาษา C++)
3. std_msgs (Package ข้อความพื้นฐานใน ROS)
อยากจะสร้าง Node ที่ทำหน้าที่เป็น
Publisher 1 Node ทำหน้าที่ส่งข้อความ
Subscriber 1 Node ทำหน้าที่รับข้อความแล้วหาคำตอบ — แล้วแสดง
สร้าง Workspace จากบทความก่อนหน้านี้ สร้าง Workspace ของ ROS
จะมี catkin_ws เป็น Workspace ของเราที่สร้างมาแล้วนั่นเอง
catkin_create_pkg ชื่อ วรรค ตามด้วย dependency หลายๆตัว ที่เว้นวรรค 1 ที
cd catkin_ws/src
catkin_create_pkg chatter_subscriber_tutorial catkin roscpp std_msgs
เราจะได้โฟลเดอร์ที่มีชื่อว่า chatter_subscriber_tutorial ขึ้นมา พอเป็นเข้าไปด้านใน จะพบว่ามี โฟลเดอร์ และไฟล์ มารอดังนี้
วางโครงสร้างของ Code C++
เราจะต้องอธิบาย Package เราก่อนว่า ประกอบด้วยอะไร และไปใช้งานใครบ้าง
ติดตั้งโปรแกรม Geany IDE ไว้สำหรับแก้ไขไฟล์ต่างๆของเรา
sudo add-apt-repository ppa:geany-dev/ppa
sudo apt-get update
sudo apt-get install geany geany-plugins
เปิดโปรแกรม Geany IDE ด้วยคำสั่ง geany
geany
เปิดไฟล์ CMakeLists.txt ขึ้นมาแก้ไข
1. add_executable จะเป็นการบอกว่า มีอะไรที่ run ได้บ้าง และ ตั้งชื่อมันว่าอะไร ด้วยการใช้คำสั่งดังนี้
add_executable(ตั้งชื่อexecutable วรรค ตามด้วย ไฟล์ Node ที่มี Main)
add_executable(ตั้งชื่อexecutable วรรค ตามด้วย ไฟล์ Node ที่ไม่มี Main)
add_executable(my_publisher src/my_publisher.cpp)
add_executable(my_subscriber src/my_subscriber.cpp)
(ซึ่งปกติมักจะไปถามเอาจาก catkin ด้วย การพิมพ์ catkin_EXPORTED_TARGETS)
add_dependencies(ชื่อexecutable export-targetต่างๆ)
add_dependencies(my_publisher ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
add_dependencies(my_subscriber ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
3. target_link_libraries
target_link_libraries(ชื่อexecutable วรรคตามด้วย Libraries ต่างๆ)
target_link_libraries(my_publisher ${catkin_LIBRARIES})
target_link_libraries(my_subscriber ${catkin_LIBRARIES})
...................
ไฟล์เปล่าๆ แบบไม่มี Comment จาก Catkin
cmake_minimum_required(VERSION 2.8.3)
project(chatter_subscriber_tutorial)
find_package(catkin REQUIRED COMPONENTS
roscpp
std_msgs
)
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES chatter_subscriber_tutorial
# CATKIN_DEPENDS roscpp std_msgs
# DEPENDS system_lib
)
include_directories(
# include
${catkin_INCLUDE_DIRS}
)
add_executable(my_publisher src/my_publisher.cpp)
add_executable(my_subscriber src/my_subscriber.cpp)
add_dependencies(my_publisher ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
add_dependencies(my_subscriber ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(my_publisher
${catkin_LIBRARIES}
)
target_link_libraries(my_subscriber
${catkin_LIBRARIES}
)
เขียนโค้ดภาษา C++
เปิดโปรแกรม Geany IDE คลิกสร้างไฟล์ใหม่
Save เก็บไฟล์ไว้ที่ โฟลเดอร์ chatter_subscriber_tutorial/src
Save เก็บไฟล์ไว้ที่ โฟลเดอร์ chatter_subscriber_tutorial/src
1. สร้าง Node ตัวส่งข้อความ “Publisher”
ไฟล์ : my_publisher.cpp
#include "ros/ros.h" #include "std_msgs/String.h" #include <sstream> int main(int argc, char **argv) { ros::init(argc, argv, "talker"); ros::NodeHandle n; ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000); ros::Rate loop_rate(10); int count = 0; while (ros::ok()) { std_msgs::String msg; std::stringstream ss; ss << "hello world " << count; msg.data = ss.str(); ROS_INFO("%s", msg.data.c_str()); chatter_pub.publish(msg); ros::spinOnce(); loop_rate.sleep(); ++count; } return 0; }
2. สร้าง Node ตัวรับข้อความ “Subscriber”
ไฟล์ : my_subscriber.cpp
#include "ros/ros.h" #include "std_msgs/String.h" void chatterCallback(const std_msgs::String::ConstPtr& msg) { ROS_INFO("I heard: [%s]", msg->data.c_str()); } int main(int argc, char **argv) { ros::init(argc, argv, "listener"); ros::NodeHandle n; ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback); ros::spin(); return 0; }
cd catkin_ws
catkin_make
roscore
หลังจากนั้นจึง Run Node ของเราได้
rosrun ชื่อpackage ชื่อexecutableที่กำหนดในCMakeLists.txt
(หน้าต่างที่ 2) เปิด Publisher (ตัวส่งข้อมูล)
rosrun chatter_subscriber_tutorial my_publisher
(หน้าต่างที่ 3) ตามมาด้วยการเปิด Subscriber (ตัวฟัง/รับข้อมูล)rosrun chatter_subscriber_tutorial my_subscriber
กด Ctrl + C ถ้าต้องการหยุดการทำงาน
หมายเหตุ : เรียบเรียงและแก้ไขดัดแปลงจากบทความต้นฉบับด้านล่าง