หลังจากจบงาน Thammasat Open House 2019 ไป เราก็จะมาแชร์ประสบการณ์ การทำหุ่นยนต์น้องไอโกะ ที่ไปเดินเล่นบนเวทีตอนพิธีงานเปิด ก่อนอื่นขอท้าวความกันก่อนว่า ระยะเวลาที่เราได้เข้ามาทำงานนี้เพียงหนึ่งเดือนนิดๆ ซึ่งก็เจอความท้าทายหลายๆอย่างเอามาเล่าต่อกันฟัง
มารู้จักตัวหุ่นยนต์ก่อน
ตัวหุ่นยนต์นี้ เป็นเพียงฮาร์ดแวร์ ชิ้นใหญ่ๆ ที่ประกอบไปด้วยคอมสองเครื่อง และส่วนประกอบๆ เช่น หัว ขา(ล้อ) หน้าจอบนหน้า หน้าจอใหญ่ที่ตัว และเซ็นเซอร์ต่างๆมากมายหลายตัว
คอมเครื่องแรกจะเป็นตัวที่เชื่อมต่อกับส่วนประกอบหลักๆอย่างพวก หัว ล้อ หน้าจอบนหน้า และพวกเซ็นเซอร์ ส่วนเครื่องที่สองจะเชื่อมกับหน้าจอใหญ่ที่ตัว
การจะควบคุมตัวหุ่นยนต์ทุกอย่างต้องทำผ่านคอมเครื่องที่สอง ที่จะทำหน้าที่ส่งคำสั่งไปคอมเครื่องหลักอีกที
ทั้งหมดนี้เป็นสิ่งที่บริษัทของหุ่นยนต์ตัวนี้ได้ออกแบบมา แต่เราอาจจะมาแก้ไขหลักการควบคุมเองต่อได้ ถ้ามีเวลามาแกะการทำงานของมันนะ
มาเริ่มลงมือทำจริงกัน
การควบคุมพื้นฐาน
อย่างแรกที่ต้องทำคือ เข้าถึงการควบคุมหุ่นยนต์ให้ได้ก่อน ซึ่งก็มี 2 ทางเลือกด้วยกัน อย่างแรกคือใช้ package ที่ตัวบริษัททำมาให้ ซึ่งเขียนบนภาษา c# กับ ทางเลือกที่สอง ก็ลองแกะดูว่ามันคุยกันยังไง ส่งสัญญานกันยังไง ถ้าเราเข้าใจ เราจะเอาไปเขียนบนภาษาไหนก็ได้
ด้วยข้อจำกัดด้านเวลา สุดท้ายจึงเลือกที่จะใช้ทางเลือกแรก ทำให้เราต้องมานั่งศึกษาภาษา c# กันใหม่ นอกจากจะศึกษาพวก syntax แล้ว ก็ต้องไปดูพวกสไตล์การเขียนของภาษานี้ ซึ่งก็ใช้เวลาไปสัปดาห์นึงได้ ต่อมาเราก็ต้องมานั่งทำความเข้าใจวิธีคำสั่งต่างๆใน package ตัวนี้ ซึ่งก็เป็นที่มาของปัญหาแรกที่เจอเลยคือ documentation ค่อนข้างแย่มาก ไม่ได้อธิบายวิธีใช้งานที่ชัดเจน คำอธิบายวัตถุประสงค์ของแต่ละคำสั่งไม่ชัดเจน และที่ยิ่งไปกว่านั้น ชื่อคำสั่งในเอกสาร กับตอนเรียกใช้จริงคนละชื่อ TT เลยทำเอาเสียเวลางมกันไประดับนึง จนถึงจะนำมาใช้จริงได้ (แต่ที่เสียเวลาส่วนนึงก็มาจากความที่เรายังไม่คุ้นชินกับภาษา c# ด้วย) หลังจากทำความเข้าใจในส่วนนี้เรียบร้อยหมดแล้ว เราก็สามารถเอามาทำเป็นสคริปการขยับตัว พยักหน้า ต่างๆไรพวกนี้
ต่อมา เพื่อที่จะทำให้หุ่นยนต์สามารถพูดภาษาไทยได้ แน่ๆเราคงไม่อัดเสียงลงไป วิธีที่ใช้คือ Text-To-Speech โดย ณ ขณะนั้น เลือกใช้
ResponsiveVoice.js และด้วยความที่มันเป็น js หรือ javascript เราก็ต้องเขียนเว็ปรันไว้เบื้องหลังให้สามารถรันสคริปพูดเหล่านี้ได้
หลังจากรันสิ่งที่หุ่นยนต์ควรทำได้แล้ว ปัญหาต่อมา เราจะสั่งการทางไกลยังไงดีละ ซึ่งปัญหานี้ก็จะแยกเป็น 2 ส่วน
- ส่วนแรก คือฝั่งฮาร์ดแวร์ว่า เราจะใช้ช่องทางไหน หลักๆที่ใช้ควบคุมทางไกลก็มี Bluetooth กับ Wifi เราเลือกใช้ Wifi เพราะสัญญาณไกล และเสถียรกว่า และที่สำคัญสำหรับเรามาก คือ มันใช้ protocol ในการสื่อสารที่เราคุ้นเคย คือพวก Internet Protocol แล้วเมื่อเลือกใช้ Wifi ก็ต้องคิดต่อว่า จะใช้ช่วงสัญญาน 2.4GHz หรือ 5GHz เราก็เลือกใช้ 5GHz ถึงแม้ระยะทางที่สัญญาณไปถึงจะสั้นกว่า แต่สิ่งที่แลกได้มาคือ ความความหนาแน่นของสัญญานน้อยกว่า เพราะเราต้องใช้สัญญาณเหล่านี้ในห้องประชุมใหญ่ที่เต็มไปด้วยคนจำนวนมาก และความเสถียรของสัญญาณซึ่งก็เป็นผลมาจากความหนาแน่นของสัญญาณน้อยกว่าเช่นกัน แล้วถึงจะบอกว่าระยะทางที่ครอบคลุมจะสั้นกว่า แต่ก็เพียงพอมากแล้วสำหรับงานของเรา
- ส่วนที่สอง ฝั่งซอฟแวร์บ้าง เราทำงานบน Internet ดังนั้น protocol ที่จะใช้มี RESTful api กับ Socket.io โดยเราทำ RESTful server บน c# เพื่อให้เราสามารถ สั่งการหุ่นยนต์จากเว็ป หรือแอปได้ สำหรับงานนี้ เราก็ได้สร้างเว็ปขึ้นอีกตัว เป็นรีโมทคอนโทรล ยิง post get request ไปที่เซิร์ฟเวอร์ c# ตอนนี้เรายังไม่สามารถสั่งการส่วนพูดได้ เพราะ มันรันเป็น client ดังนั้นเราเลยต้องเปิดท่อสื่อสารทิ้งไว้ กะว่าจะใช้ SignalR บน c# เลย แต่ยังไม่คุ้นเคยกับมัน เลยสุดท้าย เราเปิดเซิร์ฟเวอร์อีกตัวบน nodejs เพิ่ม แล้วใช้ socket.io ไว้สื่อสารกับเว็ปพูด แต่เมื่อต้องการจะสั่งให้พูด เราก็จะยิงมาจากเว็ปรีโมท ไปที่ nodeJS แล้วให้ nodeJS ส่งต่อคำสั่งไปอีกที ตามภาพโครงสร้างด้านล่าง
- *** อาจจะสงสัยทำไม่เรายิงจากเว็ปนึงไปอีกเว็ปนึงเลยไม่ได้ เพราะว่าเว็ปไซด์ ซึ่งเราจัดว่าเป็น client โดยปกติไม่รองรับการเป็นตัวรับ พวก post get request จะทำหน้าที่ส่ง request พวกนี้ซะมากกว่า แล้วเพื่อที่จะให้เว็ปไซด์สามารรับ request ได้ เราเลยต้องเปิดท่อช่องทางติดต่อทิ้งไว้กับเซิร์ฟเวอร์ซักตัว ให้สามารถติดต่อกลับได้ตลอดเวลา โดยใช้ socket protocol แล้วให้เซิร์ฟเวอร์รับ request มาก่อนแล้วส่งต่ออีกที
ตอนนี้ เป้าหมายใหญ่ๆ เราเหมือนจะจบลงแล้ว เราควบคุมตัวหุ่นยนต์ทางไกลได้แล้ว สั่งให้พูดได้แล้วทุกอย่างควรจะลงตัวแล้ว แต่ตอนมารันทุกอย่างพร้อมกัน เราจึงพบปัญหาต่อมาคือ คอมแลค คอมของหุ่นยนต์เนี่ยแหละ เพราะเราเลือกที่จะรันทั้งเซิร์ฟเวอร์ c# และ nodeJS นอกจากนี้เรายังรัน Unity เป็นตัวแสดงภาพบนจอใหญ่ แล้วเมื่อเรารันพวกสคริปอย่างการขยับหัว ตอนแรกเราให้มันขยับแค่นิดเดียว แต่เพราะความกระตุก บางครั้งมันก็ขยับไปมาก มากกว่าที่คิด บางครั้งก็ขยับน้อยยิ่งกว่าที่ตั้งใจ
วิธีแก้อย่างง่ายสุด คือพึ่งความสามารถของ CPU ที่เรามี 4 คอร์ เราก็แบ่งการทำงานให้ชัดเจนไปเลย เอาไปคนละคอร์จบๆ สั้นๆ ( เผื่อใครอยากลองทำตามแบบง่าย ลองไปเสริซหา “set affinity” )
เพียงเท่านี้ หุ่นยนต์ของเราก็พร้อมขึ้นเวทีกันแล้วละ
แต่……… เมื่อลองไปรันบนเวทีจริงแล้ว เจออีกปัญหา พวกสคริปที่สั่งขยับหัวหุ่นยนต์กลับคลาดเคลื่อนจากตำแหน่งที่ตั้งใจไว้ไปเยอะมาก แล้วจูนเท่าไหร่ก็ยังไม่เข้าที่ เวลาก็เหลือน้อยเหลือเกิน จากเดิมตั้งใจไว้ว่าจะใช้คนคุมเพียง 2 คนเท่านั้น สุดท้ายเราก็ใช้คน 4 คนเพื่อคุมหุ่นยนต์ตัวนี้ตัวเดียว
เมื่อถึงวันจริง ทุกอย่างรันได้ราบรื่น ตามที่วางแผนไว้ อันเป็นจบพิธี
ใครที่อ่านมาถึงจุดนี้แล้ว อาจจะสงสัย พูดถึงหุ่นยนต์ตั้งเยอะแยะ แต่ไหงไม่พูดถึง AI เลย ซึ่งตามนั้นเลย เราไม่ได้เอาส่วนไหนที่ทำงานเป็น AI เลย หลักๆก็ด้วยข้อจำกัดด้านเวลา และความคลาดเคลื่อนของตำแหน่งหุ่นยนต์ที่หนักมาก ไม่มีวิธีมาตั้งค่าโรงงานที่ดีพอ ในกรณีนี้เราเลยรันทุกอย่างด้วยมือ สั่งการด้วยมือ ไม่ได้มีการตอบโต้ของหุ่นยนต์ด้วยตัวมันเอง แต่อย่างน้อยเราก็สร้างฐานมารองรับสำหรับงานถัดๆไป เราอาจจะมาทำให้มันฉลาดขึ้น ตอบโต้ได้เอง แต่จะเป็นยังไง ก็คงต้องติดตามกันต่อไป ;-)
เขียนบทความรอบนี้ เราไม่ได้เจาะลึกเนื้อหาใดๆ แค่มาเล่าภาพรวมตอนทำงาน และปัญหาที่พบเจอระหว่าง หวังว่าพอจะเป็นประโยชน์ได้บ้าง หากต้องมาทำงานแนวนี้ จะได้คิดเผื่อๆ ปัญหาเหล่านี้ได้
จบถึงตรงนี้ก็ขอลากันไปก่อน ไว้เจอกันใหม่