Moulick (มูลิก - ภาษาบังคลาแปลว่า "พื้นฐาน/สำคัญ") คือของเล่นคณิตศาสตร์ที่ขับเคลื่อนด้วย Arduino คอยคำนวณจำนวนเฉพาะไปเรื่อยๆ พร้อมโชว์สถิติสนุกๆ เกี่ยวกับมันระหว่างทาง การเฝ้าดูจำนวนเฉพาะถือกำเนิดไม่เคยน่าตื่นเต้น (หรือช้า) เท่านี้มาก่อน มูลิกเริ่มนับจาก 2 แล้วพาน้องตะลุยไปจนถึงเลข 10 หลักด้วยความเร็วที่เรียกได้ว่า "บ้าบิ่นและไม่ปลอดภัยสุดๆ (สำหรับ Arduino นะเว้ย!)"* ดูวิดีโอการทำงานของมันด้านล่างเลย
*เลข 10 หลักน่ะ... อย่าหวังว่าจะเห็นในชาตินี้เลยน้อง รับประกันไม่ได้นะจ๊ะ ข้อตกลงเป็นโมฆะในเขตที่กฎหมายห้าม จำนวนเฉพาะคือความจริงของธรรมชาติ ครอบครอง ซื้อขาย หรือจดสิทธิบัตรไม่ได้
สมัยเด็กพี่บ้ากับวงจรอิเล็กทรอนิกส์ ไมโครโพรเซสเซอร์ และหุ่นยนต์สุดๆ ตอนนี้ก็ยังชอบอยู่แหละ แต่งานประจำที่ก็วนเวียนอยู่กับคอมพ์ (และสมัยเป็นนักศึกษาปริญญาโท/เอกก็อิเล็กทรอนิกส์) มันทำให้ไฟในการมานั่งแกะเล่นของที่บ้านมอดลงหน่อย ตอนนี้ถ้ามีเวลาก็จะไปทำสวนหรืองานไม้แทน นี่แหละข้ออ้างว่าทำไมพี่ถึงยังไม่เคยทำโปรเจค Arduino สักที! แต่... มาสายดีกว่าไม่มาเนอะ
พี่ได้แรงบันดาลใจมาจากของเล่น "Primer" ของ Karl Lautman นะ ของเล่นตัวนั้นต้องกดปุ่มเพื่อไปยังจำนวนเฉพาะตัวถัดไป และจำกัดอยู่แค่ 6-7 หลัก สิ่งที่ทำให้มันเจ๋งคือเสียงคลิกดังกร๊ากเวลามันเปลี่ยนเลข โดยใช้ตัวนับแบบกลเป็นจอแสดงผล
เสน่ห์หลัก (ฮ่าๆ) ของมูลิกอยู่ที่การได้เฝ้าดูมันวิ่งผ่านจำนวนเฉพาะตัวเล็กๆ เร็วปรื๊ด แล้วค่อยๆ ช้าลงจนน้องต้องกัดเล็บบนเตียงรอ ว่าจะเป็นจำนวนเฉพาะมั้ยนะ? หรือแค่เลขประกอบตัวร้ายกาจ? แล้วก็ดีใจสุดๆ เมื่อได้เห็นจำนวนเฉพาะคู่ (twin primes) อยู่ติดกัน หรือถึงกับอ้าปากค้างเมื่อจำนวนเฉพาะพาลินโดรม (palindromic prime) ที่หายากยิ่งกว่ายากโผล่มาให้เห็น

ถ้าอยากรู้รายละเอียดเพิ่มเติมเกี่ยวกับของเล่นชิ้นนี้ ลองไปดูได้ มีไฟล์ readme อธิบายครบถ้วนเลย
ฮาร์ดแวร์
ฮาร์ดแวร์หลักคือ Arduino Uno กับจอ TFT ขนาด 2.8 นิ้วที่เป็น Shield สำหรับใครที่ยังไม่รู้ Arduino Shield คือบอร์ดเสริมที่ออกแบบมาให้เสียบลงบนบอร์ด Arduino หลักได้เลยโดยไม่ต้องเดินสายเพิ่ม (ส่วน Module นั้นคือชิ้นส่วนที่ต้องต่อเข้ากับ Arduino ด้วยสายบางประเภท)
จอสีทัชสกรีนจิ๋วที่ปลดปล่อยจินตนาการพี่!
พี่ยอมรับเลยว่าพี่อาจจะตื่นเต้นกับเจ้าเจ๋งนี้เกินไปหน่อย แต่พี่ก็ยังทึ่งไม่หายที่ในราคาที่ค่อนข้างจับต้องได้ พี่สามารถซื้อจอสีทัชสกรีนจิ๋วๆ ที่คมชัด สว่างไสว มาโปรแกรมให้มันทำอะไรก็ได้!
ตอนแรกพี่คิดว่าจอ TFT มันเวอร์เกินไปสำหรับสิ่งที่พี่อยากทำ พี่มองหาแถวจอแสดงผลเจ็ดส่วน (seven segment display) ธรรมดาๆ มากกว่า ด้วยความคิดที่ว่ามันจะได้ดูคล้ายนาฬิกานับถอยหลังในหนัง แต่จะนับขึ้นและแสดงจำนวนเฉพาะแทน แล้วพี่ก็พบว่าจอเจ็ดส่วนพวกนั้นราคาไม่แพงไปกว่าจอทัชสกรีน TFT ที่โฆษณาอยู่เลยสักนิด สิ่งที่ตัดสินใจสุดท้ายคือความที่เจ้านี่เป็น Shield ที่แค่เสียบลง Arduino ก็ใช้ได้เลย ตอนนั้นพี่ก็เลยคลิก "ซื้อ" ไปอย่างไม่คิดหน้าคิดหลัง นั่นเป็นการตัดสินใจที่ชะตากรรมชักนำจริงๆ

ความที่ตอนนี้พี่มีจอราสเตอร์สีจิ๋วพร้อมหน้าจอสัมผัส (TOUCH) มันปลดปล่อยความคิดสร้างสรรค์พี่ได้จริงๆ ความเป็นมิตรต่อผู้ใช้ของ Arduino UNO กับ Arduino IDE ทำให้ทุกอย่างต่างกันมาก – พี่สามารถสร้างต้นแบบไอเดียได้เร็ว ลองดูว่ามันเป็นยังไงบนฮาร์ดแวร์จริงๆ หน้าจอสัมผัสตอบสนองยังไง และอื่นๆ ได้ทันที
โปรเจค Arduino แบบจัดเต็มเลยนะตัวนี้
ตอนเริ่มต้นทำพี่ก็คิดว่าโปรเจคนี้มันเป็น Arduino แบบครึ่งๆ กลางๆ อยู่ เพราะมันเล่นกับวัตถุทางคณิตศาสตร์ (เซตของจำนวนเฉพาะ) และไม่ตอบสนองต่อโลกภายนอกเลย ส่วนใหญ่โปรเจค Arduino มันต้องมีเซนเซอร์ มีมอเตอร์ – จุดสนุกหลักคือการโต้ตอบกัน โดยที่ Arduino ทำหน้าที่เป็นสมองที่ตอบสนองต่อสิ่งรอบตัว จริงๆ ถ้าพี่เลือกใช้แผงแสดงผล 7-Segment ไปเลย มันก็จะเป็นแบบนั้นแหละ: Arduino คำนวณอะไรบางอย่างอยู่ข้างในโดยไม่สนใจโลกภายนอกเลย แต่จอทัชสกรีนนี่แหละที่ช่วยพี่ไว้ ด้วยจอทัชสกรีน พี่ได้เซนเซอร์มา และก็เจอความท้าทายในการจัดการกับความแปลกประหลาดของอินพุตจากเซนเซอร์ ตอนนี้ของเล่นนี้ก็ตอบสนองต่ออินพุตจากผู้ใช้แล้ว (แม้จะจำกัด) เพราะฉะนั้นมันคือโปรเจค Arduino แบบ REAL ตัวจริงเสียงจริงแล้ว
ซอฟต์แวร์
IDE
การเขียนโปรแกรมให้ Arduino นี่สนุกดีนะ เพราะ IDE มันเรียบง่ายแต่ใช้งานได้ดี แต่น่าเสียดายที่การตั้งชื่อมันแปลกๆ หน่อย โปรแกรมหลักเรียกว่า "sketch" นามสกุลไฟล์เป็น .ino และเราคอมไพล์มันโดยการกดปุ่ม "verify" (ไอคอนเครื่องหมายถูก) บน IDE ไฟล์ .ino ก็แค่ไฟล์ข้อความธรรมดาที่เป็นโค้ด C++ ตรงๆ และมีฟังก์ชันเข้า 2 ตัว – setup กับ loop – แทนที่จะเป็น main โค้ดทั้งหมด – ทั้งไฟล์ .ino และไฟล์เฮดเดอร์กับซอร์ส C++ อื่นๆ ที่เราเขียน – ควรอยู่ในโฟลเดอร์เดียวกันที่ตั้งชื่อตามชื่อแอปพลิเคชัน
คอมไพเลอร์ยังสามารถเรียกใช้งานจาก command line ได้ด้วย ซึ่งโดยหลักการแล้วมันดีมากเพราะทำให้พี่ใช้ IDE ของตัวเองในการแก้ไขโค้ดได้ แต่ว่าคอมไพเลอร์โหลดแอปพลิเคชัน IDE ทั้งตัวทุกครั้ง ทำให้การเริ่มต้นทำงานช้ามาก พี่เลยต้องปล่อยให้ Arduino IDE เปิดค้างไว้แค่เพื่อกดปุ่ม "upload" หรือ "verify" แม้ว่าโค้ดในหน้าต่าง Arduino IDE จะไม่อัปเดตเมื่อพี่เซฟเวอร์ชันใหม่จาก IDE ของตัวเอง แต่การคอมไพล์จะใช้โค้ดล่าสุดจากดิสก์ พี่แค่ต้องระวังไม่เซฟจาก Arduino IDE แล้วไปเขียนทับการเปลี่ยนแปลงจาก IDE "ตัวจริง" ของพี่
แต่อย่าเข้าใจผิดนะ: Arduino IDE เป็นเครื่องมือที่ยอดเยี่ยม และสำหรับคนที่ไม่ได้เขียน C/C++ นอกเหนือจากการโปรแกรม Arduino มันคือโซลูชันแบบครบวงจรที่เจ๋งมาก
มีประโยชน์มากที่คอมไพเลอร์จะบอกคุณว่าใช้หน่วยความจำโปรแกรมไปเท่าไหร่ และตัวแปร global ใช้หน่วยความจำไดนามิกไปเท่าไหร่ และเหลือเท่าไหร่สำหรับตัวแปร local สำหรับ UNO นี่คือ 2 kB และพี่คิดว่ามันเป็นความท้าทายที่น่าพอใจที่จะทำให้ทุกอย่างพอดีกับพื้นที่ที่มี สำหรับแอปพลิเคชันง่ายๆ ของพี่ ไม่มีปัญหากับทรัพยากรการคำนวณเลย (เอ่อ... มีสิ ดูหัวข้อถัดไปเลย)
ทรัพยากรจำกัด ไม่มีเตือน OOM มีแต่บั๊กแปลกๆ
หนึ่งในความท้าทายของการโปรแกรมไมโครคอนโทรลเลอร์คือทรัพยากรบนบอร์ดที่มักจะจำกัด แต่ว่า "จำกัด" เป็นคำที่สัมพัทธ์นะ พี่เขียน C++ แบบดั้งเดิมเหมือนที่เขียนสำหรับเครื่องเดสก์ท็อป และเกือบจะรอดมาได้แล้ว พี่โปรแกรมจอสองจอลงในอุปกรณ์ แต่ละจอมีวิดเจ็ตสองสามตัวที่แสดงข้อมูลในแง่มุมที่ต่างกัน พี่ทำแบบนี้โดยไม่มีโค้ดแอสเซมบลีแม้แต่บรรทัดเดียว หรือเทคนิคประหยัดหน่วยความจำ/การคำนวณแปลกๆ และพี่ก็คิดว่า โห 2KB นี่มันเยอะมากเลยนะ!
แล้วมันก็เกิดขึ้น พี่ใช้หน่วยความจำหมด แต่พี่ไม่รู้ตัวว่าหมด สิ่งที่เกิดขึ้นคือ: พี่กำลังทำหน้าจอสถิติอยู่ นี่เป็นเวอร์ชันเก่า

และพี่มีฮิสโตแกรมสองอัน อันหนึ่งสำหรับความถี่ของตัวเลขแรก และอีกอันสำหรับความถี่ของตัวเลขสุดท้าย พี่ทิ้งไอเดียนี้ไปในที่สุด เพราะหลังจากทำโปรโตไทป์แล้วพี่ก็รู้สึกว่ามันน่าเบื่อสุดๆ ถึงแม้ว่าฮิสโตแกรมเองจะดูเรียบร้อยและสวยงามก็ตาม พี่เขียนคลาสสำหรับฮิสโตแกรมขึ้นมา แล้วทดสอบด้วยแค่หนึ่งอัน ทุกอย่างดูปกติดี
พี่เลยเพิ่มฮิสโตแกรมอันที่สองลงในจอแสดงผล มันก็แค่สร้างอินสแตนซ์ใหม่ของคลาสเดิมที่ใช้งานได้อยู่แล้ว มันทำงานได้ดีนะ แต่ตอนนี้ อย่างประหลาด ตัวนับ "Palindromic primes" เริ่มแสดงค่าเหมือนกับตัวนับ "Primes" บางครั้งมันก็แสดงค่าเดียวกัน บางครั้งก็บวกเพิ่มเข้าไปนิดหน่อย เป็นต้น ความคิดแรกของพี่คือพี่ทำอะไรที่ไม่ปลอดภัยไว้สักที่ แล้วทำให้พอยน์เตอร์หลุด และการเปลี่ยนแปลงล่าสุดนี่แหละที่ทำให้มันแสดงอาการออกมา
แต่! พี่ก็ระวังเรื่องจุดอันตรายใน C++ มาดีแล้วนะ คือพี่หนีมันไปไกลเลย แต่มันก็ไม่แน่เสมอไปแหละ
เพื่อตามหาบั๊ก พี่ก็ลองคอมเมนต์บรรทัดที่สร้างฮิสโตแกรมใหม่ดู แล้วดูซิว่าบั๊กหายไปมั้ย แล้วพี่ก็คิดได้ บางทีพี่อาจจะใช้หน่วยความจำจนหมดแล้วก็ได้
ฮิสโตแกรมเวอร์ชันแรกนี่มันกินเมมโมรีหน่อยนึงนะ – มันจองอาร์เรย์ขนาด 9 ไบต์สำหรับแต่ละอัน อย่าหัวเราะ! เรามีแค่ 2kB นะเว้ย มันหมดเร็วชะมัด สุดท้ายพี่ก็เขียนฮิสโตแกรมใหม่ให้ไม่ต้องใช้เมมโมรีส่วนนั้น ปัญหาก็หายไป
นี่แหละอาการของ OOM (Out Of Memory) บนไมโครคอนโทรลเลอร์แบบนี้ มันไม่มีระบบเซฟตี้หรอกนะ ไม่มีใครมาบอกหรอกว่า "เฮ้ย เมมหมดแล้วว่ะ" ตัวอัลโลเคเตอร์ (allocator) มันจะชี้ให้ไปยังช่องเมมโมรีที่ถูกใช้ไปแล้ว แล้วก็... ขอให้โชคดีละกัน!
Arduino.h
มีเรื่องนึงที่ค่อนข้างซ่อนเร้นและทำพี่งงอยู่พักนึง คือถึงแม้น้องจะไม่ได้ include มันในสเก็ตช์หลัก (main sketch) เลย แต่เฮดเดอร์ "Arduino.h" นี่ถูกเพิ่มเข้าไปให้อัตโนมัติตอนคอมไพล์ ซึ่งมันก็พาไลบรารีของ Arduino มาด้วยเพียบ โดยเฉพาะ math.h และ String ปกติก็ดีแหละ แต่พี่แยกโค้ดออกเป็นไฟล์ .cpp กับ .h แยกกัน แล้วก็ไปเจอข้อผิดพลาดตอนคอมไพล์ที่อ่านแล้วงงมาก คอมไพเลอร์บอกว่าไม่รู้จัก uint32_t ทั้งๆ ที่พี่เพิ่งใช้มันในอีกเฮดเดอร์นึงไม่นานนี้ สรุปแล้วคือพี่ include เฮดเดอร์ไฟล์นี้ในสเก็ตช์หลัก มันเลยได้ Arduino.h มาจากสเก็ตช์หลัก ในขณะที่อีกไฟล์นึงเป็นส่วนของหน่วยคอมไพล์แยกกัน... เรื่องมันยาว เอาเป็นว่ามันงงไปหมด
หมายเหตุเล็กน้อยเกี่ยวกับ ELEGOO 2.8 TFT
จอ ELEGOO 2.8 TFT นี่ภาพชัด สว่างดี และทางผู้ผลิตก็ให้โค้ดตัวอย่างมาเพียบ เป็นจอสี และโค้ดที่ให้มาก็สามารถพิมพ์ข้อความ วาดกราฟิกส์ หมุนจอได้ แต่มีจุดที่พี่ติดขัดอยู่ 2 จุดคือ:
- ในไฟล์
Elegoo_TFTLCD.hมันจะบอกให้เรา uncomment หรือ comment บรรทัดนึง ขึ้นอยู่กับว่าเราใช้บอร์ดแบบ Shield หรือ Breakout แต่ในกรณีพี่ แม้จะใช้ Shield ก็ต้องปล่อยให้บรรทัดนั้นถูก comment ไว้ ตัวอย่างถึงจะทำงาน - ตอนพี่ติดตั้งไลบรารีของ Elegoo ตัวอย่างขั้นสูงที่โผล่มาในเมนู Arduino IDE มันไม่ทำงาน แต่ถ้าพี่เข้าไปในโฟลเดอร์ที่แตกไฟล์ออกมาแล้ว แล้วเลือกตัวอย่างจากโฟลเดอร์ที่อยู่ระดับบนขึ้นไปหน่อย (one level up) มันกลับทำงานปกติ! พี่เดาว่า Elegoo น่าจะทำพลาดไปหน่อย คือส่งโค้ดตัวอย่างที่ล้าสมัยไปในโฟลเดอร์ไลบรารี (ซึ่ง Arduino IDE ติดตั้งให้อัตโนมัติ) แต่ไปอัพเดทโค้ดตัวอย่างไว้ในโฟลเดอร์ระดับบนแทน (ซึ่ง IDE ไม่ได้ติดตั้งให้)
- ตอนปรับโค้ด พี่สังเกตว่าฟังก์ชัน
tft.readID()มันไม่ทำงาน และในโค้ดตัวอย่างก็ฮาร์ดโค้ด ID เป็น 0x9341 สำหรับชิป ILI9341 อยู่แล้ว พี่ก็เลยทำแบบนั้นไปเลย
อีกเรื่องนึงที่พี่ไม่แน่ใจคือความสัมพันธ์ระหว่างจอ AdaFruit 2.8″ TFT กับจอตัวนี้ มันดูเหมือนโคลน และโค้ดก็ดูเหมือนดัดแปลงมาจากไลบรารีดั้งเดิมของ Adafruit ในราคา $12 จาก Amazon มันดีมากเลยนะ แต่พี่ก็แอบกังวลนิดหน่อยว่า Elegoo จะขโมยทรัพย์สินทางปัญญา (IP) ของ Adafruit มาเปล่า
uint32_t
เฮ้ย น้อง! พี่เคยคิดหนักเลยว่าจะใช้ uint32_t (ซึ่งพาเราไปถึงหลักพันล้าน) หรือ uint32_t (ซึ่งพาเราไปถึงหลักล้านล้านล้าน) ดี ผลทดลองคร่าวๆ บนฮาร์ดแวร์ที่พี่ใช้ (Uno + จอ TFT) มันทดสอบได้ 250 ตัวเลขใน 9 วินาที (หรือประมาณ 1600 ตัวเลขต่อนาที) นี่คือตอนทดสอบตัวเลขต่ำกว่าหนึ่งล้านนะเว้ย พี่ว่ามันต้องช้าลงอีกเยอะถ้าเราไปถึงตัวเลขที่ใหญ่ขึ้น
ถ้าคิดแบบตาตี่ๆ การหาจำนวนเฉพาะสี่พันล้านตัวด้วยวิธีไล่ทีละตัวคงใช้เวลามากกว่า 5 ปี ส่วนสิบแปดล้านล้านล้านตัว... อืม คงใช้เวลานานกว่านั้นอีกนิดนึง555 พี่เคยช่วงหนึ่งที่คิดเพ้อเจ้อไปเลย ว่าเจ้าโมลิกนี้จะกลายเป็นของคัลท์ แล้วถูกฝังในแคปซูลเวลาพร้อมแบตเตอรี่วิเศษ รอให้ลูกหลานมนุษย์ในอนาคตขุดขึ้นมา แล้วมันยังทำงานติ้กต็อกอยู่ได้เลย! แต่สุดท้ายพี่ก็ตัดสินใจใช้ uint32_t ไปละ ถ้าน้องอยากลองของ อยากลุยไปถึงหลักล้านล้านล้าน ก็แค่ไปเอา comment ออกจากบรรทัดที่เกี่ยวข้องในไฟล์ prime.h ได้เลยจ้า ไว้ลองเล่นๆ
ตัว Arduino นี่ใช้โปรเซสเซอร์ 8 บิตนะตัวนี้ เพราะฉะนั้นทุกการดำเนินการกับตัวเลข 4 ไบต์ มันต้องใช้ 4 รอบสัญญาณนาฬิกา Arduino ของเราวิ่งที่ 16 MHz เอาเป็นว่า... อย่าเพิ่งเอาไปแข่งหา "จำนวนเฉพาะที่ใหญ่ที่สุด" ละกันน้อง 555
ตรรกะคณิตศาสตร์เพื่อการศึกษา
โมลิก (মৌลিক) คือของเล่นเพื่อการศึกษาที่ออกแบบมาให้สอนเรื่อง จำนวนเฉพาะ ผ่านการตอบสนองทางฮาร์ดแวร์แบบจับต้องได้
- ตรรกะการกรองของเอราทอสเทนีส: Arduino จะแสดงตัวเลขสุ่ม (0-100) บน จอแสดงผล 12 ส่วน ขนาดใหญ่ ส่วนเฟิร์มแวร์ด้านในจะรันอัลกอริทึมทดสอบความเป็นจำนวนเฉพาะ เพื่อตรวจสอบว่าตัวเลขนั้นมีตัวหารแค่สองตัวหรือเปล่า
- เมทริกซ์ตรวจสอบแบบอินเทอร์แอคทีฟ: ผู้ใช้ต้องกดปุ่ม "Prime" หรือ "Composite" Arduino จะตรวจสอบคำตอบ แล้วให้สัญญาณตอบกลับเป็นเสียง "สำเร็จ" ที่ให้กำลังใจ หรือเสียง "ลองใหม่" แบบบัซเซอร์
การออกแบบ
- สไตล์อุตสาหกรรมแบบถือได้: มาพร้อมปุ่มอาร์เคดขนาดใหญ่กดสนุก และไฟ LED คอนทราสต์สูง ทำให้แนวคิดนามธรรมอย่างจำนวนเฉพาะ กลายเป็นเรื่องจับต้องได้และน่าจดจำสำหรับน้องๆ วัยเรียน สู้งานนะน้อง!