Simulink Serial Port Connect with Arduino
การใช้ Simulink สื่อสารกับอาร์ดูโน่ผ่าน Serial Port
ในหัวข้อนี้เราจะพูดถึงเรื่องอะไร?
- การเชื่อมต่อ Simulink กับบอร์ด อาร์ดูโน่
- การส่งและรับข้อมูลแบบรีลไทม์ ระหว่าง Simulink และ อาร์ดูโน่
- การแก้ไขปัญหาหากเชื่อมต่อไม่ได้
การเชื่อมต่อ Simulink กับบอร์ดอาร์ดูโน่
โดยปกติ Simulink จะมีบล็อคสำหรับเชื่อมต่อกับอาร์ดูโน่ได้โดยตรง ซึ่งสามารถรับค่า หรือส่งออกค่าผ่านทาง Pin ของอาร์ดูโน่ได้เลย โดยไม่ต้องไปแยกเขียนโปรแกรมลงในบอร์ดอาร์ดูโน่ต่างหาก ซึ่งมันมีข้อดีคือใช้งานง่าย และผู้ใช้งานไม่จำเป็นต้องเขียนโค้ดอะไรเลย ส่วนข้อเสียของมันก็คือ หาก Simulink หยุดรัน บอร์ดอาร์ดูโน่ก็จะหยุดทำงานเช่นกัน และในบางครั้ง Simulink ก็ไม่สามารถอัดโปรแกรมลงบอร์ดอาร์ดูโน่ได้ด้วยสาเหตุหลายๆ อย่าง
ดังนั้นในบทความนี้ ผมจึงจะแนะนำการเชื่อมต่อ Simulink กับบอร์ดอาร์ดูโน่ ผ่าน Serial Port ซึ่งเป็นการเชื่อมต่อโดยตรง เราจึงไม่ต้องปวดหัวกับปัญหา Error ต่างๆ ที่ Simulink อัดโปรแกรมลงบอร์ดอาร์ดูโน่ไม่ได้
แต่วิธีนี้ก็ค่อนข้างยุ่งยากเล็กน้อย เพราะเราต้องเขียนโปรแกรมในฝั่งของอาร์ดูโน่เอง
ก่อนอื่นเราไปดูไดอะแกรมของ Simulink และการกำหนดค่ากันก่อนนะครับ
ตรงส่วนของ Sample time: ผมใส่เป็น inf เอาไว้ หมายความว่าบล็อคนี้จะส่งค่าออกไปตลอดเวลาที่โปรแกรมรันอยู่ ซึ่งถ้าหากเราปรับเปลี่ยนค่า Constant value ในระหว่างที่รันโปรแกรมอยู่ ค่านั้นก็จะถูกส่งออกไปเช่นกัน แต่ถ้าเกิดตั้งเป็นค่าอื่นเช่น 1 เมื่อโปรแกรมรันเกิน 1 วินาที ค่าก็จะไม่ถูกส่งออกไปจากบล็อคนี้อีก
ส่วน Output data type ให้กำหนดเป็น single นะครับ ถ้ากำหนดเป็นประเภทอื่น ฝั่งอาร์ดูโน่ที่คอยรับค่าอยู่จะอ่านไม่ได้
การตั้งค่า Terminator นี่สำคัญนะครับ เพราะในฝั่งอาร์ดูโน่ เราก็จะตรวจจับสัญลักษณ์ \r\n นี่แหละครับ เพื่อดูว่าข้อความสิ้นสุดหรือยัง
ต่อไปเป็นการตั้งค่าการรันโมเดลครับ
Stop time คือเวลารันโปรแกรม เช่น 10 ก็คือ 10 วินาที ถ้าจะให้รันตลอดก็ใส่เป็น inf
Type ให้ตั้งเป็น Fixed-step ก็คือแต่ละช่วงเวลาในการรันจะห่างเท่าๆ กัน
Solver จะตั้งเป็น auto หรือเลือกอะไรก็ได้ครับ ซึ่งแต่ละแบบจะทำให้โปรแกรมรันได้ ช้า-เร็ว แตกต่างกัน ดังนั้นหากโปรแกรมรันได้ช้า ก็ลองมาเปลี่ยนชนิดของ Solver ดู
เพียงเท่านี้โปรแกรมฝั่ง Simulink ก็พร้อมส่งข้อมูลแล้วครับ
ต่อไปเป็นโปรแกรมที่ต้องเขียนฝั่งอาร์ดูโน่นะครับ
//แปลงข้อมูลจาก byte เป็น float
union BtoF{
byte b[50];
float k;
} c;//ประกาศตัวแปร
float Value, A;
const int buffer_size = 50;
byte buf[buffer_size];//กำหนดความเร็วการสื่อสารของ Serial port และกำหนด Pin output ของอาร์ดูโน่
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
pinMode(46, OUTPUT);
pinMode(48, OUTPUT);
pinMode(50, OUTPUT);
pinMode(52, OUTPUT);
Value = 100;
}//ลูปการทำงานหลักของโปรแกรม
void loop() {
// Process if serial available
if(Serial.available()>0){
int rlen = Serial.readBytesUntil("\r\n", buf, buffer_size);
for(int i = 0; i < rlen; i++){
c.b[i] = buf[i];
}
A = c.k;
if(A>0){
Value = A;
writeToMatlab(Value);
}
}
if(Value>0){
LEDBlink(Value);
}
}//ฟังก์ชันไฟกระพริบ โดย LED แต่ละดวงจะไฟติดไล่กันไปตามตัวอย่างผลรัน
void LEDBlink(float DELAY){
digitalWrite(46, HIGH);
digitalWrite(52, LOW);
delay(DELAY);
digitalWrite(46, LOW);
digitalWrite(48, HIGH);
delay(DELAY);
digitalWrite(48, LOW);
digitalWrite(50, HIGH);
delay(DELAY);
digitalWrite(50, LOW);
digitalWrite(52, HIGH);
delay(DELAY);
}//ฟังก์ชันส่งค่ากลับให้ Simulink
void writeToMatlab(float number){
byte *b = (byte *) &number;
Serial.write(b, 4);
Serial.write(13); // "\r" CR
Serial.write(10); // "\n" LF
}
เมื่อเขียนเสร็จแล้วก็คอมไพล์แล้วอัดลงบอร์ดอาร์ดูโน่ได้เลยครับ
เมื่ออัดเสร็จแล้วก็กดรันโปรแกรม Simulink ได้เลย
การแก้ปัญหาเมื่อโปรแกรมส่งหรือรับค่าไม่ได้
- เช็คว่าโปรแกรมฝั่งอาร์ดูโน่รับค่าได้ไหม โดยใช้โค้ดดังนี้
const int buffer_size = 50;
byte buf[buffer_size];void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
}void loop() {
// Process if serial available
if(Serial.available()>0){
int rlen = Serial.readBytesUntil("\r\n", buf, buffer_size);
for(int i = 0; i < rlen; i++){
Serial.write(buf[i]);
}
}
}
โปรแกรมนี้จะทำการส่งค่าที่รับได้กลับไปทันที โดยไม่มีการแปลงค่าหรือการคำนวณใดๆ ดังนั้นหาก Simulink ยังรับค่าไม่ได้แสดงว่าเป็นที่ฝั่ง Simulink ที่มีปัญหา
2. เช็คการตั้งค่าในโปรแกรม Simulink
2.1 เช็ค Time out ใน Serial Configuration โดยให้ลองเพิ่มค่า Time out ดูก่อน เพราะว่าค่า Time out อาจจะน้อยเกินไป โปรแกรมยังรับข้อมูลได้ไม่หมด ก็หมดเวลาเสียก่อน
2.2 เช็ค Output data type ของแต่ละบล็อคว่าเป็น Single หรือไม่ เพราะถ้าเป็นประเภทอื่น ฝั่งอาร์ดูโน่จะอ่านค่าไม่ได้
2.3 ตรวจสอบไดอะแกรม Simulink ว่าค่าที่ออกไปในแต่ละบล็อคถูกต้องหรือไม่ และอย่าลืมคำนึงถึง Delay time ของฮาร์ดแวร์ทำงานด้วย ตัวอย่างเช่น
ความหมายของบล็อคข้างต้นก็คือ ผู้เขียนโปรแกรมตั้งใจจะให้ output แสดงค่าออกมาก็ต่อเมื่อค่าที่รับได้จาก Serial Port มีค่ามากกว่า 0 ถ้าหากมีค่าเท่ากับหรือน้อยกว่า 0 ให้แสดงค่าเป็น -1
ซึ่งการเขียนบล็อคเช่นนี้ ไม่มีส่วนไหนที่ผิดเลย แต่ output ที่ได้จะเป็น -1 เสมอ แต่ที่เป็นเช่นนั้น ไม่ใช่เพราะว่า Serial Receive รับค่าไม่ได้ แต่มันต้องใช้เวลารับค่าต่างหาก ซึ่งไม่เหมือนกับ Constant1 ที่สามารถส่งค่าออกได้ทันที ดังนั้น output ที่ได้จึงเป็น -1 เสมอ
2.4 ฝั่งอาร์ดูโน่ต้องรับค่าเป็น byte เท่านั้นนะครับ ถ้าอยากเปลี่ยนเป็นประเภทอื่นค่อยเอาไปแปลงทีหลัง ส่วนประเภทตัวแปรที่ส่งให้ฟังก์ชัน writeToMatlab ก็ต้องเป็นชนิด float เท่านั้น ข้อมูลถึงจะส่งได้ และฝั่ง Simulink ถึงจะรับและอ่านรู้เรื่อง
สรุป
การสื่อสารระหว่าง Simulink และ อาร์ดูโน่ ผ่าน Serial port สามารถทำได้ โดยไม่ต้องติดตั้งแพ็คเก็จเสริมใดๆ ใน Simulink เพียงแต่ต้องเขียนโปรแกรมรับค่าในฝั่งอาร์ดูโน่ด้วย ซึ่งการเขียนโปรแกรมแบบนี้มีข้อดีคือ ถึงแม้ว่า Simulink จะหยุดรันไปแล้ว แต่โปรแกรมฝั่งอาร์ดูโน่ก็จะยังทำงานต่อไป ตราบใดที่เรายังจ่ายไฟเลี้ยงให้มันอยู่