<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Tarit Witworrasakul on Medium]]></title>
        <description><![CDATA[Stories by Tarit Witworrasakul on Medium]]></description>
        <link>https://medium.com/@wtarit?source=rss-4df800a7a724------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*DBNNBVKljENU81iKocrm2g.jpeg</url>
            <title>Stories by Tarit Witworrasakul on Medium</title>
            <link>https://medium.com/@wtarit?source=rss-4df800a7a724------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 07 Jun 2026 15:45:04 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@wtarit/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[สร้าง Model แปลภาษาไทย — อังกฤษ]]></title>
            <link>https://wtarit.medium.com/%E0%B8%AA%E0%B8%A3%E0%B9%89%E0%B8%B2%E0%B8%87-model-%E0%B9%81%E0%B8%9B%E0%B8%A5%E0%B8%A0%E0%B8%B2%E0%B8%A9%E0%B8%B2%E0%B9%84%E0%B8%97%E0%B8%A2-%E0%B8%AD%E0%B8%B1%E0%B8%87%E0%B8%81%E0%B8%A4%E0%B8%A9-e23cb9585f5?source=rss-4df800a7a724------2</link>
            <guid isPermaLink="false">https://medium.com/p/e23cb9585f5</guid>
            <category><![CDATA[naturallanguageprocessing]]></category>
            <category><![CDATA[thai-nlp]]></category>
            <category><![CDATA[machine-translation]]></category>
            <category><![CDATA[language-model]]></category>
            <dc:creator><![CDATA[Tarit Witworrasakul]]></dc:creator>
            <pubDate>Sat, 10 Jun 2023 11:46:20 GMT</pubDate>
            <atom:updated>2023-06-14T15:50:28.353Z</atom:updated>
            <content:encoded><![CDATA[<h3>สร้าง Model แปลภาษาไทย — อังกฤษ</h3><p>Idea ในการทำ Project นี้มาจากที่เห็นคนเริ่มใช้ ChatGPT ในการแปลภาษา รวมถึงใช้ในการแก้ประโยคต่าง ๆ ซึ่งมักจะได้การแปลที่มีคุณภาพกว่า Google Translate ดังนั้นเลยอยากลองพัฒนา Model แปลภาษาขึ้นมา และการมี Model ที่ Opensource ก็จะทำให้คนอื่นสามารถนำไปใช้งานและพัฒนาต่อยอดไปใน Application อื่น ๆ ได้</p><p>ซึ่ง model แปลภาษา th-en ตอนนี้ที่เป็น opensource ที่ดีที่สุดคือ <a href="https://airesearch.in.th/releases/machine-translation-models/">SCB_1M-MT_OPUS+TBASE</a> จาก airesearch ซึ่งได้ BLEU score บน IWSLT 2015 อยู่ที่ 28.3</p><p>ดังนั้นเป้าหมายของผมก็คือทำ model ที่ดีกว่าตัวที่ opensource อยู่ปัจจุบัน (ยังไม่หวังชนะพวก API เสียเงิน พวกนั้นเขามีเงินจ้างทีมวิจัย+ซื้อการ์ดจอแรง ๆ อาจจะเป็นเป้าหมายที่สูงไปหน่อย) พอมาพิจารณาความเป็นไปได้ก็คิดว่าด้วย Pretrained Model ในปัจจุบัน ถ้าเอามา finetune ก็น่าจะทำ BLEU score ที่ดีกว่า Model opensource เดิมได้</p><h3>Metrics</h3><p>จาก Intro ด้านบนก็น่าจะเห็นกันไปแล้วว่า Model แปลภาษาจะถูกวัดความสามารถโดยใช้ BLEU score (Bilingual Evaluation Understudy) ซึ่งเป็นการคำนวนว่าการแปลของ Model นั้นใกล้เคียงกับประโยคที่ถูกต้องมากแค่ไหน โดยเทียบคำที่เหมือนกันที่ n-gram = 1–4 และนำมาเฉลี่ยกัน</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/930/1*zazvoeBwJ0Iz9WMdcFGH4w.png" /></figure><p>โดยสูตรนี้จะต่างจาก Precision ปกติตรง Clip(Num n-grams matches) โดยจำนวนคำที่ match จะต้องไม่เกินจำนวนคำที่อยู่ใน Reference</p><blockquote><em>ตัวอย่างเช่น<br>Reference: </em>I drive a car<em><br>model predict ออกมาว่า: </em>car car car car<br><em>ถ้าใช้สูตร precision ปกติจะได้</em> = 4/4 = 1 <em>หรือว่าถูกทั้งหมด<br>แต่ถ้าคำนวนตาม BLEU score จะได้ </em>1/4<em> เพราะ Reference มีคำว่า car แค่คำเดียว</em></blockquote><h3>Data Preparation</h3><p>ตัว Dataset Machine Translation ภาษาไทย-อังกฤษมีหลัก ๆ อยู่ 2 ตัวก็คือ <a href="https://airesearch.in.th/releases/machine-translation-datasets/">scb-mt-en-th-2020</a> และ <a href="https://opus.nlpl.eu/">OPUS</a> ซึ่งตัว OPUS เป็น Dataset ที่มีอยู่เกือบทุกภาษา! โดยเราจะไปโหลดจากเว็บ OPUS โดยตรงก็ได้ หรือว่าถ้าอยากได้แบบง่าย ๆ ก็โหลดจาก <a href="https://github.com/vistec-AI/thai2nmt/releases/tag/scb-mt-en-th-2020%2Bmt-opus_v1.0">Vistec</a> ที่ปล่อยไว้เป็น CSV ให้เรียบร้อย</p><p>ก่อนจะเอา Data ไป Train model เราก็ต้อง Clean Data ซะก่อน โดยเฉพาะกับภาษาไทยที่บางครั้งอาจจะเห็นว่าเขียนเหมือนกัน แต่จริง ๆ แล้วเป็นตัวอักษรคนละตัว แต่เวลาเอาไป tokenize และแปลงเป็น input_ids จะออกมาเป็นคนละตัวกัน</p><p>ใช้ขั้นตอนดังนี้ (Code, Based on <a href="https://github.com/vistec-AI/thai2nmt/blob/master/scripts/clean_text.py">thai2nmt</a>)</p><ol><li>ตัด Whitespace หน้า/หลังประโยค</li><li>HTML unescape แปลง HTML Entities กลับมาเป็น Charactor ปกติ (ex: &amp;quot; —&gt; “)</li><li>Normalize Unicode เนื่องจากตัวอักษรที่เป็น Unicode อาจมีหลายรูปแบบแต่หมายถึงตัวอักษร / สัญลักษณ์ตัวเดียวกัน (ex: ℌ, H) เลยต้อง Normalize มาให้เป็นตัวเดียวกัน</li><li>Normalize Thai Text Ex. สระ แ- สามารถพิมพ์ได้ด้วย สระแอ ตัวเดียว หรือ สระเอ 2 ตัว (เ เ -) หรือ คำว่า น้ำ ที่เขียนได้ทั้ง น้ำ (น, ้ , ำ) , นำ้ (น, ำ, ้) หรือ นํ้า (น, ํ , ้ , า)</li></ol><p>หลังจาก Clean Text แล้วก็จะมีบางคู่ประโยคที่ต้องตัดออก โดย</p><ol><li>คู่ประโยคที่มี String เปล่า (“”)</li><li>คู่ประโยคที่ภาษาไทยไม่มีตัวอักษรภาษาไทย (มีแต่ตัวอักษรภาษาอังกฤษ) อันนี้พบว่าบางคู่ประโยค โดยเฉพาะ opus-kde4 จะมี Text ที่เป็นภาษาอังกฤษทั้งคู่แต่เขียนไม่เหมือนกันอยู่</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IweofpNaUOT-Uos8Jnetwg.png" /><figcaption>Text เป็นอังกฤษทั้งคู่ แต่เขียนไม่เหมือนกัน</figcaption></figure><p>3. Text ที่มี Unicode Control codes บางตัว จะเป็นตัวอักษรที่อ่านไม่ออก (ส่วนมากเจอใน opus-opensubtitles)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/949/1*ZFbXS2dgBcMfypDTfM-sgw.png" /><figcaption>Text ภาษาไทยอ่านไม่ออก</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/513/1*iSYYA_eleOg-lYf2FbMugw.png" /><figcaption>บางคู่ประโยคมีมี Text แค่ภาษาเดียว</figcaption></figure><h3>Exploratory Data Analysis</h3><p>เนื่องจากว่าตอน Train Model Machine Translation เราจะต้องกำหนด Sequence Length หรือความยาวของประโยคที่จะเอาเข้าไป Train ซึ่งในแต่ละ Batch ทุกประโยคจะต้องมีความยาวเท่ากัน</p><p>ดังนั้นเราจะมาดู Distribution ของความยาวประโยคเมื่อ tokenize ออกมาแล้วกัน เพื่อดูว่าส่วนใหญ่ประโยคยาวเท่าไร</p><p>Note: ข้อมูลตรงนี้มาจากการใช้ NLLB Tokenizer ตัดประโยคนะครับ</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_ZaOIMLR7uyjz8W0r5QBIA.png" /><figcaption>Distribution ของความยาวประโยคในแต่ละ File</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/591/1*0S4S1yaNXSjRejRAcKRDeg.png" /><figcaption>Distribution ของความยาวประโยคทั้งหมด (SCB+OPUS)</figcaption></figure><p>ซึ่งก็จะเห็นว่าประโยคส่วนมากจะยาวไม่เกิน 50 Tokens ดังนั้นผมเลยตั้ง Sequence Length ให้ไม่เกิน 64</p><h3>Model</h3><p>สำหรับ Tools ที่ใช้ Train Model ที่เป็น architecture Transformer ก็คงหนีไม่พ้น Huggingface transformers ซึ่งถ้าใครอยากลอง Reproduce ผลการทดลองนี้ก็ดู Code ทั้งหมดได้บน <a href="https://github.com/wtarit/th-en-machine-translation">https://github.com/wtarit/th-en-machine-translation</a></p><h4>mT5</h4><p>Model ตัวแรกที่ลองคือ mT5 จาก Google ซึ่งใน Dataset มาการใช้ภาษาไทย Train อยู่ 1.14% (อาจจะดูน้อย แต่ mT5 นั้น train จาก dataset 107 ภาษา) ซึ่ง Google ก็ได้ <a href="https://github.com/google-research/multilingual-t5#released-model-checkpoints">Release mT5 ออกมา 5 ขนาด</a>ได้แก่ mT5-Small (300M parameters), mT5-Base (580M parameters), mT5-Large (1.2B parameters), mT5-XL (3.7B parameters), mT5-XXL (13B parameters) เลยลองนำ mT5-Small มา finetune บน dataset SCB ดู</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8Rvqfsn2HY6ePA_scB1FLA.jpeg" /><figcaption>Distribution ของภาษาที่ใช้ Pretrain mT5 (<a href="https://arxiv.org/pdf/2010.11934.pdf">https://arxiv.org/pdf/2010.11934.pdf</a>)</figcaption></figure><p>โดยก่อนจะ finetune นั้นผมจะ Tokenize dataset แล้ว Save เก็บไว้เพื่อต้องมา Run ซ้ำหรือ Train ไปแล้วเกิด Error ต้อง Train ใหม่จะได้ไม่ต้องเสียเวลา Tokenize data ใหม่</p><p>หลังจากเริ่ม Train ก็มีปัญหาเกิดขึ้นทันที นั้นก็คือ loss เป็น 0.0</p><pre>{&#39;loss&#39;: 0.0, &#39;learning_rate&#39;: 4.973326944577544e-05, &#39;epoch&#39;: 0.04}</pre><p>ซึ่งเอาไป search ดูก็พบว่าเป็นเพราะใช้ fp16 train ซึ่งมีปัญหาที่ Implementation ของ mT5 ใน Huggingface (<a href="https://discuss.huggingface.co/t/t5-fp16-issue-is-fixed/3139">ที่ Huggingface บอกว่าแก้แล้วแต่เห็นหลาย ๆ คนรวมถึงผมก็ยังเป็นอยู่</a>) วิธีแก้ก็คือไปใช้ bf16 ที่มี range ของตัวเลขกว้างกว่า (แต่จะใช้ได้เฉพาะบน GPU Nvidia ที่เป็น Ampere หรือใหม่กว่า) หรือใช้ fp32 ปกติ</p><p>พอเปลี่ยนไปใช้ bf16 แทนแล้วก็ finetune ไปได้ 5 epochs ก็พบว่า BLEU score นั้นต่ำกว่าที่คิด ใน Validation Set อยู่ที่ 13.15 และพอเอาไปลองกับ Test set อยู่ที่ 12.14 ซึ่งตรงนี้ดูจาก Training และ Evaluation Loss แล้วก็คิดว่าถ้า Train ต่อ Model ก็น่าจะดีขึ้นอีก</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LqaumnRuC7NzAfBAH2pGSQ.png" /><figcaption>Training และ Evaluation Loss ช่วง epochs 1–5</figcaption></figure><h4>No Language Left Behind (NLLB)</h4><p>เนื่องจาก mT5 ออกมาตั้งแต่ปี 2020 ในโลกของวงการ NLP ปัจจุบันที่อะไรออกมาได้อาทิตย์เดียวก็ถือว่าเก่าแล้ว ผมเลยคิดว่ามันน่าจะต้องมี Pretrained Model อะไรที่ดีกว่านี้สิ เลยมาเจอ NLLB จาก Meta ที่ออกมาเมื่อปี 2022 เป็น Model สำหรับแปลภาษาโดยเฉพาะที่แปลได้ถึง 200 ภาษารวมถึงภาษาไทยด้วย! ลองใช้ Model ตัวเล็กสุด (<a href="https://huggingface.co/facebook/nllb-200-distilled-600M">600M Parameter</a>) ก็พบว่าได้ BLEU score ถึง 24.03 โดยไม่ต้องทำอะไรเลย ก็เลยคิดว่านี่น่าจะเป็นจุดเริ่มต้นที่ดีกว่า mT5 ในการเอาไป finetune</p><p>การ finetune ก็เหมือนกับ mT5 เลยคือ Tokenize dataset เก็บไว้ก่อนแล้วเอาไป Train โดยตอนแรกใช้แค่ SCB dataset ก็พบว่า BLEU score กลับลดลงเหลือ 21.7</p><p>ซึ่งจากที่คุยกับ mentor ก็คิดว่าเป็นเพราะ SCB dataset มีข้อมูลที่เป็นภาษาพูด/บทสนทนาอยู่น้อยที่ 300,280 ประโยค หรือประมาณ 30% ของ Dataset ทั้งหมด (Taskmaster-1, NUS SMS, Mozilla Common Voice) พอทดสอบกับ iwslt_2015 ที่เป็นภาษาพูด Model เลยทำงานได้ไม่ดี</p><p>ก็เลยลองเพิ่ม dataset เป็น scb+opus พอ Train ไปได้ 3 epochs BLEU score ดีขึ้นเป็น 27.37 ดูแล้วมาถูกทาง และดูจาก Training/Evaluation Loss ก็คิดว่า Train ต่อได้อีก</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*eaaKGVBMjSxdWmwTuXUbXQ.png" /><figcaption>NLLB Training/Evaluation Loss</figcaption></figure><p>แต่ปัญหาคือมัน Train นานมาก ๆๆ ทั้งหมดนี่ใช้เวลาไป 78 ชม. (Train บน RTX3080 16GB Laptop)</p><h4>LoRA</h4><p>จากที่เห็นคน finetune LLaMA และ LLM อื่น ๆ ด้วย LoRA แล้วเลยคิดว่าน่าจะเอามาลองใช้ดู</p><p>วิธีการของทำงาน LoRA นั้นจะ freeze weight ทั้งหมดของ model และ inject parameter ใหม่เข้าไปใน Transformer layer และ Update แค่ Parameter นั้น</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*2rr4CoGZ0pcCk8wH.png" /><figcaption>Credit: <a href="https://lightning.ai/pages/community/tutorial/lora-llm/">https://lightning.ai/pages/community/tutorial/lora-llm/</a></figcaption></figure><p>อีกเทคนิคหนึ่งคือการแยก Weight Matrix เป็น 2 ตัว ที่เมื่อคูณกันแล้วจะได้ <em>ΔW (ΔW = WA x WB) </em>เนื่องจากใน Paper นี้พบว่า Weight ของ Model นั้นมี Rank ต่ำ ทำให้ Decompose ออกมาเป็น Matrix ขนาดเล็กได้</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/902/1*ZSSxWB5gC_C2KZLM0AAEeQ.png" /><figcaption>Credit: <a href="https://youtu.be/dA-NhCtrrVE">https://youtu.be/dA-NhCtrrVE</a></figcaption></figure><p>ส่วนค่า r นั้นคือ hyperparameter ที่ต้องกำหนด โดยถ้า r มาก Trainable Parameter ก็จะมากขึ้น</p><p>และข้อดีของ LoRA อีกอย่างคือเราสามารถ Save แค่ Weight ที่ inject ได้เข้าไปและเอามารวมกับ Base Model ทีหลังได้ ทำให้ได้ Weight ที่มีขนาดเล็ก</p><p>โดย Library ที่ผมจะใช้ในการ finetune ด้วย LoRA ก็คือ Huggingface PEFT แต่มันไม่ support NLLB ดังนั้นเราจะต้องใส่ target_modules เอง (ส่วนที่จะ Train) ผมเลือก query projection, value projection (<a href="https://github.com/wtarit/th-en-machine-translation/blob/main/NLLB/train_nllb_lora.py">Training Code</a>)</p><pre>peft_config = LoraConfig(<br>    task_type=TaskType.SEQ_2_SEQ_LM,<br>    inference_mode=False,<br>    r=8,<br>    lora_alpha=32,<br>    lora_dropout=0.1,<br>    target_modules=[&quot;q_proj&quot;, &quot;v_proj&quot;],<br>)</pre><p>ส่วน rank=8 โดยอันนี้เลือกมาตาม paper ของ LoRA ที่เขาทดลองมาว่าการใช้ rank=64 ก็ไม่ได้ทำให้ accuracy ดีขึ้น</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/943/1*QwTnKrJ3urnmOJiJYytkow.png" /><figcaption><a href="https://arxiv.org/pdf/2106.09685.pdf">https://arxiv.org/pdf/2106.09685.pdf</a> Page 10</figcaption></figure><p>หลังจาก Train ไปได้ 9 epochs ได้ BLEU Score บน Validation Set อยู่ที่ 24 ซึ่งต่ำกว่า Model ที่ Train ทั้ง Model แค่ 3 epochs เลยตัดสินใจหยุด Train (ดู Training Logs ได้บน <a href="https://wandb.ai/wtarit/nllb-lora/runs/ba5u8b35">Weights &amp; Biases</a>)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*03TcJ1FI0sDPtvqDQbte5g.png" /><figcaption>NLLB-LoRA Training/Evaluation Loss, BLEU Score</figcaption></figure><p>พอเอาไปทดสอบบน Test Set ได้ BLEU Score อยู่ที่ 24.23 ซึ่งพบว่าแทบจะไม่ได้ดีขึ้นจาก Baseline เลย ซึ่งตรงนี้อาจจะต้องลองปรับ rank ดูว่าจะทำให้ model เรียนรู้ได้ดีขึ้นไหม</p><h3>Model Result</h3><p>ตัวอย่างประโยคจากการแปลด้วย NLLB-600M, NLLB-Finetuned (SCB+OPUS) และ Model จาก AIResearch</p><blockquote><em>Source: โยว่ และนี้คือเสียงจากเด็กวัด<br>NLLB-600M: Oh, and this is the voice of the nun.<br>NLLB-Finetuned: Yo, and this is the voice of the boy.<br>AIResearch: Yo, and this is the voice from the temple boy.</em></blockquote><blockquote><em>Source: วันเสาร์อาทิตย์นี้อยากไปเที่ยวไหน<br>NLLB-600M: Where do you want to go this Saturday?<br>NLLB-Finetuned: What holiday would you like to go to this weekend?<br>AIResearch: What weekend would you like to go?</em></blockquote><blockquote><em>Source: สวัสดีครับพี่เนม<br>NLLB-600M: Hey, what’s up, Ned?<br>NLLB-Finetuned: Hello, Nam.<br>AIResearch: Hello, Nem.</em></blockquote><blockquote><em>Source: เย็นนี้เราน่าจะออกไปกินข้าวข้างนอก<br>NLLB-600M: We should go out for dinner tonight.<br>NLLB-Finetuned: We should go out for dinner this evening.<br>AIResearch: We should go out for dinner this evening.</em></blockquote><blockquote><em>Source: ขอทราบนามสกุลคุณสมชายค่ะ<br>NLLB-600M: I’d like to know your last name, Mr. Prince.<br>NLLB-Finetuned: May I have your full name?<br>AIResearch: What’s your last name, Somchai?</em></blockquote><p>ซึ่งจากผลการแปล NLLB-Finetuned จะมีความใกล้เคียงกับ Model จาก AIResearch ซึ่งน่าจะเป็นเพราะใช้ Dataset เดียวกัน</p><h3>Deployment</h3><p>การ Deploy ผมเลือกใช้ Huggingface Space เพราะว่า Free (สำคัญสุด) และให้ Resource เยอะ โดยเฉพาะ Ram 16GB ทำให้ Deploy Model ใหญ่ ๆ ได้ ซึ่งถ้าใครอยากทดลองก็สามารถเข้าไปได้ที่ <a href="https://huggingface.co/spaces/wtarit/nllb-th-en-translation">https://huggingface.co/spaces/wtarit/nllb-th-en-translation</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*JffMYwTpnDeyqKoMir7Jsg.png" /><figcaption><a href="https://huggingface.co/spaces/wtarit/nllb-th-en-translation">https://huggingface.co/spaces/wtarit/nllb-th-en-translation</a></figcaption></figure><h3>Improvement</h3><p>วิธีการที่ผมคิดว่าจะสามารถทำให้ Model ทำงานได้ดีขึ้นได้ แต่ไม่ได้ลองด้วยเหตุผลทางด้านเวลา และเงิน</p><h4>เพิ่ม Dataset</h4><p>จากการปรึกษา Mentor มีไอเดียว่าใช้ ChatGPT มา Generate Data (แนว ๆ Alpaca ที่เอา Data จาก text-davinci มา train) ปัญหาคือพอคำนวณ cost แล้ว แพงมาก ลองคำนวณคร่าว ๆ 1 ล้านประโยค ใช้ประมาณ 300 USD (assume 1 ประโยคใช้ 150 tokens, gpt-3.5-turbo $0.002 / 1K tokens)</p><p>อีกไอเดียนึงคือใช้ Youtube Subtitles จากช่องที่มี Subtitles ทั้ง 2 ภาษา แต่พบปัญหาคือพอเอา Subtitles ไทย-อังกฤษมา align กันตามเวลาของคลิป มีบางอันที่ประโยคไทยกับอังกฤษตัดมาไม่ตรงกัน (เช่นไทยเขียนเป็นประโยคยาว อังกฤษตัดเป็น 2 ช่วง)</p><h4>คัด Data ที่คุณภาพต่ำออก</h4><p>สังเกตว่า Dataset ที่มาจากการ Web Scraping หลาย ๆ อันจะ Align มาไม่ตรงกันเช่น Data จาก Wikipedia ใน SCB</p><blockquote><em>EN: “FIFA 15” received positive reviews across all platforms, although the PC version in particular was criticized for the amount of bugs that were featured at release.<br>TH: </em><strong><em>และเป็นเกมแรกในซีรีส์”ฟีฟ่า” ที่ได้รับสิทธิอย่างเต็มที่ในพรีเมียร์ลีก</em></strong><em> “ฟีฟ่า 15” ได้รับคำวิจารณ์ในเชิงบวกในทุกระบบแพลตฟอร์ม แม้ว่าในเวอร์ชันพีซีจะได้รับการวิจารณ์ถึงอาการบั๊กที่เกิดขึ้นบ่อยครั้งในช่วงเปิดตัวอยู่ก็ตาม</em></blockquote><p>บางประโยคแปลผิด เช่น ข้อมูลที่มาจากการ Crowdsourcing (ตัวอย่างจาก SCB generated_reviews_crowd)</p><blockquote><em>EN: This was my book club’s choice for the spring 2012.<br>TH: นี่คือหนังสือเล่มโปรดของฉันในฤดูร้อนปี 2012</em></blockquote><p>ข้อมูลจาก NUS_SMS ที่ถึงเป็นภาษาอังกฤษแต่เป็นแบบ Singlish</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DlcwBHO6i8ZWPOxfOdQXjw.png" /><figcaption>NUS_SMS Sample</figcaption></figure><h4>Train Model ที่ให้ขึ้น</h4><ol><li>Train model ให้นานขึ้น</li><li>ลอง Train NLLB ตัวที่มี Parameter เพิ่มมากขึ้น</li></ol><h3>Conclusion</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9gvpRZL1GUfPrV5RqZUMgQ.png" /><figcaption>สรุปผลลัพธ์ Model ที่ได้ลอง Train ไป</figcaption></figure><p>ถึงแม้ว่า Project นี้จะยังไม่ได้ผลลัพธ์ตามเป้าหมายที่ตั้งใจไว้ แต่ก็ถือว่าใกล้เคียงมาก ๆ ส่วนที่ยังไม่ได้ Train ต่อนั้นเพราะอยากจะ Clean Data ให้ดีกว่านี้แล้วค่อย Train (ตามคติที่ว่า Garbage in — Garbage out) และการ Train แต่ละครั้งมันใช้เวลานาน</p><p>ในด้าน Tools ที่ใช้งานอาจจะสังเกตว่า Project นี้มีความเป็น Huggingface Ecosystem มาก ๆ แต่ว่ามันใช้ง่ายจริง ๆ แนะนำให้ลองสำหรับคนที่จะทำ NLP (แต่ปัจจุบัน Huggingface transformers ก็ Support Data แบบอื่น ๆ ด้วยนะ)</p><p>และสำหรับคนที่กำลังมองหา Model Machine Translation ไปใช้งานก็หวังว่า Model นี้จะเป็น Option หนึ่งให้พิจารณาครับ (แนะนำให้ลอง Evaluate ด้วยประโยคใน Domain ที่จะใช้งาน)</p><p>สุดท้ายก็ขอขอบคุณผู้จัดโครงการ AI Builders ที่จัดโครงการนี้ขึ้นมา และ Mentor, TA ที่ให้คำปรึกษาในการทำโครงงานครับ</p><h3>Reference</h3><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FM05L1DhFqcw%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DM05L1DhFqcw&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FM05L1DhFqcw%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/5616ed9a734a76d4d3faabb6008f2c8e/href">https://medium.com/media/5616ed9a734a76d4d3faabb6008f2c8e/href</a></iframe><ul><li><a href="https://arxiv.org/abs/2010.11934">mT5: A massively multilingual pre-trained text-to-text transformer</a></li><li><a href="https://arxiv.org/abs/2106.09685">LoRA: Low-Rank Adaptation of Large Language Models</a></li></ul><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FdA-NhCtrrVE%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DdA-NhCtrrVE&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FdA-NhCtrrVE%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/2f219bb3bdad7b964b2897dd07fe4316/href">https://medium.com/media/2f219bb3bdad7b964b2897dd07fe4316/href</a></iframe><p><a href="https://lightning.ai/pages/community/tutorial/lora-llm/">Parameter-Efficient LLM Finetuning With Low-Rank Adaptation (LoRA) - Lightning AI</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e23cb9585f5" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[รีวิวประสบการณ์สัมภาษณ์ ISE Chula (Portfolio Option)]]></title>
            <link>https://wtarit.medium.com/%E0%B8%A3%E0%B8%B5%E0%B8%A7%E0%B8%B4%E0%B8%A7%E0%B8%9B%E0%B8%A3%E0%B8%B0%E0%B8%AA%E0%B8%9A%E0%B8%81%E0%B8%B2%E0%B8%A3%E0%B8%93%E0%B9%8C%E0%B8%AA%E0%B8%B1%E0%B8%A1%E0%B8%A0%E0%B8%B2%E0%B8%A9%E0%B8%93%E0%B9%8C-ise-chula-portfolio-option-a3978e2fa210?source=rss-4df800a7a724------2</link>
            <guid isPermaLink="false">https://medium.com/p/a3978e2fa210</guid>
            <category><![CDATA[chulalongkorn-university]]></category>
            <dc:creator><![CDATA[Tarit Witworrasakul]]></dc:creator>
            <pubDate>Sat, 11 Mar 2023 11:37:39 GMT</pubDate>
            <atom:updated>2023-03-11T11:37:39.298Z</atom:updated>
            <content:encoded><![CDATA[<p>จากที่ผมได้ไปสัมภาษณ์ ISE จุฬาเมื่อวันที่ 13/1/2023 ที่ผ่านมา และเห็นใน internet ไม่ค่อยมีใครแชร์ประสบการณ์การเข้า ISE แบบ Portfolio เลย ซึ่งก็อาจจะเป็นเพราะว่า Option นี้รับน้อยและเหมือนเพิ่งจะมีมาไม่นาน แต่ส่วนตัวผมก็คิดว่าเป็น Option ที่ดีสำหรับคนที่มีผลงาน และขี้เกียจไปสอบพวก SAT แต่ยังไงก็ต้องยื่นคะแนนอังกฤษนะ (ผมยื่น IELTS) ก็เลยอยากเอามาเขียนไว้ให้น้อง ๆ รุ่นต่อ ๆ ไป</p><p>เริ่มจากที่ส่ง Portfolio จะเป็นการกรอกข้อมูลใน Website สมัคร (ไม่ต้องทำเป็นเล่ม) ข้อมูลที่ใส่ก็จะคล้าย ๆ วิศวะภาคไทย (ดูหัวข้อได้จากประกาศรับสมัคร —<a href="http://www.ise.eng.chula.ac.th/news/detail?id=1571&amp;gid=1-008-002-002)"> ปี 2023</a>)</p><p>พอก่อนประกาศผลประมาณ 2 วันก็มี Email เข้ามาว่าให้เข้า Line Openchat ซึ่งในใจเราก็คิดว่าคงแปลว่าเราผ่านเข้ารอบสัมภาษณ์แล้วแหละ ซึ่งเขาส่ง Email แบบ to หาทุกคน ทำให้เราเห็น Email Address ของทุกคน นับรวมได้ 47 คน</p><p>แต่ปรากฎว่า! วันที่ประกาศผลตามกำหนดการเราก็เข้าไปดูประกาศแล้วก็นับดูพบว่า มีคนได้สัมภาษณ์แค่ 36 คน ตามมาด้วย Chat นี้</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*SKLjMoYQXmF1YIrnL0pK-A.jpeg" /></figure><p>ซึ่งก็เลยสงสัยว่า แปลว่ามีคนส่ง Port ทั้งหมด 47 คนเหรอ? แล้วเขาจะเชิญเข้า Openchat ทั้งหมดทำไม เพื่อแค่บอกว่าถ้าจะสมัครรอบต่อไปไม่ต้องจ่ายค่าสมัคร? รู้สึกว่ามันดูทำร้ายจิตใจคนไม่ได้ยังไงไม่รู้ แต่สำหรับคนที่ได้อย่างเราก็ดี เพราะคู่แข่งลดลงไปตั้ง 11 คน</p><p>ซึ่งจุฬาก็จะใช้ Microsoft Team สัมภาษณ์ ซึ่งบอกเลยว่าวุ่นวายมาก เพราะเขาจะส่ง invite เข้า Team มาโดยใช้ Email ที่เราใช้สมัคร แล้วอย่างเราที่ใช้ Gmail ก็ต้องเอา Email นั้นไปสมัคร Microsoft Account เพื่อที่จะเข้าทีม</p><h4>วันสัมภาษณ์</h4><p>ผมสัมภาษณ์เป็นคิวแรกเลย ซัก 8.40น. ก็เปิด MS Teams มา Standby แล้วก็จะมี Chat จากเจ้าหน้าที่มาบอกให้เราพิมพ์รายงานตัว และกด Join Call เพื่อเข้าไปสัมภาษณ์ พอเข้าไปใน Call ก็จะมีอาจาย์ 2 คน (ผมเจอต่างชาติทั้งคู่) แล้วก็พี่นักศึกษา/เจ้าหน้าที่ 2 คน ที่จะตรวจบัตรประชาชนเรา แล้วก็ช่วยอาจารย์จับเวลา</p><p>พอให้ดูบัตรประชาชนเสร็จเขาก็บอก “let’s start the interview”<br>เราก็เลยเริ่มแนะนำตัวไป ชื่อ โรงเรียน hobby</p><p><strong>Q: What’s about your family?</strong><br>A: เราก็เล่าว่าพ่อแม่เรียนจบอะไร ทำงานอะไร<br><strong>Q: มีพี่น้องไหม</strong><br>A: มีน้องสาว เรียนอยู่ Grade 8 โรงเรียนเดียวกัน</p><p><strong>Q: ให้อธิบายงานใน Port อันนึงที่เราทำไปเป็น Mobile App (อันที่ส่งแข่ง NSC นั้นแหละ)</strong><br>A: เราอธิบายไปว่าเป็นแอปอะไร ได้ idea มาจากอะไร ทำเพื่ออะไร</p><p><strong>Q: มีงานใน Port อยู่ 3 Project มี Challenge อะไรที่เจอตอนทำ</strong><br>A: อันนี้เราเล่าที่ไปแข่ง 2nd Kibo Robot Programming Challenge ว่าช่วงนั้นเป็นการทำงานออนไลน์(เพราะ COVID) ก็จะมีปัญหาเรื่องการทำงานร่วมกันที่อาจจะไม่ Smooth ในช่วงแรก แต่ก็ปรับตัวกันได้เพราะยังไงงานเขียนโปรแกรมมันทำที่ไหนก็ได้ แล้วก็เล่า Challenge จริง ๆ ของงานว่าการแข่งนั้นเราจะต้องควบคุมหุ่นยนต์ให้แม่นที่สุด แต่ก็ต้อง Optimize Code ให้ทำงานได้เร็วที่สุด</p><p><strong>Q: ตอนทำงาน, ทำ Project เป็นกลุ่มเจอปัญหาไรบ้างไหม</strong><br>A: อันนี้ก็เดาว่าเขาคงถามเน้นเวลาที่เราไปแข่งขันเป็นทีม ก็เลยตอบไปว่าเวลาแข่งพวกนี้มันไม่เหมือนกับงานกลุ่มที่ทำในห้องที่ถ้าคนไม่ทำก็สามารถโดนตัดชื่อออกจากกลุ่ม แล้วก็จะไม่ได้คะแนน แต่พอเป็นงานแข่งทุกคนมาด้วยความสมัครใจ แล้วเราก็ไม่สามารถไปบังคับให้ทุกคนช่วยทำงานได้ ซึ่งมันก็จะมีบางงานแข่งที่เราไม่ได้ใส่ใน Portfolio ที่ครูในชมรมอาจจะจับทีมให้เราไปแข่ง แล้วก็มีคนไม่ทำงาน ซึ่งสิ่งที่เราทำก็คือ ช่างมันแล้วก็ไป Concentrate ทำงานกับคนที่อยากทำ แล้วครั้งหน้าก็ไม่ทำงานกับมันอีก (เอาจริง ๆ ตรงนี้รู้สึกว่ามันไม่ใช่วิธีการแก้ปัญหาที่ดีเท่าไร แต่ก็คิดอย่างอื่นไม่ออก แล้วเราก็ทำแบบนี้ก็ตอบไปแบบนี้แหละ)</p><p><strong>Q: เกรดดีทั้งคณิต ฟิสิกส์ เคมี เลยนะเนี่ย ชอบวิชาไหนมากสุด</strong><br>A: ชอบฟิสิกส์ เพราะว่ารู้สึกว่าเป็นวิชาที่เรียนแล้วเห็นภาพในชีวิตจริง เช่นเรื่องการเคลื่อนที่เราก็เห็นความสัมพันธ์ของตัวแปรต่าง ๆ ในชีวิตจริงได้ แต่อย่างเคมีรู้สึกว่าเรียนเกี่ยวกับอะตอม โมเลกุล เราก็ไม่ได้เห็นว่าจริง ๆ มันหน้าตาเป็นไง ประมาณนี้</p><p><strong>Q: อาจารย์ Share จอขึ้นมาให้เราทำโจทย์เลข</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/691/1*ixPoIJJI24OVMQF2xiJrLA.png" /><figcaption>อันนี้วาดเองหลังสัมเสร็จนะ แต่โจทย์แบบนี้แหละ</figcaption></figure><p>A: อันนี้ก็หา x ไป 2 ข้อ ข้อ 2 เขาถามวิธีคิดเราก็อธิบายว่ามุมภายในของสามเหลี่ยมมันต้องเป็น 180 ทำให้ได้มุมที่อยู่ตรงข้าม X แล้วก็เส้นตรงมุมรวมเป็น 180 ประมาณนี้</p><p><strong>Q: เขาแก้โจทย์ บอกให้ Differentiate 2^x </strong><br>A: เราตอบมั่วไป ซึ่งมันก็ผิด เขาไม่ได้ว่าอะไร แล้วก็ปิด Powerpoint โจทย์ไป</p><p><strong>Q: ให้หา Volume ห้องที่เราอยู่ตอนนี้</strong><br>A: เราเดาความกว้าง ยาว สูงของห้อง แล้วก็คูณเลขตอบไป</p><p><strong>Q: Density คือ</strong><br>A: มวล ต่อ ปริมาตร ก็คือขนาดของมวลในปริมาตร 1 หน่วย</p><p><strong>Q: คิดว่าเราจะกลับไป lockdown ไหม</strong><br>A: คิดว่าขึ้นอยู่กับการพัฒนาของ Virus กับ Vaccine ถ้ามี Virus สายพันธุ์ใหม่มาแล้วอัตราการตายมันสูงก็มีโอกาสที่เราจะกลับไป Lockdown ใหม่</p><p><strong>Q: ถ้าไม่ได้ภาค ICE จะทำไง</strong><br>A: ถ้าได้ภาค Robotics AI ก็จะไปคิดดูก่อน แต่ถ้าไม่ได้ทั้งคู่เราจะไปเรียนมหาวิทยาลัยอื่น</p><p><strong>Q: Apply มหาวิทยาลัยอื่นไหม บอกได้ไหมว่าที่ไหน</strong><br>A: ผม Apply แค่ที่นี่กับ Mahidol ICT</p><p><strong>Q: Apply ไปแค่ 2 ที่เหรอ (เขาดูงง + ปนตกใจนิดนึง)</strong><br>A: ใช่ครับ ตอนแรกเราก็สนใจ SIIT ด้วยแต่เนื่องจากมันอยู่ใกล และถ้าอยู่ภาคคอมมันจะต้องไปอยู่บางกะดีด้วย เราเลยตัดสินใจไม่สมัคร</p><p><strong>เขาให้เราถาม</strong><br><strong>Q: ส่วนใหญ่เด็กที่จบ ICE ไปทำงานตรงสายไหม เช่น ไปเป็น Software Engineer รึเปล่า</strong><br>A: เขาไม่ใช่อาจารย์ภาค ICE แต่ว่าเด็ก ISE จุฬาเกีอบทั้งหมดได้ทำงานในบริษัทดี ๆ หรือไม่ก็ไปเปิด Start Up กันเอง<br>A (อาจารย์อีกคน): แนะนำให้เลือกภาคที่เราอยากเรียนตามความชอบตอนนี้ เพราะอีก 4 ปี ความชอบของเราอาจจะเปลี่ยนก็ได้</p><p><strong>Q: เด็ก ISE มีไป Exchange เยอะไหม</strong><br>A: มีไปหลายประเทศเลย ทั้งไปทำงานในภาคอุตสาหกรรม และก็ไปทำวิจัยกับมหาวิทยาลัยต่างประเทศ</p><p><strong>Q: แล้วเด็ก ISE มีทำงานวิจัยกันไหม</strong><br>A: จะทำกันช่วงปี 4 เพราะว่าปี 2–3 จะมี Coursework เยอะ แล้วช่วงปี 1 ก็จะต้องปรับตัวจากการเรียนมัธยมมามหาวิทยาลัย</p><p>หลังวันสัมภาษณ์ 4–7 วัน (แล้วแต่ว่าได้สัมภาษณ์วันไหน) เขาก็จะประกาศผลว่าเราผ่านไหม แล้ว Rank เท่าไร (ลำดับคะแนนที่ได้จากการสมัคร/สัมภาษณ์) ซึ่งตรงนี้ก็มี Surprise นิดนึงคือ <strong>มีทุนให้ด้วย</strong> ตอนแรกคิดว่าจะมีให้แต่คนที่เข้า Option Test Score (จากที่อ่านประกาศตอนแรกเข้าใจอย่างงั้น) แล้วเขาก็มาแจ้งใน Line ทีหลังว่าคนที่ได้ Rank 1–2 ได้ ISE100 และ Rank 3–4 ได้ ISE50</p><p>ปล. ทุน ISE คือได้แค่ปีแรกปีเดียวนะครับ ปีต่อ ๆ ไปจะวัดกันที่เกรดอีกที</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1023/1*O33I_RTd0wnwQAFG2eBRQA.png" /></figure><p>แล้วเราก็จะต้องเลือกภาคว่าอยากเข้าอะไร อันดับ 1–5 ก็เลือกไปใน Website แล้วเขาก็จะให้ Print ใบออกมาเซ็น ซึ่งจะต้อง Upload เข้าระบบหลังจากที่เข้าไปยืนยันสิทธิ์กับเขาอีกที</p><p>วันยืนยันสิทธิ์ (หลังจากนั้น 3 วัน) เราก็เข้า MS Team ไปตาม Rank (สูงกว่าเลือกก่อน) ซึ่งอาจารย์เขาก็จะ Share Screen เป็น Program เลือกภาคแบบบอกเลยว่าเราเข้าภาคอะไร แล้วก็พูดประมาณว่า ISE commitee decide ว่าเราได้ภาคนี้ Do you confirm? เราก็ตอบไป Yes, ICE is my first chioce อะไรประมาณนั้น แล้วก็ออก Call</p><p>เสร็จแล้วเราก็จะต้องวงในใบที่ Print ออกมาแล้วก็ Upload เข้าไปในระบบ เป็นอันเสร็จพิธี</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FCYmF46qDu6LzmlbVLM-YQ.jpeg" /><figcaption>ใบ Confirm Program</figcaption></figure><p>หลังจากนี้ก็แค่รอกดเลือกมหาลัยในระบบ TCAS แล้วก็จ่ายเงินค่าเทอมตามขั้นตอน (ถ้าเลือกจุฬาอะนะ)</p><p>ซึ่งบอกเลยว่าผมก็สงสัยว่าระบบการเลือกแบบนี้จะทำไปทำไม คือส่วนตัวคิดว่าเลือกออนไลน์ แล้วก็ประกาศเลยว่าใครได้อะไร แล้วก็อาจจะให้ยืนยันอีกที ว่าจะเอาหรือสละสิทธิ๋ แล้วก็เรียกตัวสำรอง แต่ที่เขาทำแบบนี้ก็คงมีเหตุผลของเขาแหละ</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a3978e2fa210" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Diary การแข่งขัน NSC 2022]]></title>
            <link>https://wtarit.medium.com/diary-%E0%B8%81%E0%B8%B2%E0%B8%A3%E0%B9%81%E0%B8%82%E0%B9%88%E0%B8%87%E0%B8%82%E0%B8%B1%E0%B8%99-nsc-2022-340c3e4b9dad?source=rss-4df800a7a724------2</link>
            <guid isPermaLink="false">https://medium.com/p/340c3e4b9dad</guid>
            <dc:creator><![CDATA[Tarit Witworrasakul]]></dc:creator>
            <pubDate>Sat, 11 Mar 2023 10:44:01 GMT</pubDate>
            <atom:updated>2023-03-11T10:44:01.371Z</atom:updated>
            <content:encoded><![CDATA[<p>ก่อนอื่นต้องขอบอกว่าผมเล่าเรื่องนี้ในฐานะผู้เข้าแข่งขันที่ส่งโครงการ และได้รับรางวัลที่ 2 ในหมวดโปรแกรมเพื่อการศึกษาและส่งเสริมการเรียนรู้ ระดับนักเรียนมา และก็เนื้อหาอาจจะผิดพลาด ตกหล่นไปบ้างเพราะหลังจากแข่งก็ยุ่ง ๆ เพิ่งมีเวลามาเขียนให้เสร็จ</p><p>ทำไมถึงลงแข่งรายการนี้?<br>เหตุผลหลัก ๆ เลยที่ผมลงแข่งเป็นเพราะเป็นรายการที่แข่งขันกันระดับชาติ, จัดติดต่อกันมานาน และก็เห็นคนที่ประสบความสำเร็จในสายงานด้าน Programming หลาย ๆ คนก็ผ่านการแข่งขันนี้มา (<a href="https://youtu.be/jo2FBN1z3n4?t=69">ref</a>) แล้วถ้าแข่งชนะได้เงินรางวัลสูง (เทียบกับรายการแข่งขันหุ่นยนต์อื่น ๆ ที่เคยเข้าร่วมมา)</p><p>การแข่งขันในครั้งนี้ผมไปกับเพื่อนอีกคนหนึ่ง (รวม 2 คน) เมื่อรวมทีมได้แล้วพวกเราก็เริ่มหาหัวข้อโครงการที่จะเข้าแข่งขัน พอคุยไปคุยมาก็คิดว่าอยากทำเป็นแอปที่ทำ Text Search ในรูปได้ เพราะว่าเป็นปัญหาที่เราพบเจอกันในปัจจุบัน</p><h3>รอบข้อเสนอโครงการ (รอบ 1)</h3><p>เมื่อได้หัวข้อที่ชัดเจนแล้วเราก็ต้องเริ่มเขียนข้อเสนอโครงการ ซึ่งเราก็ใส่หัวข้อต่าง ๆ ตามที่ระบุไว้ในคู่มือ ซึ่งในจุดนี้ผมก็ต้องเริ่มเลือก Tech Stack ที่จะใช้งานเพื่อที่จะเขียนไปในส่วนของเครื่องมือที่ใช่พัฒนา</p><ul><li>Flutter โดยเนื่องจาก H̶y̶p̶e เราต้องการ Mobile App ที่ Run ได้ทั้งบน iOS และ Android แต่คิดว่าด้วยเวลาที่จำกัดเราคงไม่สามารถเขียน Native ทั้ง 2 Platform ได้ เลยเลือก Flutter ประกอบกับผมเคยเริ่มศึกษา Flutter มานิดหน่อยแล้ว</li><li>Tesseract เพราะว่า App เราต้องการ OCR และอยากให้ทุกอย่าง Run Local บนเครื่อง ซึ่งจากการ Google พบว่า Tesseract OCR ได้หลายภาษา และมี Flutter package</li><li>แล้วก็เขียนพวก Tools ที่ใช้ Vscode, Android Studio, Xcode, Google Colab, Python ใส่ไปเพื่อ ๆ ก่อน (Colab, Python ใส่ไปเพื่อเราใช้ Train model)</li></ul><p>พอส่ง Proposal ไปแล้ว ก็รอประกาศว่าผ่านรอบแรกไหม ซึ่งทีมเราผ่านเข้ารอบ 2 โดยในรอบแรกจะได้ทุนมาทำโครงงาน 3,000 (กว่าจะได้เงินก็หลังงานจบไปละ แต่ได้แน่นอนนะ Confirm)</p><h3>เริ่มเขียน App</h3><p>เมื่อมาเริ่มเขียน App จริง ๆ ก็เจอปัญหามากมาย</p><p>เริ่มจากตัว Feature หลักของ App เราคือ OCR ซึ่งเมื่อทดสอบกับ Tesseract แล้วก็พบว่ามันอ่านลายมือภาษาไทยไม่ค่อยได้ เราก็เลยอยากจะ Train ใหม่ หรือหา model อื่น ๆ โดย Strategy ตอนนั้นคือ อยากใช้ Font ลายมือมา Generate รูป รวมกับ Label Data เพิ่มนิดหน่อย แล้วก็ Train model ใหม่ แต่พอเริ่มลองแล้วก็พบว่าด้วยเวลา และประสบการณ์ เราน่าจะทำกันไม่ทัน</p><p>ซึ่งทำให้เราต้องเปลี่ยนแผนไปใช้ API แทนซึ่งเราเลือกใช้ของ Google Cloud ที่อ่านลายมือภาษาไทยได้ แต่ว่าพอคำนวนราคาแล้วก็คิดว่าไม่ sustainable แน่นอน ถ้าปล่อยให้ใช้ฟรี แต่ให้มันเป็นปัญหาหลังแข่งจบละกัน (คนใช้เยอะเราก็ปิด Backend จบ)</p><p>ปัญหาต่อมาคือเรื่องของการ Deploy Object Detection Model ซึ่งพบว่า Library หรือ Code ตัวอย่างสำหรับ Flutter จะมีแต่ Model เก่า ๆ เช่น YoloV2 ซึ่งเรารู้สึกว่ามันไม่ดีพอ เลยต้องหาวิธี Deploy Model ที่ใหม่กว่าลงไป (สุดท้ายเราเลือกใช้ YoloV4 เพราะเป็น Model เดียวที่หาตัวอย่างได้ ซึ่งก็ต้องเอามา migrate เป็น flutter 2 ที่ต้อง Support null-safety ซึ่งก็เหนื่อยอยู่)</p><h3>รอบนำเสนอผลงาน (รอบ 2)</h3><p>รอบนี้เราจะต้องทำรายงานฉบับสมบูรณ์ แล้วก็คู่มีการติดตั้ง App เหื่อส่งให้กรรมการ</p><p>แล้วก็จะมีการนำเสนอซึ่งตรงนี้เข้าใจว่าจัดโดยศูนย์ประสานงานภูมิภาค ดังนั้นประสบการณ์ที่ผมเจอก็จะเป็นของภาคกลางที่รับผิดชอบโดยมหาวิทยาลัยธรรมศาสตร์ (SIIT) ซึ่งก็จะมี Line OpenChat ที่ใช้ประสานงานนอกเหนือจาก email</p><p>การนำเสนอรอบนี้จะผ่าน Zoom ซึ่งรู้สึกว่ากรรมการที่มาน่าจะมาทางสาย Tech (เอาชื่อไป Search ก็ดูจะเป็นอย่างนั้น) เพราะว่าโดนถามเรื่อง Technical ว่าแบบใช้ model อะไร ตัว OCR ทำยังไงบ้างพวกนี้ โดยรวมรู้สึกว่า Positive ตอบคำถามได้ทั้งหมด</p><h3>ก่อนรอบชิง</h3><p>พอผ่านรอบ 2 ก็จะมี Email มาบอกให้เราทำ Video แนะนำผลงาน ความยาวไม่เกิน 7 นาที, แบบฟอร์มสรุปข้อมูลโครงการ, รายละเอียดทีมพัฒนาและอ.ที่ปรึกษา (พวกเอกสารมี Template ให้หมด แค่กรอกข้อนูล ไม่เยอะ) แล้วก็มีให้ทำ poster ซึ่งเขาวงเล็บว่า (ถ้ามี) ตรงนี้ก็ไม่รู้เหมือนกันว่ามีผลต่อการตัดสินไหม แต่คนที่ทำเห็นเขาเอาไปลงในกลุ่ม Facebook</p><p>แล้วพอเมื่อผ่านเข้ามารอบนี้เราจะได้เงินอีก 9,000 บาท แบ่งเป็นสำหรับผู้พัฒนา 7,000 บาท และอาจารย์ที่ปรึกษา 2,000 บาท</p><p>แล้วก็มีอีกอย่างนึงที่เราพยายามทำเพิ่มคือ Subject Classification คือให้เอกสารในหมวดหมู่ Document ถูกแยกออกเป็นวิชาเพื่อให้มันดูโยงการศึกษามากขึ้น (คิดถูกมากที่ทำ)</p><h3>การนำเสนอรอบชิงชนะเลิศ</h3><p>ในปีนี้เป็นการนำเสนอ Online ผ่าน WebEx ซึ่งการนำเสนอจะนำเสนอ 5 นาที ถามตอบ 10 นาที รอบนี้ Cap ชื่อกรรมการมา Search ไม่ทัน แต่เดาว่าคนที่มาเป็นกรรมการน่าจะไม่ใช่คนสาย Tech เพราะไม่โดนคำถาม Technical เลย เดาว่าผู้จัดน่าจะเอากลุ่มครูซึ่งมีโอกาสจะเป็นผู้ใช้ของ Application มาเป็นกรรมการ</p><p>รอบนี้โดยคำถามค่อนข้างเยอะ</p><p>Q: ที่บอกว่า App ทำการ Index รูปภาพได้ช้านี่ช้าขนาดไหน<br>ข้อนี้โชคดีผมเคยวัด และจดไว้ก็เลยตอบไปได้ เป็น Fact เพราะฉะนั้นเขาก็ไม่ได้แย้งอะไร</p><p>Q: แอปนี้สนับสนุนการเรียนรู้อย่างไร เพราะว่าไม่เห็นส่วนที่จะเข้ามาช่วยในการเรียนการสอน<br>ข้อนี้จริง ๆ เราก็เตรียมคำตอบไว้แล้วระดับนึง เพราะก็รู้ว่าเราทำกว้าง ๆ แต่พยายามตบให้มันเข้าเรื่องการศึกษา ก็เลยตอบไปว่าจริง ๆ App เราสามารถใช้ได้ทุกวัย แต่ว่าก็จะช่วยอำนวยความสะดวกให้กับนักเรียนเพราะว่านักเรียนก็จะมีเอกสาร ชีทเรียนต่าง ๆ ค่อนข้างมาก และก็ให้ดู Feature แยกวิชา ซึ่งเราทำไม่ทันก่อนที่จะส่งรายงาน-Video ซึ่งกรรมการก็บอกเพิ่งเห็น</p><p>Q: แอปนี้มีความแม่นยำในการแยกหมวดหมู่/OCR ขนาดไหน ได้มีการวัดประสิทธิภาพไหม<br>ตอนเจอคำถามนี้เข้าไปก็ปวดหัวเหมือนกันเพราะว่าเราไม่เคยวัด ก็เลยตอบไปว่า เราใช้การสำรวจจากกลุ่มผู้ใช้งานแล้วผู้ใช้มีความพึงพอใจ แต่ก็จะมีบางหมวดที่ผิดอยู่บ้าง เช่นภาพการ์ตูนที่จะไม่มีอยู่ใน Dataset ซึ่งในอนาคตเราก็จำเป็นที่อาจจะต้องเก็บข้อมูลเหล่านี้มาพัฒนา Model ต่อไป<br>Q (กรรมการตอบกลับมา): คือตรงนี้ก็รู้ว่าตัว App สามารถทำงานได้ ก็เคยทดลองใช้งานแล้ว แต่ก็ควรจะมีข้อมูลเหล่านี้เพื่อทำให้รู้ว่าตัว App สามารถทำงานได้ดีให้คนมั้นใจเข้ามาใช้งาน<br>ตรงนี้เราเลยตอบกลับไปว่าการทำไปก็อาจจะไม่ได้ประเมินผลได้แม่นยำ เพราะเราก็มีโอกาสที่จะนำ Dataset ที่มี Bias ที่เรารู้ว่าสามารถทำงานได้ดีมาทดสอบได้อยู่ดี เช่นเราอาจจะใช้รูปที่ลายมือสวย อ่านง่าย มาทดสอบ เราจึงใช้การสำรวจจากผู้ใช้งานจริง<br>Q (กรรมการตอบกลับมา): จริง ๆ ตรงนี้คิดว่าก็น่าจะทำได้ก็อาจจะหาข้อมูลจาก Internet มาทดสอบ</p><p>หมดเวลา (เหมือนจะเกินด้วยซ้ำ)</p><p>จริง ๆ ตอนแรกก็คิดอยู่ในหัวว่าจะตอบตัว mAP ของ model ที่เรา Train ได้ไป แต่คิดว่าไม่เอาดีกว่าเพราะตัวเลขมันดูน้อย (ไม่ถึง 50%) ซึ่งผมกลัวกรรมการจะไม่เข้าใจแล้วเราจะโดนตัดคะแนน แล้วยังไงเราก็ไม่มีตัวเลขของ OCR อยู่ดี</p><p>ซึ่งจริง ๆ มานั่งคิดดูก็รู้สึกว่าถ้าจะวัดจริง ๆ มันก็ยากนะ แล้วมันจะไปเทียบกับอะไร แล้วจะมั่นใจได้ไงว่าไม่ Bias เพราะ Dataset บน Internet (Dataset ที่คนใช้ Benchmark model เช่น COCO, ImageNet) มันก็ไม่ตรงกับสิ่งที่เราต้องการ ดังนั้นมันก็ไม่สามารถเอามาใช้เทียบตรง ๆ ได้ อีกอย่าง เราใช้ Model Object Detection ก็จริง ซึ่งจริง ๆ การวัด Accuracy ของ Object Detection Model มันจะดูว่า Predict Class ถูก แล้วก็ความแม่นยำของ Bounding Box (กล่อง ๆ ที่ Model ตีรอบวัตถุ) แต่ว่าการเอามาใช้ครั้งนี้เราสนแค่ Object ที่มัน Predict ออกมา ไม่ได้สนตำแหน่ง แปลว่าเราก็ควรเอาแค่ Object ที่มัน Predict ถูกมาเป็น Metric ในการวัด?</p><p>ตรงนี้ผมคิดว่าน่าสนใจมากว่า ถ้าผมแข่งในครั้งหน้าควรจะ Handle เรื่องนี้ยังไง ตอนนี้ที่คิดได้ก็คงจะเป็นการเตรียม Dataset มาวัดประสิทธิภาพดู (ที่ตรงกับงานของเรา) แล้วก็อาจจะเปิด Data ชุดนั้นเป็น Public ให้คนอื่นมาดูได้ว่าเราใช้อะไรวัด เพราะส่วนตัวคิดว่าเวลาที่คนจะพิจารณาใช้ App ก็น่าจะทดลองใช้งานก่อน และตัดสินใจว่าจะใช้งานต่อหรือไม่ หรือไม่ก็ดู Review จากคนอื่นอยู่แล้ว</p><p>ดังนั้นถ้าในครั้งหน้าผมมีโอกาสได้เข้าร่วมการแข่งขันนี้อีก สิ่งที่ผมจะเปลี่ยนแปลงคือ</p><ul><li>ถ้า App มีการใช้ Machine Learning Model ไม่ว่าจะเป็นการทำ Model เองหรือการใช้ API ก็ควรมีการวัดประสิทธิภาพ / Accuracy ถึงแม้มันจะไม่มี Industry Standard ก็ตาม เราก็ควรเตรียม Dataset มาวัดเอง (ตาม Paragraph บน)</li><li>รีบทำ Feature ต่าง ๆ ให้เสร็จทั้งหมดก่อนที่จะส่งเล่มรายงานเนื่องจากเมื่อเข้ารอบชิงชนะเลิศแล้วจะไม่มีการส่งเล่มรายงานอีก</li></ul><p>คำแนะนำสำหรับ Programmer ที่อยากลง คือถ้ามีเพื่อนที่ทำงานเอกสาร, Slide, และ Video ดี ๆ ชวนมาเข้าทีมไว้ก็ไม่เสียหายเพราะงานนี้ผมก็ให้เพื่อนช่วยจัดการเรื่องพวกนี้ทำให้ชีวิตสะดวกขึ้นมาก ๆ</p><h3>สิ่งที่ผมคิดว่า NSC ควรปรับปรุง</h3><ul><li>หน้า Web มีการ Login ต้องใส่ข้อมูลต่าง ๆ เพื่อความปลอดภัยตรงนี้ควรจะทำให้เป็น HTTPS ได้แล้ว</li><li>น่าจะมีที่รวมสรุปชื่อโครงการที่ผ่านรอบต่าง ๆ ของปีก่อนในหน้า Web ให้ดูง่าย ๆ ไว้เป็น idea ให้คนที่เข้ามาแข่งใหม่ รวมถึง Video นำเสนอ ไม่ต้องไปหา Load หาดูตามกลุ่ม Facebook ที่ Search ยากเหลือเกิน</li><li>อันนี้ไม่รู้ว่าเขามีเหตุผลอะไรเป็นพิเศษหรือเปล่า แต่อยากให้ปล่อยคลิปที่นำเสนอกับกรรมการของทุกทีมเพื่อความโปร่งใส แล้วก็จะได้เป็น idea ให้กับรุ่นต่อ ๆ ไปที่เข้ามาแข่งด้วย</li></ul><p>ถ้าใครอยากดู Code ที่เราเขียนก็ไปดูได้ที่ <a href="https://github.com/wtarit/domacod">https://github.com/wtarit/domacod</a></p><p>ปล. Backend อาจจะไม่อยู่ตลอดไปนะครับ มันกินเงิน Google Cloud ผมอยู่ทุกเดือน แต่ไปลอง Deploy ใช้เองได้ครับ</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=340c3e4b9dad" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[ลง Bootloader MightyCore ให้กับ Board ที่ใช้ ATMega644P เพื่อให้ใช้กับ Platform IO ได้]]></title>
            <link>https://wtarit.medium.com/%E0%B8%A5%E0%B8%87-bootloader-mightycore-%E0%B9%83%E0%B8%AB%E0%B9%89%E0%B8%81%E0%B8%B1%E0%B8%9A-board-%E0%B8%97%E0%B8%B5%E0%B9%88%E0%B9%83%E0%B8%8A%E0%B9%89-atmega644p-%E0%B9%80%E0%B8%9E%E0%B8%B7%E0%B9%88%E0%B8%AD%E0%B9%83%E0%B8%AB%E0%B9%89%E0%B9%83%E0%B8%8A%E0%B9%89%E0%B8%81%E0%B8%B1%E0%B8%9A-platform-io-%E0%B9%84%E0%B8%94%E0%B9%89-eb32e5e8d0f4?source=rss-4df800a7a724------2</link>
            <guid isPermaLink="false">https://medium.com/p/eb32e5e8d0f4</guid>
            <category><![CDATA[inex]]></category>
            <dc:creator><![CDATA[Tarit Witworrasakul]]></dc:creator>
            <pubDate>Thu, 03 Mar 2022 16:29:38 GMT</pubDate>
            <atom:updated>2022-03-03T16:29:38.840Z</atom:updated>
            <content:encoded><![CDATA[<p>เนื่องจาก Board ของ INEX นั้นจะต้องใช้กับ Arduino ของ INEX เท่านั้น ผมจึงต้องการที่จะเปลี่ยนไปใช้ Platform IO เพราะต้องการ Feature ต่าง ๆ เช่น Autocomplete</p><p>Board ที่ผมจะนำมาลง Bootloader ใหม่ในวันนี้ก็คือ IPST-SE ซึ่งอุปกรณ์ที่ต้องใช้นอกจาก Board ที่ต้องการลง Bootloader ก็ต้องใช้ ISP programmer ซึ่งจะซื้อ ISP programmer โดยเฉพาะใช้ก็ได้ แต่สำหรับคนที่ไม่อย่ากซื้อก็สามารถใช้ Arduino อีกตัวมาเป็น ISP programmer ได้ ซึ่งผมจะใช้เป็น ESP32 (สามารถใช้ตัวอื่นที่มีได้)</p><p>** ถ้าใครใช้ ISP Programmer ตัวอื่น ๆ สามารถข้ามไป Part ต่อไปได้เลย</p><p>ในการเตรียม ESP32 สำหรับเป็น ISP programmer นั้น ก็ต้องลง Sketch ArduinoISP (เปิดได้จาก example &gt; ArduinoISP &gt; ArduinoISP) ซึ่งสำหรับ ESP32 นั้นจะต้องแก้ Reset Pin เพราะ Pin 10 ของ ESP32 นั้นต่อกับ SPI flash อยู่ ให้เปลี่ยนเป็น GPIO ไหนก็ได้ (ที่ไม่ใช่ SPI pin เพราะต้องใช้ส่งข้อมูล) ในกรณีนี้ผมเปลี่ยนเป็น pin 22 และ LED_HB ซึ่งผมเปลี่ยนเป็น pin 2 (เพื่อใช้งาน Builtin LED บน ESP32 dev board)</p><p>สามารถ Download code ที่แก้แล้วได้ที่ <a href="https://gist.github.com/wtarit/696e409b16465008bb89076ee81c01e1">link</a></p><p>Note: หากมีปัญหา Burn bootloader ไม่ผ่านแล้วเจอ Error เช่น</p><pre>avrdude: stk500_getsync() attempt 10 of 10: not in sync: resp=0x40</pre><p>ให้ลองเปลี่ยน Pin ที่ใช้อันอื่น ๆ ที่อาจจะตรงกับ GPIO ของ ESP32 ที่ไม่สามารถใช้งานได้ (สามารถดูได้ตาม <a href="https://randomnerdtutorials.com/esp32-pinout-reference-gpios/">link</a>) จากที่ทดลองทำเปลี่ยนแค่ LED_HB ก็ใช้ได้ แต่ถ้าไม่ได้อาจจะต้องแก้ตัวอื่นด้วย</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/495/1*klQuFenb5JUdofxGbq1O-A.jpeg" /><figcaption>การเปิด Sketch ArduinoISP</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/944/1*TcZkVqHfWLtZF_gLMZHfPg.jpeg" /><figcaption>แก้ในบรรทัดที่ 73–74</figcaption></figure><p><strong>การต่อสายไฟ</strong></p><p>ตัว Board IPST-SE นั้นมี ISP connector มาให้อยู่แล้ว ซึ่งตอน Program ผมใช้ไฟเลี้ยงบอร์ดที่ 3.3 V จาก ESP32 เลย ไม่ได้ต่อไฟเลี้ยงให้ IPST-SE แยก เพื่อจะได้ไม่ต้องใช้ Logic Level Shifter ให้วุ่นวาย (จากที่ลอง Flash ที่ 3.3V สามารถทำได้ไม่มีปัญหา) ซึ่งก็สามาถต่อกับ Hardware SPI Pin (หรือ Pin ที่กำหนดบน ESP32 ได้เลย) ส่วน RESET นั้นก็ต่อตามที่กำหนด (ในที่นี้กำหนดเป็น 22)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xZCHEwI0-RzFFZcsGbhoQA.jpeg" /><figcaption>IPST-SE ISP Pinout</figcaption></figure><p><strong>การ Burn Bootloader ผ่าน Arduino IDE</strong></p><p>การจะ Burn Bootloader นั้นจะต้อง Install <a href="https://github.com/MCUdude/MightyCore">MightyCore</a> บน Arduino IDE ก่อน ซึ่งทำโดยเพิ่ม URL</p><pre>https://mcudude.github.io/MightyCore/package_MCUdude_MightyCore_index.json</pre><p>เข้าไปใน Additional Boards Manager URLs และ install <a href="https://github.com/MCUdude/MightyCore">MightyCore</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/786/1*nbapbpL5t0q-GFkVPXavEg.jpeg" /><figcaption>Install Board</figcaption></figure><p>เมื่อ Install เสร็จแล้ว ให้เลือก Board เป็น ATmega644 เลือก Programmer เป็น Arduino as ISP (MightyCore) ส่วน Port ให้เลือก Port ขอว ESP32 ที่จะใช้งานเป็น Programmer และกด Burn Bootloader ได้เลย</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/739/1*cqRc8BdBQIKvyi4UUTDSOQ.jpeg" /><figcaption>เลือก Board</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/748/1*QN3aVKOnTzf9PZ3JByNsPw.jpeg" /><figcaption>เลือก Programmer</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/473/1*u-ETcuDBWAOs1TWtJ8CLrw.jpeg" /><figcaption>กด Burn Bootloader ได้เลย!</figcaption></figure><p>รอจน Burn Bootloader เสร็จ (ใช้เวลาไม่เกิน 1 นาที) โดย Arduino IDE จะขึ้นว่า Done burning bootloader. และ avrdude done. Thank you. ใน Output ด้านล่าง ก็สามารถนำ Board ไปใช้งานใน PlatformIO ได้แล้ว (จะใช้ใน Arduino IDE โดยเลือก Board เป็น ATmega644 ก็ได้)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*pflqbXiXOIQ3Ig6lFZ8tVg.jpeg" /><figcaption>Burn Bootloader เสร็จเรียบร้อย</figcaption></figure><p><strong>การใช้งาน — สร้าง Project ใน PlatformIO</strong></p><p>ในการสร้าง Project ใน PlatformIO ให้เลือก Board เป็น ATmega644P/PA</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/610/1*87nxjSmYBqB0apR88SaqeA.jpeg" /></figure><p>สามารถใช้งานได้เลย แต่จะใช้งานคำสั่งต่าง ๆ ของ INEX ไม่ได้แล้วนะครับ เช่นพวก motor, OK, knob, glcd ต้องเขียนใหม่เอง และ pinmap ก็จะไม่เหมือนเดิม โดยต้องดูเทียบกันระหว่าง pinmap เดิม กับ pinmap ของ MightyCore (<a href="https://camo.githubusercontent.com/0b707a4b8289bb01db43b1bf0b70bccd828830d5508348d6ffa8f67bf9b24f3d/68747470733a2f2f692e696d6775722e636f6d2f7a424e506335622e706e67">link</a>)</p><p>Motor Library ที่ผมเขียนเอง (ใช้ได้ทั้ง 2 bootloader) <a href="https://github.com/wtarit/IPST-SE_Motor">https://github.com/wtarit/IPST-SE_Motor</a></p><p>(นำมาจาก file pins_arduino.h ใน C:\Arduino18\hardware\INEX_AVR\avr\variants\IPST-SE\pins_arduino.h)</p><pre>// ATMEL ATMEGA644P / IPST-SE<br>//<br>//                   +---\/---+<br>//  INT0 (D 16) PB0  1|        |40  PA0 (AI 0 / D31)<br>//  INT1 (D 17) PB1  2|        |39  PA1 (AI 1 / D30)<br>//  INT2 (D 18) PB2  3|        |38  PA2 (AI 2 / D29)<br>//   PWM (D 19) PB3  4|        |37  PA3 (AI 3 / D28)<br>//   PWM (D 20) PB4  5|        |36  PA4 (AI 4 / D27)<br>//  MOSI (D 21) PB5  6|        |35  PA5 (AI 5 / D26)<br>//  MISO (D 22) PB6  7|        |34  PA6 (AI 6 / D25)<br>//   SCK (D 23) PB7  8|        |33  PA7 (AI 7 / D24)<br>//             RST  9|        |32  AREF<br>//             VCC 10|        |31  GND <br>//             GND 11|        |30  AVCC<br>//           XTAL2 12|        |29  PC7 (D 15)<br>//           XTAL1 13|        |28  PC6 (D 14)<br>//  RX0 (D 0)  PD0 14|        |27  PC5 (D 13) TDI<br>//  TX0 (D 1)  PD1 15|        |26  PC4 (D 12) TDO<br>//  RX1 (D 2) PD2 16|        |25  PC3 (D 12) TMS<br>//  TX1 (D 3) PD3 17|        |24  PC2 (D 10) TCK<br>//  PWM (D 4) PD4 18|        |23  PC1 (D 9) SDA<br>//  PWM (D 5) PD5 19|        |22  PC0 (D 8) SCL<br>//  PWM (D 6) PD6 20|        |21  PD7 (D 7) PWM<br>//                   +--------+<br>//</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QnbrmOiDNu4LA6iJRFKctA.png" /><figcaption>Pinmap ของ MightyCore</figcaption></figure><p><strong>การ Burn Bootloader เดิมกลับคืน</strong></p><p>ในการ Burn Bootloader เดิมก็มีขั้นตอนเหมือนกับการลง Bootloader MightyCore เพียงแค่เปลี่ยน Board ใน ArduinoIDE กลับเป็น IPSE-SE</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/454/1*q34ccG0ll_2dA1Ca7fx4_g.jpeg" /></figure><p>เมื่อกด Burn Bootloader แล้วจะเจอ Error</p><pre>Error while burning bootloader: missing &#39;bootloader.tool&#39; configuration parameter</pre><p>(เจอใน Arduino IDE version 1.8.16 จาก INEX version อื่น ๆ อาจไม่เป็น)</p><p>ให้เข้าไปแก้ file boards.txt โดยเข้าไปที่ C:\Arduino18\hardware\INEX_AVR\avr หรือตำแหน่งที่ติดตั้ง Arduino แล้วเพิ่ม</p><pre>IPST-SE.bootloader.tool=avrdude</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/794/1*hjyl9fEJHt_lxhTlLGCyrg.jpeg" /><figcaption>แก้ File boards.txt</figcaption></figure><p>ปิด Arduino IDE แล้วเปิดใหม่ก็จะสามารถ Burn Bootloader ได้</p><p><strong>Reference</strong></p><p><a href="https://forum.arduino.cc/t/missing-bootloader-tool-configuration-error-when-trying-to-burn-bootloader/304914">https://forum.arduino.cc/t/missing-bootloader-tool-configuration-error-when-trying-to-burn-bootloader/304914</a></p><p><a href="https://youtu.be/06Kj1ALprGw?t=150">https://youtu.be/06Kj1ALprGw?t=150</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=eb32e5e8d0f4" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[จด Domain ใช้งานแบบไม่เสียเงินด้วย Freenom]]></title>
            <link>https://wtarit.medium.com/%E0%B8%88%E0%B8%94-domain-%E0%B9%83%E0%B8%8A%E0%B9%89%E0%B8%87%E0%B8%B2%E0%B8%99%E0%B9%81%E0%B8%9A%E0%B8%9A%E0%B9%84%E0%B8%A1%E0%B9%88%E0%B9%80%E0%B8%AA%E0%B8%B5%E0%B8%A2%E0%B9%80%E0%B8%87%E0%B8%B4%E0%B8%99%E0%B8%94%E0%B9%89%E0%B8%A7%E0%B8%A2-freenom-e5b64d2747c6?source=rss-4df800a7a724------2</link>
            <guid isPermaLink="false">https://medium.com/p/e5b64d2747c6</guid>
            <category><![CDATA[web-hosting]]></category>
            <category><![CDATA[freenom]]></category>
            <dc:creator><![CDATA[Tarit Witworrasakul]]></dc:creator>
            <pubDate>Thu, 29 Jul 2021 15:28:31 GMT</pubDate>
            <atom:updated>2021-07-29T15:28:31.687Z</atom:updated>
            <content:encoded><![CDATA[<p>ก่อนอื่นต้องเตือนไว้ก่อนเลยว่าความ Free ของ Domain ที่จดกับ Freenom อาจจะไม่ได้ Free ตลอดไปนะครับ เคยมี Case ว่าถ้า Website มี Traffic เยอะๆ แล้ว Freenom จะ Deactivate Domain ของเราแล้วต้องซื้อเพื่อใช้งานต่อ [<a href="https://hostingpill.com/domain-registrar/freenom/">Ref</a>]</p><p>สำหรับผม ผมไม่ได้สนใจในส่วนนี้ เพราะ Project นี้เป็น Project API ที่ใช้กับ Chatbot (ใช้ Tool ของ Botnoi) ที่ผมสามารถ URL เปลี่ยนเมื่อไรก็ได้ แต่ถ้าจะนำไปใช้เป็น website ที่ต้องการให้คนจำได้ ควรจะพิจารณาในส่วนนี้ด้วยนะครับ</p><p>เรื่มแรก เข้าไปที่ Website <a href="http://www.freenom.com">www.freenom.com</a> แล้ว Search domain ที่ต้องการ</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*K-OTXhnzaICZzz75Yyjddg.png" /></figure><p>จะเห็นได้ว่าจะมี Domain .tk .ml .ga .cf .gq ที่ให้ Free ให้กด Get it now</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BgaE1onakvgNqeK2UmL_Mg.png" /></figure><p>ถ้ากด Get it now ได้ก็ให้กด Checkout ได้เลย แต่ถ้าไม่ได้ (ตามภาพด้านบน) ให้ไปพิมพ์ชื่อ Domain พร้อม Domain name extension</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*73UplEiBJsEBCQfPvtqBSQ.png" /></figure><p>กด Checkout เลือก Period เป็น 12 months แล้วกด Continue</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qpF0x5uGf9DD8OHcNzVQGg.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Q-xBJiLCGzXwZuoHyIu8fA.png" /></figure><p>Register ตามขั้นตอน จนเข้ามาหน้าหลักอีกรอบ</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*De_eLGIvFkkqs-Y47R2Wqw.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zn9RUBO8sorgyMQlLDNJGw.jpeg" /></figure><p>เลือก My Domains แล้ว เลือก Manage Domain ใน Domain ที่ต้องการ</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7KCQNNGX65fuWxYGGhUQpg.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aOO1OnhI7KipYGLmVX0HQg.jpeg" /></figure><p>เลือก Manage Freenom DNS และ Add record ได้เลย โดยช่อง Name จะเป็น Subdomain Ex. <a href="https://www.google.com/"><strong>www</strong>.google.com/</a> , <a href="https://docs.google.com/document/u/0/"><strong>docs</strong>.google.com</a> <br>ส่วนช่อง Target ให้ใส่ IP address ของ Server ได้เลย</p><p>แค่นี้ก็สามารถเข้า Website ของเราผ่าน Domain name ที่จดใหม่ได้แล้ว แต่อาจจะต้องรอซัก 15–30 นาทีให้ DNS update ก่อนถึงจะเข้าได้</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e5b64d2747c6" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[ESP32-cam ส่งรูปผ่าน Post Request]]></title>
            <link>https://wtarit.medium.com/esp32-cam-%E0%B8%AA%E0%B9%88%E0%B8%87%E0%B8%A3%E0%B8%B9%E0%B8%9B%E0%B8%9C%E0%B9%88%E0%B8%B2%E0%B8%99-post-request-1956d98b7105?source=rss-4df800a7a724------2</link>
            <guid isPermaLink="false">https://medium.com/p/1956d98b7105</guid>
            <category><![CDATA[esp32]]></category>
            <category><![CDATA[fastapi]]></category>
            <category><![CDATA[http-request]]></category>
            <category><![CDATA[esp32-cam]]></category>
            <dc:creator><![CDATA[Tarit Witworrasakul]]></dc:creator>
            <pubDate>Thu, 08 Apr 2021 17:12:15 GMT</pubDate>
            <atom:updated>2021-04-08T17:12:15.849Z</atom:updated>
            <content:encoded><![CDATA[<p>เนื่องจากผมมี Project ที่จะใช้ ESP32-cam ในการส่งรูปไปยัง Server เพื่อทำการ Process ต่อ โดยตั้งใจจะ Host ไว้บน Heroku เลยต้องใช้ HTTP Request ในการส่งรูป โดยในตัว Server ผมจะใช้ Python กับ FastAPI</p><p>จากการหาข้อมูล ผมก็เจอ <a href="https://randomnerdtutorials.com/esp32-cam-post-image-photo-server/">Tutorial ของ Random Nerd Tutorials</a> แต่พอเอามาใช้กับ FastAPI ก็พบ Error 422 Unprocessable Entity ซึ่งก็พบว่าจำเป็นที่จะต้องแก้ Code ฝั่ง Server หรือ ESP32 cam โดยในส่วนของ name ใน String head ตรงช่อง name ต้องตรงกับ <a href="https://fastapi.tiangolo.com/tutorial/request-files/#file-parameters-with-uploadfile">File parameter</a> ของ FastAPI</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/760/1*zrz7wfqNEHHhvZo2T1-oJQ.jpeg" /><figcaption>File parameter ใน function สำหรับรับ file (ไมีจำเป็นที่จะต้องเป็น async def)</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*pGbWgz2W-q5V-DLFatu8Dw.jpeg" /><figcaption>จุดที่ต้องแก้ใน String head</figcaption></figure><p>ที่นี้เราก็สามารถนำรูปออกมาใช้งานได้แล้วครับ</p><p>ปล.สำหรับคนใช้ flask ลองดู <a href="https://github.com/Nannigalaxy/esp32-cam_flask">repo</a> นี้ดูครับ</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1956d98b7105" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[เเก้ปัญหา detectron2 show ภาพไม่ครบ frame เมื่อ run demo โดยใช้ webcam]]></title>
            <link>https://wtarit.medium.com/%E0%B9%80%E0%B9%80%E0%B8%81%E0%B9%89%E0%B8%9B%E0%B8%B1%E0%B8%8D%E0%B8%AB%E0%B8%B2-detectron2-show-%E0%B8%A0%E0%B8%B2%E0%B8%9E%E0%B9%84%E0%B8%A1%E0%B9%88%E0%B8%84%E0%B8%A3%E0%B8%9A-frame-%E0%B9%80%E0%B8%A1%E0%B8%B7%E0%B9%88%E0%B8%AD-run-demo-%E0%B9%82%E0%B8%94%E0%B8%A2%E0%B9%83%E0%B8%8A%E0%B9%89-webcam-36b016188666?source=rss-4df800a7a724------2</link>
            <guid isPermaLink="false">https://medium.com/p/36b016188666</guid>
            <category><![CDATA[detectron2]]></category>
            <dc:creator><![CDATA[Tarit Witworrasakul]]></dc:creator>
            <pubDate>Mon, 14 Dec 2020 13:27:05 GMT</pubDate>
            <atom:updated>2020-12-14T13:27:05.923Z</atom:updated>
            <content:encoded><![CDATA[<p>เนื่องจากผมลอง run code demo จาก <a href="https://github.com/facebookresearch/detectron2/blob/master/demo/demo.py">https://github.com/facebookresearch/detectron2/blob/master/demo/demo.py</a> เเล้วให้ใช้รูปจาก webcam เเล้วมัน show รูปไม่เต็ม frame</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/1*iFWMm8yVYuV-VkYPCHOxFQ.jpeg" /></figure><p>ลองไล่อ่าน code ดูเจอว่า window ของ opencv มันถูกกำหนด size ไว้ (line 121)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/729/1*PvIKQPSIrAtyWgJipYzIzA.jpeg" /></figure><p>เลยเเก้โดยเอาออกไปเลย (เอา cv2.WINDOW_NORMAL ออก)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/641/1*M3YAAm751LXBGKBbgz2_Vw.jpeg" /><figcaption>ดูรูปได้เเบบเต็มๆเเล้ว</figcaption></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=36b016188666" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[วิธีการ Pair Bluetooth ระหว่างมือถือกับ micro:bit]]></title>
            <link>https://wtarit.medium.com/%E0%B8%A7%E0%B8%B4%E0%B8%98%E0%B8%B5%E0%B8%81%E0%B8%B2%E0%B8%A3-pair-bluetooth-%E0%B8%A3%E0%B8%B0%E0%B8%AB%E0%B8%A7%E0%B9%88%E0%B8%B2%E0%B8%87%E0%B8%A1%E0%B8%B7%E0%B8%AD%E0%B8%96%E0%B8%B7%E0%B8%AD%E0%B8%81%E0%B8%B1%E0%B8%9A-micro-bit-a759b0a3ab6e?source=rss-4df800a7a724------2</link>
            <guid isPermaLink="false">https://medium.com/p/a759b0a3ab6e</guid>
            <category><![CDATA[bluetooth-low-energy]]></category>
            <category><![CDATA[microbit]]></category>
            <category><![CDATA[bluetooth]]></category>
            <category><![CDATA[bbc-microbit]]></category>
            <category><![CDATA[ble]]></category>
            <dc:creator><![CDATA[Tarit Witworrasakul]]></dc:creator>
            <pubDate>Sun, 19 Apr 2020 10:30:36 GMT</pubDate>
            <atom:updated>2020-04-19T10:30:36.374Z</atom:updated>
            <content:encoded><![CDATA[<p>บทความนี้จะเน้นการ Pair micro:bit กับ Android เป็นหลัก</p><p>การเลือกโหมดการ Pair ของ micro:bit นั้น จะมี 3 เเบบดังนี้</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zlgG-RQx8JGeLLLur5ux1g.jpeg" /></figure><p>ซึ่งเข้าไปปรับได้โดย เข้าไปใน Project Settings</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/345/1*mT47PZFfv9HlBsW1d6il9g.jpeg" /></figure><h4>JustWorks pairing เป็น Defualt หากไม่เข้าไปปรับ โดยวิธีการ Pair คือ</h4><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FJlzGCeaPhWU%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DJlzGCeaPhWU&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FJlzGCeaPhWU%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/4e1aaf442fe25340e116506239c673a1/href">https://medium.com/media/4e1aaf442fe25340e116506239c673a1/href</a></iframe><p>เเต่จะไม่ต้องใส่ Passcode (กดเลือกในมือถือเเล้ว Pair ได้เลย)</p><h4>Passkey pairing</h4><p>ตามใน Video เลยคือต้องใส่ Passcode ก่อนถึงจะ Pair</p><h4>No Pairing Required</h4><p>อันนี้ผมงงๆ กับมันอยู่เพราะเวลากด Connect ในมือถือ มันก็ขึ้นให้ใส่ Passcode อยู่ดี เเต่ไม่ต้องเข้า Pairing Mode (กด A+B เเล้ว Reset) คือมันจะ Scan หาได้เลย</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a759b0a3ab6e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[สร้างรถบังคับผ่านมือถือด้วย micro:bit ผ่าน BLE]]></title>
            <link>https://wtarit.medium.com/%E0%B8%AA%E0%B8%A3%E0%B9%89%E0%B8%B2%E0%B8%87%E0%B8%A3%E0%B8%96%E0%B8%9A%E0%B8%B1%E0%B8%87%E0%B8%84%E0%B8%B1%E0%B8%9A%E0%B8%9C%E0%B9%88%E0%B8%B2%E0%B8%99%E0%B8%A1%E0%B8%B7%E0%B8%AD%E0%B8%96%E0%B8%B7%E0%B8%AD%E0%B8%94%E0%B9%89%E0%B8%A7%E0%B8%A2-micro-bit-%E0%B8%9C%E0%B9%88%E0%B8%B2%E0%B8%99-ble-47b383408630?source=rss-4df800a7a724------2</link>
            <guid isPermaLink="false">https://medium.com/p/47b383408630</guid>
            <category><![CDATA[bluetooth-low-energy]]></category>
            <category><![CDATA[ble]]></category>
            <category><![CDATA[rc-cars]]></category>
            <category><![CDATA[microbit]]></category>
            <category><![CDATA[bbc-microbit]]></category>
            <dc:creator><![CDATA[Tarit Witworrasakul]]></dc:creator>
            <pubDate>Sun, 19 Apr 2020 10:22:40 GMT</pubDate>
            <atom:updated>2020-04-20T08:27:23.780Z</atom:updated>
            <content:encoded><![CDATA[<p>micro:bit BLE rc car using Kitronik Move app</p><p>Code เเละ Application ผมได้ลองใช้งานบน Android เท่านั้น แต่เห็นใน IOS น่าจะสามารถใช้ Official App ของ micro:bit ได้เลย</p><p>Code นี้สามารถนำไปปรับใช้ควบคุมอะไรก็ได้โดยใช้ micro:bit กับโทรศัพท์มือถือเเต่ในที่นี้ผมจะใช้ในการควบคุมรถบังคับ</p><h4>อุปกรณ์ที่ใช้</h4><ol><li>ตัวรถ</li><li>micro:bit</li><li>บอร์ดขับมอเตอร์ (ใช้ของอะไรก็ได้ เพียงเขียน Code ให้ตรงกับบอร์ดที่ใช้ ในที่นี้ผมใช้ Board iBIT ของ INEX)</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*lxou548gVbEeMpeHL9zsgg.jpeg" /><figcaption>ไม่ต้อสนใจพวกสายไฟเยอะๆทั้งหลายนะครับ ผมต่อ Sensor ทิ้งไว้เเต่ไม่ได้ใช้ในงานนี้</figcaption></figure><p>เริ่มเเรกให้ Download App Kitronik Move (<a href="https://play.google.com/store/apps/details?id=com.kitronik.blemove&amp;hl=en">https://play.google.com/store/apps/details?id=com.kitronik.blemove&amp;hl=en</a>)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zS53CSuMEj7m1xH-eM-Hkg.jpeg" /></figure><p>จากนั้น เขียนโปรเเกรมลง micro:bit โดยผมจะใช้ MakeCode Block Editor เริ่มจากไปลง Extension Bluetooth เเละลง Extension อื่นๆ ที่ต้องการใช้งาน</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xw9v_5u4B4MWY8cZn8UR9g.jpeg" /><figcaption>เมื่อเลือกเเล้วจะมี Pop-up ว่า Extension radio is incompatible with bluetooth. Remove radio and add bluetooth? ให้กด Remove ไปเลย</figcaption></figure><p>ก่อนที่จะใช้งานจะต้อง Pair Bluetooth กับ micro:bit ก่อน</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FJlzGCeaPhWU%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DJlzGCeaPhWU&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FJlzGCeaPhWU%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/4e1aaf442fe25340e116506239c673a1/href">https://medium.com/media/4e1aaf442fe25340e116506239c673a1/href</a></iframe><p>โดยหาก upload code ผ่าน WebUSB จะสามารถใช้งานได้เลยทุกครั้งที่ลง Code ใหม่ เเต่หากใช้การ Copy hex file ไปยัง Drive MICROBIT จะต้องทำการ Pair ใหม่</p><p>การใช้งาน App Kitronik Move</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FUfEYrqXsF70%3Fstart%3D37%26feature%3Doembed%26start%3D37&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DUfEYrqXsF70&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FUfEYrqXsF70%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/ba7eb24d5717b887cba52b01f5b3ffed/href">https://medium.com/media/ba7eb24d5717b887cba52b01f5b3ffed/href</a></iframe><p>ตอนใช้งานอาจต้องเปิด Location เนื่องจาก micro:bit เป็น BLE Device ถ้าจะ Access จะต้อง เปิด Location ก่อน ซึ่งผมก็ไม่รู้ว่าทำไม คงต้องไปถาม Google</p><h4>Code ส่วนนี้ไม่มีผลต่อการทำงานหลัก เป็นการบอกสถานะเท่านั้น</h4><ol><li>ตอนเริ่ม ผมจะให้ Show LED เพื่อให้รู้ว่า Board นั้นมีไฟเลี้ยงจ่ายเข้าไปแล้ว (เวลาจ่ายไฟผ่าน edge connector จะไม่มีไฟขึ้นที่ Port USB</li><li>เมื่อ Bluetooth Connect / Disconnect ก็ให้เปลี่ยนสิ่งที่ Show LED</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/679/1*bx2ZKL9hEFY79oSrEzceSQ.jpeg" /><figcaption>on bluetooth connected เเละ on bluetooth disconnected อยู่ในกลุ่ม Bluetooth</figcaption></figure><p>โดยการเขียน Code หลักนั้นจะใช้คำสั่งจาก Block Control ในการตรวจสอบการกดปุ่มใน App Kitronik Move โดย</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/610/1*tIv0PsLm_9m3y-nvyFH9SQ.jpeg" /></figure><p>การเลือก MES_DPAD_CONTROLLER_ID จะเป็นการตรวจสอบเหุตการณ์การกดปุ่มบน App Kitronik Move ถ้ามีการกด ก็จะเข้าไปทำงานตามที่เขียนโปรแกรมไว้ด้านใน โดยเราจะตรวจสอบค่าที่ได้จากเหตุการณ์นั้นๆ ไปเลยก็ได้ เช่นกดปุ่มใดเเล้วค่อยทำงานโดยกำหนดในช่องถัดมา เเต่ในกรณีนี้ ผมจะเข้าไปเขียนการ Check ว่ากดปุ่มใดใน Event นี้อยู่เเล้วจึงไม่ได้กำหนดเเละปล่อยไว้เป็น MICROBIT_EVT_ANY</p><p>ด้านในเราจะต้องทำการ Check ว่าปุ่มใดถูกกด โดยดูตามตารางต่อไปนี้</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BBMgOpuuYOaGhIkFrlmVaA.jpeg" /><figcaption>ตารางจาก <a href="https://www.kitronik.co.uk/blog/kitronik-move-app/">https://www.kitronik.co.uk/blog/kitronik-move-app/</a></figcaption></figure><p>โดย DPAD คือปุ่มทางด้านซ้าย ส่วน CIRCLE คือปุ่มทางด้านขวา โดยถ้ากดปุ่ม จะเป็น DOWN ปล่อยจะเป็น UP</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/718/1*YGbAfS7iS5ebSYHnxqUaHg.jpeg" /></figure><p>เงื่อนไขที่จะ Check ก็จะเป็นดังนี้ โดย Event Value คือค่าที่ได้จากเหตุการณ์นั้นๆ (ในที่นี้คือ MES_DPAD_CONTROLLER_ID หรือการกดปุ่มนั้นเอง</p><p>หลักการทำงานคือ เมื่อเกิดการกดปุ่ม จะทำการ Check ว่าปุ่มไหนถูกกด เเละทำงานตามเงื่อนไขที่วางไว้ เช่น เมื่อกดปุ่ม MES_DPAD_BUTTON_A_DOWN มอเตอร์จะเดินหน้า ฯลฯ</p><p>จริงๆเเล้ว เราจะเขียนโปรเเกรมโดยให้ Check ปุ่มพร้อมกับ Check เหตุการณ์ไปด้วยเลยก็ได้ เช่น</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2mc9USPbdrruTLT967mAtA.jpeg" /></figure><p>เเต่จะมีปัญหาตรงที่การเขียนเเบบนี้ อาจทำให้เกิด Error ตอนทำงานได้เนื่องจาก จะใช้พื้นที่ Flash หรือ Ram มากไป (Error Code : 20) (อ้างอิงจาก <a href="https://support.microbit.org/support/solutions/articles/19000016969-micro-bit-error-codes">https://support.microbit.org/support/solutions/articles/19000016969-micro-bit-error-codes</a>) ซึ่งตอนผมจะทดสอบโปรเเกรมนี้ ผมถึงกับต้องเอาการ Show LED ช่วงต้นออกเพื่อลดการใช่ทรัพยากรถึงจะทดสอบได้</p><p>อีกปัญหาคือต้อง Check ทั้งการกด เเละการปล่อย มิฉะนั้นพอสั่ง motor เเล้วมันก็จะหมุนไปเรื่อยๆ ไม่หยุดตอนปล่อยปุ่ม เเต่การเขียนเเบบเเรก พอไม่เข้าเงื่อนไขก็จะ Motor Stop ทันที</p><h4>Reference</h4><p><a href="https://www.kitronik.co.uk/blog/kitronik-move-app/">https://www.kitronik.co.uk/blog/kitronik-move-app/</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=47b383408630" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[เเก้ปัญหา ใช้ analogWrite พร้อมกับ IRremote Arduino Library library ไม่ได้]]></title>
            <link>https://wtarit.medium.com/%E0%B9%80%E0%B9%80%E0%B8%81%E0%B9%89%E0%B8%9B%E0%B8%B1%E0%B8%8D%E0%B8%AB%E0%B8%B2-%E0%B9%83%E0%B8%8A%E0%B9%89-analogwrite-%E0%B8%9E%E0%B8%A3%E0%B9%89%E0%B8%AD%E0%B8%A1%E0%B8%81%E0%B8%B1%E0%B8%9A-irremote-arduino-library-library-%E0%B9%84%E0%B8%A1%E0%B9%88%E0%B9%84%E0%B8%94%E0%B9%89-15a1a0f60c3e?source=rss-4df800a7a724------2</link>
            <guid isPermaLink="false">https://medium.com/p/15a1a0f60c3e</guid>
            <dc:creator><![CDATA[Tarit Witworrasakul]]></dc:creator>
            <pubDate>Fri, 17 Apr 2020 17:01:52 GMT</pubDate>
            <atom:updated>2020-05-07T15:14:16.528Z</atom:updated>
            <content:encoded><![CDATA[<h3>แก้ปัญหา ใช้ analogWrite พร้อมกับ IRremote ไม่ได้</h3><p>หมายเหตุ : การเปลี่ยน Timer ที่ใช้กับ IRremote library อาจใช้ในการเเก้ปัญหาที่มีตอนใช้ Library อื่นร่วมกับ IRremote library เนื่องจากใช้ Timer เดียวกัน โดยดูใน <a href="http://z3t0.github.io/Arduino-IRremote/">http://z3t0.github.io/Arduino-IRremote/</a> ว่าโดย Defualt ใช้ Timer ไหนใน Microcontroller นั้นๆ เเละสามารถย้ายไปใช้ Timer ไหนได้บ้าง</p><p>เนื่องจากผมเริ่มใช้ IRremote เพื่อที่จะทำรถบังคับผ่าน board IPST-SE (ผมลง bootloader MightyCore นะครับ เเต่น่าจะนำไปใช้กับ board ที่ใช้ bootloader เดิมได้เหมือนกัน)</p><p>โดย Defualt ของ IRremote Arduino Library (<a href="https://github.com/z3t0/Arduino-IRremote">https://github.com/z3t0/Arduino-IRremote</a>) บนบอร์ด ATMega644P จะใช้ Timer 2 ซึ่งเป็น Timer เดียวกันกับที่ใช้ใน PWM pin ที่ต่อกับ Motor Driver ของ IPST-SE</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*JaGv6G03kxOJ8lW0H1DN7w.png" /></figure><p>ซึ่งเราไม่สามารถไปย้าย Motor Driver ไปต่อ Pin อื่นได้เพราะมันบัดกรีลง PCB มาเเล้ว เเต่ จาก <a href="http://z3t0.github.io/Arduino-IRremote/">http://z3t0.github.io/Arduino-IRremote/</a> จะเห็นว่า ATMega644P สามารถเลือกใช้ได้ 2 Timer คือ 1 เเละ 2</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/473/1*ygV35ZIHA7aq0w3Y3sj_TA.jpeg" /></figure><p>ดังนั้น เราจะย้ายไปใช้ Timer 1 ซึ่งดีเลยเนื่องจาก Timer 1 ใช้ในการคุม PWM Pin 12,13 ซึ่งเป็นขาคุม Direction Motor ยังไงก็ต้องเป็น Digital Logic อยู่เเล้ว เอามาทำอย่างอื่นไม่ได้</p><p>โดยการเปลี่ยน Timer จะต้องเข้าไปที่ Folder ที่เก็บ Library ไว้ โดยจะเเก้ File “boarddefs.h” ให้ดูตรงใต้ // Define which timer to use</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/831/1*sXM9Dq5vNqUG-Y_e06g68A.png" /></figure><p>โดยให้เลื่อนหา Board ที่เราใช้งานเเละ Uncomment Timer ที่จะใช้</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/742/1*cN1gDKSIdAE7-DAohBCTKg.png" /><figcaption>ในกรณีนี้ ผมใช้ ATMega644P ก็เปลี่ยนจาก TIMER2 เป็น TIMER1</figcaption></figure><p>เเค่เเก้ไขไฟล์ Library ง่ายๆ ก็เเก้ปัญหาได้เเล้ว</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=15a1a0f60c3e" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>