กลับไปหน้ารวมไฟล์
f1-in-schools-car-safety-modulation-0fcb82.md

สวัสดีน้องๆ! พี่ชื่อนิโคลัส เป็นนักเรียน Year 10 ที่ออสเตรเลีย

พูดตรงๆ พี่ก็ยังใหม่กับเรื่องโปรแกรมมิ่งและอิเล็กทรอนิกส์อยู่เหมือนกัน ปีนี้ครูเปิดคลาส STEM สำหรับเด็กสายช่าง/วิศวะ (ส่วนใหญ่) ขึ้นมา เรากำลังทำโปรเจคแรกกัน ซึ่งมันคือ:

  1. พิมพ์รถแข่ง 3D (ให้ตรงตามมาตรฐาน F1 in Schools ของออสเตรเลีย)
  2. สร้างการปรับแต่ง (modification) เพื่อให้รถปลอดภัยขึ้นสำหรับผู้โดยสารสมมติ พร้อมบันทึกข้อมูลระหว่างการวิ่ง (ลงจากราง) เพื่อพิสูจน์ว่าการเปลี่ยนแปลงนั้นทำให้ปลอดภัยขึ้นจริง

แต่ปัญหาคือ ทั้งห้อง (รวมถึงครู) ประสบการณ์ด้านโปรแกรมมิ่งสำหรับ Arduino น้อยมาก โดยเฉพาะ กำลังต้องการความช่วยเหลืออยู่

ปัญหาหลักอยู่ที่การบันทึกข้อมูลเพื่อเปรียบเทียบ เราติดตั้ง Adafruit Feather 32u4 Adalogger ลงในรถคันจิ๋วเพื่อบันทึกข้อมูลขณะวิ่งลงราง เพื่อคำนวณค่าจีโรสโคป (gyroscope) และความเร่ง (acceleration) ของรถ และดูการเปลี่ยนแปลงเมื่อเราทำการปรับแต่ง

สู้กับแรง G สูง: ความปลอดภัยผ่านการบันทึกข้อมูลระยะไกล (Telemetry)

ในโลกของ F1 in Schools รถสามารถทำความเร็วได้อย่างเหลือเชื่อในระยะทางแค่ 20 เมตร ซึ่งส่งผลให้โครงสร้างรถโมเดลต้องรับแรง G ที่มหาศาล โปรเจคนี้ไม่ได้แค่ทำรถให้สวย แต่ใช้ การปรับแต่งเชิงกล (Mechanical Modulation) เพื่อเพิ่มความปลอดภัยให้ผู้โดยสาร ด้วยการบันทึกข้อมูลความเร็วสูงระหว่างการวิ่ง ทีมงานจะสามารถพิสูจน์ได้อย่างชัดเจนว่าการเปลี่ยนแปลงโครงสร้างส่งผลต่อแรงที่กระทำภายในรถอย่างไร ระหว่างการเร่งและเบรกอย่างรวดเร็ว

Adalogger Stack: บันทึกข้อมูลแบบครบวงจรในตัวเดียว

เพื่อให้รถเบาแต่ยังบันทึกข้อมูลได้ โปรเจคนี้ใช้ Adafruit Feather 32u4 Adalogger:

  • ช่องเสียบ SD Card ในตัว: ไม่เหมือน Arduino Uno ทั่วไป Adalogger มีช่องเสียบ microSD card ในตัวที่เชื่อมต่อผ่าน SPI bus ทำให้ไม่ต้องเดินสายซับซ้อน และลด "น้ำหนักบรรทุก" ของรถ เพื่อให้มันยังแข่งบนรางได้อย่างมีประสิทธิภาพ
  • จัดการแบตเตอรี่: Feather มีขั้วต่อ JST สำหรับ แบตเตอรี่ LiPo ทำให้ระบบ telemetry ทำงานแบบไร้สายภายในโครงสร้างรถที่พิมพ์จาก 3D printer ได้

การวัดความเฉื่อยด้วย MPU-6050

"คะแนนความปลอดภัย" ของรถคำนวณมาจาก MPU-6050 อุปกรณ์ติดตามการเคลื่อนที่ 6 แกน:

  1. Accelerometer 3 แกน: วัดแรงเชิงเส้น (หน่วย G) ตามแกน X, Y และ Z สำคัญมากสำหรับการวัด "แรงกระชาก" ขณะที่หัวกระสุน CO2 ถูกยิงออก
  2. Gyroscope 3 แกน: ตรวจจับการเคลื่อนที่แบบหมุน ถ้ารถเกิดอาการ "โคลงเคลง" ที่ความเร็วสูง Gyroscope จะบันทึกความถี่ของการสั่นสะเทือนนั้น ช่วยให้นักวิศวะปรับแต่งอากาศพลศาสตร์ (aerodynamics) ของตัวรถที่พิมพ์จาก 3D printer ได้
  3. การเชื่อมต่อ I2C ความเร็วสูง: MPU-6050 ติดต่อกับ Feather ผ่านไลบรารี Wire.h โปรเจคนี้จัดการข้อมูลไบนารีดิบ 14 ไบต์ ทุกๆ 50ms เพื่อให้แน่ใจว่าข้อมูลการวิ่งที่สั้นที่สุดก็ถูกบันทึกด้วยความละเอียดสูง

ตามหาบั๊กในลูปข้อมูล (Troubleshooting the Data Loop)

ปัญหาหลักๆ ที่เจอในโปรเจคนี้ก็คือเรื่อง ความเสถียรของการอ่านเขียนไฟล์ (File I/O Stability) นี่แหละ:

  • จัดฟอร์แมต CSV: โค้ดเราตั้งใจให้มันเขียนข้อมูลเป็นฟอร์แมตที่คั่นด้วยจุลภาค (datalog.txt) ไว้เลย พอแข่งเสร็จ น้องๆ ก็แค่ถอดการ์ด SD ออก แล้วดึงข้อมูลเข้า Excel หรือ Google Sheets ได้ทันที เพื่อไปทำ กราฟเปรียบเทียบความปลอดภัย สวยๆ
  • ตั้งค่า SD: ต้องระวังให้ดี เพราะบอร์ด Feather มันใช้ขา (Pin) คนละแบบกับ Arduino Uno ทั่วไป (โดยเฉพาะ ขาที่ 4 สำหรับ Chip Select) โปรเจคนี้เลยเป็นบทเรียนสำคัญเรื่องการเช็คฮาร์ดแวร์ให้ชัวร์ และต้องมั่นใจว่าได้ฟอร์แมตการ์ด SD เป็น FAT16/FAT32 ก่อนรันโค้ดทุกครั้ง

ตอนนี้เรากำลังเจอปัญหาว่าโค้ดมันบันทึกข้อมูลลงการ์ด SD ไม่ได้ตามที่คิดไว้ โค้ดที่เรามีตอนนี้หน้าตาเป็นแบบนี้:

// (c) Michael Schoeffler 2017

#include "Wire.h" // This library allows you to communicate with I2C devices.
#include <SPI.h>
#include <SD.h>

const int MPU_ADDR = 0x68; // I2C address of the MPU-6050. If AD0 pin is set to HIGH, the I2C address will be 0x69.

int16_t accelerometer_x, accelerometer_y, accelerometer_z; // variables for accelerometer raw data
int16_t gyro_x, gyro_y, gyro_z; // variables for gyro raw data
int16_t temperature; // variables for temperature data

char tmp_str[7]; // temporary variable used in convert function

char* convert_int16_to_str(int16_t i) { // converts int16 to string. Moreover, resulting strings will have the same length in the debug monitor.
  sprintf(tmp_str, "%6d", i);
  return tmp_str;
const int chipSelect = 4;
}

void setup() {
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  Serial.print("Initializing SD card...");
  // see if the card is present and can be initialized:
  if (!SD.begin(4)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    while (1);
  }
  Serial.println("card initialized.");
  Wire.begin();
  Wire.beginTransmission(MPU_ADDR); // Begins a transmission to the I2C slave (GY-521 board)
  Wire.write(0x6B); // PWR_MGMT_1 register
  Wire.write(0); // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);
}

void loop() {
  // make a string for assembling the data to log:
  String dataString = "";
  // read three sensors and append to the string:
  for (int analogPin = 0; analogPin < 3; analogPin++) {
    int sensor = analogRead(analogPin);
    dataString += String(sensor);
    if (analogPin < 2) {
      dataString += ", ";
    }
  }
  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  File dataFile = SD.open("datalog.txt", FILE_WRITE);
  // if the file is available, write to it:
  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
    // print to the serial port too:
    Serial.println(dataString);
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.txt");
  }

  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H) [MPU-6000 and MPU-6050 Register Map and Descriptions Revision 4.2, p.40]
  Wire.endTransmission(false); // the parameter indicates that the Arduino will send a restart. As a result, the connection is kept active.
  Wire.requestFrom(MPU_ADDR, 7*2, true); // request a total of 7*2=14 registers

  // "Wire.read()<<8 | Wire.read();" means two registers are read and stored in the same variable
  accelerometer_x = Wire.read()<<8 | Wire.read(); // reading registers: 0x3B (ACCEL_XOUT_H) and 0x3C (ACCEL_XOUT_L)
  accelerometer_y = Wire.read()<<8 | Wire.read(); // reading registers: 0x3D (ACCEL_YOUT_H) and 0x3E (ACCEL_YOUT_L)
  accelerometer_z = Wire.read()<<8 | Wire.read(); // reading registers: 0x3F (ACCEL_ZOUT_H) and 0x40 (ACCEL_ZOUT_L)
  temperature = Wire.read()<<8 | Wire.read(); // reading registers: 0x41 (TEMP_OUT_H) and 0x42 (TEMP_OUT_L)
  gyro_x = Wire.read()<<8 | Wire.read(); // reading registers: 0x43 (GYRO_XOUT_H) and 0x44 (GYRO_XOUT_L)
gyro_y = Wire.read()<<8 | Wire.read(); // อ่านค่าจากรีจิสเตอร์: 0x45 (GYRO_YOUT_H) และ 0x46 (GYRO_YOUT_L)
  gyro_z = Wire.read()<<8 | Wire.read(); // อ่านค่าจากรีจิสเตอร์: 0x47 (GYRO_ZOUT_H) และ 0x48 (GYRO_ZOUT_H)

  // พิมพ์ค่าออกมาให้ดูหน่อย
  Serial.print("aX = "); Serial.print(convert_int16_to_str(accelerometer_x));
  Serial.print(" | aY = "); Serial.print(convert_int16_to_str(accelerometer_y));
  Serial.print(" | aZ = "); Serial.print(convert_int16_to_str(accelerometer_z));
  // สูตรนี้เอามาจากคู่มือนะจ๊ะ [MPU-6000/MPU-6050 Register Map and Description, p.30]
  Serial.print(" | tmp = "); Serial.print(temperature/340.00+36.53);
  Serial.print(" | gX = "); Serial.print(convert_int16_to_str(gyro_x));
  Serial.print(" | gY = "); Serial.print(convert_int16_to_str(gyro_y));
  Serial.print(" | gZ = "); Serial.print(convert_int16_to_str(gyro_z));
  Serial.println();

  // รอหน่อย เดี๋ยวเซนเซอร์ช็อต
  delay(50);
}

ถ้าใครรู้ว่าผิดพลาดตรงไหน ช่วยบอกพี่หน่อยนะน้อง ขอบคุณล่วงหน้าจ้า!

โปรเจคนี้แหละตัวดี เป็นตัวอย่างของ STEM Methodology แบบจัดเต็ม: ใช้ 3D printing ในการสร้างชิ้นงาน ใช้ความรู้ด้านอิเล็กทรอนิกส์ในการเก็บข้อมูล และใช้ซอฟต์แวร์ในการวิเคราะห์เปรียบเทียบ เพื่อแก้ปัญหาด้านวิศวกรรมความปลอดภัยในชีวิตจริง สู้งานนะน้อง!

ข้อมูล Frontmatter ดั้งเดิม

apps:
  - "1x Arduino IDE"
author: "nicholasdsilva"
category: "Transportation"
components:
  - "1x Adafruit Feather 32u4 Adalogger"
  - "1x MPU-6050 Accelerometer & Gyroscope"
  - "1x MicroSD Card (8GB+ recommended)"
  - "1x 3.7V Lithium Polymer (LiPo) Battery"
  - "1x 3D Printed F1 Chassis"
description: "ลงโค้ดให้ Adafruit Feather 32u4 อ่านค่าจากเซนเซอร์ แล้วบันทึกข้อมูลความเร่งกับค่ากายโรลง SD Card ไว้วิเคราะห์ งานง่ายแต่หล่อ จัดไป!"
difficulty: "Intermediate"
documentationLinks: []
downloadableFiles:
  - "https://projects.arduinocontent.cc/d68b89a5-849a-4b4a-8dd1-f9842d7a3ee3.ino"
  - "https://projects.arduinocontent.cc/d68b89a5-849a-4b4a-8dd1-f9842d7a3ee3.ino"
encryptedPayload: "U2FsdGVkX196aywsrrvKaqQNIqOBb2X7x54isBJkJWeyOgkopIcyFWxKMC39+3sX03vsM+WB5ClkzqCQ+48O0i4VrMT8RIGOr/XfIJYdRUg="
heroImage: "https://cdn.jsdelivr.net/gh/bigboxthailand/arduino-assets@main/images/projects/f1-in-schools-car-safety-modulation-0fcb82_cover.jpg"
lang: "en"
likes: 1
passwordHash: "b6db70d67965f4368a1d932e657bd851ca291c8a0b546a40f4efe1bef0588bda"
price: 1999
seoDescription: "Data-driven safety modulation for F1 in Schools cars. Learn to log MPU-6050 inertial data to an SD card using the Adafruit Feather 32u4."
tags:
  - "data-logging"
  - "telemetry"
  - "f1-in-schools"
  - "mpu6050"
  - "safety-engineering"
title: "โปรเจค F1 in Schools - ระบบเซฟตี้ตึงๆ สำหรับรถแข่งวัยรุ่น"
tools: []
videoLinks: []
views: 1579