[ROS] Part 2, Concept of Modularity
หลังจากโดนหลอกให้ Cliff hanger ไปใน [ROS] Part 1, Introduction + Installation ! แล้ว
รวมไปถึงคนเขียนซึ่งหางานหาการทำได้แล้ว(มาปีครึ่ง) -*-
เลยมีเวลาเขียนน้อยลง
อันนี้จะเป็นเรื่องของ Concept จริงๆซักทีนะ !!
โปรดระวัง บทความนี้มีรูปภาพเยอะมากๆๆๆๆ
จากตอนที่แล้ว ผมได้ยัดเยียดการ Install ROS ลงไปใน Ubuntu ของทุกคนแล้ว
เราจะมาพูดถึง Terminology(ส่วนประกอบพื้นฐาน) ของ ROS กันหน่อย
ว่า เราจะเขียนโปรแกรมโดยใช้หลักการของอะไร ของต่างๆเรียกยังไง
อยากจะย้ำเรื่อง Concept
ROS นั้นช่วยให้ผู้พัฒนาหุ่นยนต์
สามารถส่ง message ระหว่าง module ต่างๆในระบบได้ง่ายดาย
นั้นคือ concept หลักๆของมัน
โดยวันนี้เราจะมาพูดถึงโครงสร้างของ Software ที่จะเกิดขึ้นกัน
ขอมาตั้งคำศัพท์กันหน่อยก็แล้วกัน
Terminology — Vocabulary
ลองจำๆแบบไม่จำเป็นต้องรู้ความหมายจริงจังก็ได้ ขอแค่พอเข้าใจคร่าวๆ ใช้งานไปแล้วจะเข้าใจเอง 55555
Node — ส่วนของโปรแกรมที่ทำหน้าที่เฉพาะ
เช่น
Node ของการจับหน้าคน
Node ของการขับเคลื่อนมอเตอร์
Node ของการรับค่าจาก Joystick
มองมันเป็น Module หนึ่งใน Software ก็ได้
จริงๆมันจะมีสิ่งที่เรียกว่า Nodelet ด้วยนะเออ แต่อันนั้นมัน Advance มากเลย
เป็นการ Implement Node ในลักษณะที่ทำให้ทำงานไวมากๆ ด้วย Zero copy pointer (ถ้าคนเคยเขียนภาษา C มาจะรู้ว่าแม่งไวจริง)
เอาไว้ทำงานล้ำๆ แต่การเขียนมันจะยากหน่อย ในระดับเริ่มต้น แนะนำว่าให้ข้ามๆไปก่อน ถ้าไม่ได้ยุ่งกับพวก Algorithm เดือดๆมากนัก
Message — ข้อความที่ Node ใช้คุยกัน
เช่น ข้อความทั่วๆไป ก็ string (ข้อความ) , int(จำนวนเต็ม) , double (จำนวนทศนิยม)
หรือ จะเป็นตัวที่ ROS Provide standard ให้
เช่น Vector3 ที่เรากรอกค่า (x,y,z) ได้
Robot Specific หน่อย ก็ — Transformation frame , geometry_msgs::Twist , GoalTarget
หรือจะเป็น Custom ที่ทำเอง เช่น tutormessage ที่ประกอบด้วย int 5 ค่า แบบนี้ก็ได้
Topic — ช่องทางที่ Node ใช้ส่ง Message หรือรอฟัง Message
เป็นเรื่องที่จะส่งคุยกันนั่นแหละ เหมือนเป็น ห้อง Chat , Group ลับๆ 18+ หรืออะไรก็ตาม จะไม่มีใครพ่นเรื่องอื่นในห้องนั้น !!
เราสามารถตั้งชื่อ Topic ได้ตามใจเรา แต่ส่วนใหญ่จะตามหัวข้อเรื่อง
เช่น /detected_faces , /command_velocity , /transformation_frame , . ..
โดยจะเสมือนเป็นท่อที่ทิ่มออกจาก Node
มีความสามารถแบบ IN-OUT (ทั้งรับและส่ง) ผ่านท่อนี้เลย
โดย Node นึงจะมีได้หลาย Topic อยู่ที่จะเป็นการรับ หรือเป็นการส่งข้อมูล
การรับและการส่งข้อมูลใน ROS จะเป็น Message broadcasting based
คนส่ง คนรับ ?
คนส่งข้อความจะเรียกว่า
- Publisher — ตัวส่งสาส์น
ทำหน้าที่ ขับ MSG ออกทางท่อ TOPIC ที่กำหนดไว้ (ออกทางท่อฝั่งส่ง)
ซึ่ง Publisher จะอยู่ใน Node และจะมีกี่อันก็ได้
คนรับจะเรียกว่า
- Subscriber — คนรับสาส์น
ทำหน้าที่ รับ MSG ตามท่อ TOPIC ที่วางไว้ (ท่อฝั่งรับ)
จากการปู้ยี้ปู้ยำ จะได้รูปหน้าตาประมาณนี้
สังเกตดีๆจะพบว่า ของมันถูกแบ่งเป็นเรื่องๆ และคนอื่นจะมาจิ้มเข้าตรงไหนเพิ่มเติมก็ได้
เห็นได้ชัดเจนว่าการใช้ Message Passing (การส่งข้อความ) แบบนี้เนี่ย
มันช่วยลดความเบลอ ตอนเวลา Code มากๆเลย
ถึงเวลาจะใช้ก็เรียกใช้ ถึงเวลาจะส่งก็ส่ง มันทำให้อะไรๆง่ายขึ้นเยอะ
ที่พูดๆมานี้เรียก ระบบ MESSAGING
ซึ่งจริงๆมี 3 แบบ
- แบบส่งๆรับๆ ไม่สนใจเงื่อนไขอะไร ส่งก็ส่งไป รับก็รับไป “ส่งแบบต่อเนื่อง”
- แบบส่ง แล้วรอคำตอบ (รอได้ไม่นานนะ หงุดหงิด เชอะ !)
- แบบส่งทิ้งไว้ ไม่รอคำตอบ(เพราะต้องรอนาน)
แต่ถ้ามีคำตอบมาเมื่อไหร่ ค่อยมาบอก
1. ROS MESSAGE (STREAM)
คือการส่ง Message ระหว่าง Node ต่างๆใน ROS
การส่งจะเป็นแบบ Stream ข้อมูลแบบต่อเนื่อง ส่งไป มีคนรับไม่รับไม่รู้ คนส่งมีหน้าที่ส่ง อยากจะส่งเมื่อไร ก็ส่ง
คนรับ ก็รอฟังอย่างเดียว ส่งมาถึงที่ หรือล่มกลางทางก็ไม่รู้ แต่ถ้าได้รับข้อความเมื่อไร ก็ใช้งานผ่าน Receive callback function
ตัวอย่างของจริงๆ ! — ขับหุ่นยนต์ !
สมมติว่าเรามี ฐานหุ่นยนต์อยู่ สามารถสั่งการเป็น
ความเร็วลงไปที่ฐานหุ่นยนต์ได้ ผ่าน Serial Port
เรามี Joystick อยู่ ติดต่อผ่าน Driver ของ Joystick
สิ่งที่เราต้องใช้คือ
- MOTOR DRIVER NODE
Node ที่ทำหน้าที่ เขียนคำสั่งความเร็วหุ่นยนต์
ส่ง แบบ Serial ลงไปตามสาย USB ที่ต่อกับฐานหุ่นยนต์
เรียกได้ว่าเป็น Low level Communication Node - JOYSTICK ACTION MAPPING NODE
Node ที่ติดต่อกับ Driver Joystick (ดึงค่าปุ่ม ค่าคันโยก) - JOYSTICK (DRIVER ของจอย) NODE
Node ที่ทำหน้าที่แปลงค่าจาก Joystick ให้เป็นความเร็วของหุ่นยนต์
ซึ่งพบว่าพวกนี้ แม่งมักจะมีคนเขียนทิ้งไว้ให้โหลดมาใช้กันฟรีๆ และเป็นของดีที่ test มาแล้ว ( สบายตัวละกู ไม่ต้องเขียนเอง 555555+ )
ตอนนี้เราก็เรียนรู้ concept ของการส่งข้อมูลใน ROS แล้ว
จริงๆแล้วมันยังไม่จบ !
หลังจากที่เราเข้าใจ สิ่งที่เรียกว่า ROS — Message แล้ว
มันเลยเอา Message ไปทำ Operation แบบอื่นๆได้ อีกสองแบบ
คือ
ROS Services
และ
ROS ActionLib (Action Library)
(ซึ่งจริงๆมันก็คือการส่ง ROS Message แหละ แต่เค้าสร้างตัวช่วยขึ้นมาเพิ่ม)
2. ROS Services
เนื่องจาก ROS Message จะเป็นการส่งข้อมูลกันแบบ Stream ต่อเนื่อง
อยากจะส่งก็ส่ง อยากจะหยุดก็หยุด
คนที่ส่งได้ตลอด ก็ส่งตลอด
ไม่สนใจคนรับว่าจะเอาไปใช้งานอะไรไหม
แล้วถ้าอยากทำอะไรแค่ครั้งเดียวล่ะ ขอแค่ทีเดียว
ก็เลยต้องมี Paradigm แบบ Request Response ขึ้นมาบ้าง สำหรับการกระทำบางอย่างที่เราต้องการรอผลลัพธ์ของการ Request เพื่อทำอะไรบางอย่าง
ROS Service เลยทำหน้าที่นี้ คือ การส่ง Message แบบ ไม่เน้นความต่อเนื่อง มี Request มี Response
ตัวอย่างจริงๆก็คือ
ส่ง Request ไปขอ แผนที่จาก Node ที่ถือไฟล์รูปหน่อย
เราสามารถตอบ Request ของ service นี้ว่า สำเร็จหรือไม่สำเร็จก็ได้
เช่น
Request ให้ไปหารูป SORA.jpg แต่ดันไม่มีไฟล์ ก็ตอบ Failed กลับมา
หรือถ้าสำเร็จ ก็ส่ง Array ของรูป คืนกลับไปให้คนขอใช้งาน
หรืออีกตัวอย่าง คือ Request ขอเปิดไฟ
(คงไม่ขอเปิดไฟรัวๆ แบบ Message Stream ใน ROS Message แบบที่ 1)
ก็คือการ request เปิดไฟไป ถ้าเปิดติดแล้ว ก็ return succeed กลับมาให้ ประมาณนี้
แล้วถ้า เปิดอยู่แล้ว ดันสั่งเปิดด้วยเนี่ย ก็ Return failed มา พร้อมข้อความบอกว่า มันเปิดอยู่แล้วเฟร้ยย แบบนี้ก็ได้
คนที่ Request ต้องรอ response เสมอ เหมือนสัญญาใจ ! ห้ามไปคุยกับใครเลย รอเท่านั้น ~!
(จริงๆก็มี Timeout ของการรอนะ แต่ขอเล่า Theme ประมาณนี้ก่อน)
อ้าว แล้วถ้าไม่อยากรอล่ะ
ก็คนรักกันมันไว้ใจได้ เดี๋ยวเค้าก็กลับมาเอง !
ไปใช้ Action Library ไป๊
3. ROS Action Library
สำหรับใช้งานกับ Task ที่ กินเวลาน๊านนาน แล้วไม่อยากรอคำตอบ(นานไป๊) เช่น สั่งให้หุ่นยนต์เดินรอบโลก รอบนึง
ถ้าเป็น Service ก็จะต้องรอคำตอบไปจนกว่าจะมีคน Response (หรือ timeout หมดไป) ได้แห้งตายกันพอดี
Action-lib จะใช้หลักการคือ ส่ง Goal เข้าไป (ส่งเป้าหมาย)
แล้ว คนที่รับเป้าหมายไปทำ สามารถ Report progress มา (เรียก feedback)
และ สามารถ Report เมื่อเป้าหมายถึงจุดที่ต้องสิ้นสุด
( Succeed หรือ Aborted(failed) )
ถ้าเข้าใจ Service มา ในส่วนนี้ก็ไม่ยากเลย ก็คือ Service ที่เราสามารถ ดู Progress ได้ ว่ามันทำถึงไหนแล้ว และ รอคำตอบแบบ Asynchronous (ไม่ได้หยุดทั้งโปรแกรมเพื่อรอ คำตอบนั้นๆ — โปรแกรมทำอย่างอื่นต่อได้ ไว้คำตอบมาเมื่อไร ค่อยมาดูกันว่าจะทำยังไงต่อไป)
ตอนนี้เรามีอาวุธ 3 ชิ้นในมือแล้ว ในการใช้ ROS Framework ของเรา
ทั้งหมดนี้คือความพยายามย่อยในหัวข้อที่ชี้ๆ ให้เป็นภาษาที่คนทั่วไปมาอ่านแล้วพอจะเข้าใจแบบนัวๆ ไม่ลึกมาก ถ้าอยากจะเจาะไปที่ประเด็นเลย
ลองไปอ่านตามลิงค์นี้เน้อ
RECAP : Episode
นี้เราได้รู้ว่า ROS ทำให้เราแบ่งโปรแกรมในตัวหุ่นยนต์ออกเป็นก้อนๆเป็นเรื่องๆได ้
มันสามารถคุยกันด้วย Message ได้ ผ่านทาง Topic
โดยการส่ง Message นั้น
- จะส่งเป็น Stream ก็ได้ (ROS Message)
- จะเป็น Single Operation แบบ Blocking การทำงานตัวเอง เพื่อรอ(ROS Service)
- หรืออาจเป็นการ Dispatch Long term action แบบไม่ Blocking (ROS Action-lib)
โดยทั้ง 3 แบบนี้ จะเป็นรูปแบบสากลในการส่งข้อความแหละ !
เราจะเอาไปทำอะไรดี
มาทำหุ่นยนต์บังคับกันเถอะ !!! [ROS] Part 3 Workspaces (Catkin)
แล้วก็หลอกให้รอ Episode ถัดไปอีกปีนึง 5555555555555555555555555
จะรีบเขียนให้ไวที่สุดเน้ออออ :)
ปุกาศๆๆๆ : ช่วงขายของและ Tie-in
เอ้อ ตอนนี้ ติวทำงานประจำอยู่ที่ Obodroid Corporation นะ
ทำหุ่นยนต์เพื่อใช้งานในที่พักอาศัย
ไม่ว่าจะเป็น Assistant robot , Security robot , Cart Robot
ที่สำคัญสุดคือ !! WE’RE HIRING (ประกาศ ณ. 10–3–2018)
ถ้าอยากทำงานด้านหุ่นยนต์ ไม่ว่าจะเป็น Mechanical engineer , Robotics Software engineer , Perception&ML,Deep,AI Engineer ก็ ลองสมัครเข้ามาได้ :)
ส่ง Resume มาที่ jobs@hiveground.com ได้เลยจย้าา