Tạo một quy trình công nghiệp với các bước bằng Arduino - Phần 2: công việc có điều kiện

I. Giới thiệu

Ở bài viết trước, mình đã đề cập đến vấn đề là "Làm thế nào để xây dựng một quy trình công nghiệp trên Arduino". Ở bài viết đó, mình đã đề cập đến vấn đề quy trình tuần tự không điều kiện, và với sự hưởng ứng từ Cộng đồng qua vấn đề làm một máy công nghiệp dùng để sản xuất sản xuất thành phẩm, mình muốn đóng góp một cái gì đó để dự án này hoàn thiện, đó cũng làm một cách để rèn luyện khả năng xử lý vấn đề thông qua mô tả mà không trực tiếp "chạy" máy devil! Vấn đề mình muốn giải quyết đó là xây dựng một quy trình công nghiệp có điều kiện.

II. Bài toán đặt ra

Bạn cần đọc kĩ và thực hành ở bài Tạo một quy trình công nghiệp với các bước bằng Arduino trước khi đọc tiếp, vì như vậy bạn mới thấy được những khó khăn trong bài viết đó. Từ đó, cảm nhận những thay đổi trong bài viết này.

Ngoài ra, bạn có thể download bộ thư viện tại đây và tạo một sketch mới sau đó paste vào hoặc donwload sketch mẫu tại đây. Mình chưa tạo một thư viện hoàn toàn vì muốn các bạn trải nghiệm trước từ đó đóng góp hơn nữa, mình vẫn thấy nó còn thiếu một điều gì đó cool.

Bài toán thực tế được đưa ra là, làm thế nào để điều khiển nhiều động cơ bước, trong đó, động cơ bước kia phải hoạt động rồi mới đến lượt động cơ bước này. Bài toán này không khó nếu chỉ có 2 hay 3 động cơ bước. Nhưng với 7, 8 động cơ bước thì việc biết chính xác lúc nào động cơ kia được chạy quả không phải là một điều đơn giản cho việc code theo hướng thủ tục. Ở bài viết trước, mình có nói đến quy trình công nghiệp, nhưng rõ ràng là nó không thực tế tí nào, vì nó không quan tâm đến công việc kia đã hoàn thành hay chưa, chỉ cần đến đúng lúc thì nó chạy :D. Có thể nó phù hợp với công việc quét LED hơn chăng crying?

Bài toán đặt ra là: thư viện phải biết khi nào bước đó được hoạt động, nghĩa là thêm điều kiện để kiểm tra bước đó được phép hoạt động hay không? Nhưng chưa cần giải quyết rẻ nhánh (nếu không được trong bao lâu đó thì rẻ nhánh sang bước khác) devil.

III. Giải quyết vấn đề

Ta có thể dễ dàng thấy rằng vấn đề này rất giống với vấn đề trước chỉ khác ở chỗ xác định đươc "thời điểm kết thúc chinh xác". Như vậy, mình sẽ thiết kế một hướng đối tượng tên kIndustryCalendar kế thừa đối tượng kCalendar đã có để tiết kiệm thời gian ngồi gõ code devil.

Về cơ bản đối tượng kIndustryCalendar giống với kCalendar hết, vì vậy, các lưu ý sẽ được giữ nguyên không thay đổi gì, mình chỉ nói những thay đổi mới thôi nhé.

Khác với kCalendar, bạn phải tính toán thời điểm chính xác trong quy trình của bước đó, thì ở lớp kIndustryCalendar bạn chỉ cần xác định khoảng thời gian giữa bước thứ i - 1 và bước thứ i, hoặc là xác định điều kiện để bước thứ i được thực hiện heart.

IV. Lập trình

Để hiểu rõ hơn, bạn xem đoạn code mẫu mình đã viết như sau.

#include "Timer.h"
#include "kIndustryCalendar.h"



//job1
void job1() {
	unsigned long time = millis();
	Serial.print("Job1: ");
	Serial.println(time);
}

//job2
void job2() {
	unsigned long time = millis();
	Serial.print("Job2: ");
	Serial.println(time);
}

void job3() {
	Serial.println("Ban da nhan phim tren Serial");
}

bool waitForSerial() {
  bool res = Serial.available();
  //xóa hết buffer của Serial
  while (Serial.available())
    Serial.read();
  return res;
}

void setup()
{
	
	//Khởi tạo serial ở mức baudrate 115200
	Serial.begin(115200);

	//Khởi gạo class timer (design pattern singleton) - bắt buộc phải có trong hàm setup (trước khi khởi tạo các job)
	Timer::getInstance()->initialize();

	//Khởi tạo lịch, các công việc phải được sắp xếp theo chiều thời gian tăng dần để tránh lỗi
	kIndustryCalendar::getInstance()->initialize();
	//Chạy lệnh job1 ở thời điểm 0 trong chu kỳ
	kIndustryCalendar::getInstance()->addJob(job1, (unsigned long)0);
	//Chạy lệnh job2 ở thời điểm 1000ms trong chu kỳ
	kIndustryCalendar::getInstance()->addJob(job2, (unsigned long)1000);

    //Job3 sẽ chỉ được thực hiện khi bạn gửi một ký tự gì đó qua Serial (bật serial monitor lên và nhấn bất kì rồi ấn Enter :D)
    kIndustryCalendar::getInstance()->addJob(job3, waitForSerial);

	//Bắt đầu tính giờ thời gian của quy trình đầu tiên
	kIndustryCalendar::getInstance()->startFirstJob();
}

//trong hàm loop chỉ nên có những hàm này, bạn muốn viết một chức năng khác? Xin hãy tạo một job và đưa vào thời khóa biểu scheduler như hàm dưới

void loop()
{
	//đầu hàm loop phải có để cập nhập thời điểm diễn ra việc kiểm tra lại các tiến trình
	Timer::getInstance()->update();
	
	kIndustryCalendar::getInstance()->update();

	//cuối hàm loop phải có để cập nhập lại THỜI ĐIỂM (thời điểm chứ ko phải thời gian nha, tuy tiếng Anh chúng đều là time) để cho lần xử lý sau
	Timer::getInstance()->resetTick();
	
}

Giống như thư viện trước, job1 và job2 sẽ lần lượt được thực hiện, nhưng job3 chỉ được thực thi khi job1 đã chạy xong!

Điều khiển động cơ bước như thế nào nhỉ?

Easmple 4 diagram

Mình lắp mạch như trên và thử đọn code này và cảm nhận đoạn code dưới đây nào. Thư viện điều khiển động cơ bước, các bạn download ở đây.

#include "Timer.h"
#include "kIndustryCalendar.h"
#include <AccelStepper.h>

AccelStepper stepper1(1, 9, 8);
AccelStepper stepper2(1, 7, 6);

//job1
void job1() {
    unsigned long time = millis();
    Serial.print("Job1: ");
    Serial.println(time);
    stepper1.moveTo(1000);
}

bool waitJob1Finish() {
    return stepper1.distanceToGo() == 0;
}

//job2
void job2() {
    unsigned long time = millis();
    Serial.print("Job2: ");
    Serial.println(time);
    stepper2.moveTo(-1000);
}

bool waitJob2Finish() {
    return stepper2.distanceToGo() == 0;
}

//job3
void job3() {
    unsigned long time = millis();
    Serial.print("Job3: ");
    Serial.println(time);
    stepper2.moveTo(1000);
    stepper1.moveTo(-1500);
}

bool waitJob3Finish() {
    return (stepper2.distanceToGo() == 0) && (stepper1.distanceToGo() == 0);
}

void jobEnd() {
    //chả làm gì cả, một hàm để đảm bảo được gọi trước khi kết thúc. Hoạt dùng để đếm số lần hoạt động của máy từ đó ra quyết định dừng máy lại :)
}

void setup()
{
    
    //Khởi tạo serial ở mức baudrate 115200
    Serial.begin(115200);
    
    //gán các giá trị tốc độ tối đa và gia tốc khác nhau cho động cơ bước!
    stepper1.setMaxSpeed(300); // tốc độ tối đa
    stepper1.setAcceleration(1000); // gia tốc
    stepper2.setMaxSpeed(200);
    stepper2.setAcceleration(800);
    
    //Khởi gạo class timer (design pattern singleton) - bắt buộc phải có trong hàm setup (trước khi khởi tạo các job)
    Timer::getInstance()->initialize();
    
    //Khởi tạo lịch, các công việc phải được sắp xếp theo chiều thời gian tăng dần để tránh lỗi
    kIndustryCalendar::getInstance()->initialize();
    //Chạy lệnh job1 ở thời điểm 0 trong chu kỳ
    kIndustryCalendar::getInstance()->addJob(job1, (unsigned long)0);
    //Chạy lệnh job2 ở thời điểm 1000ms trong chu kỳ
    kIndustryCalendar::getInstance()->addJob(job2, waitJob1Finish);
    
    kIndustryCalendar::getInstance()->addJob(job3, waitJob2Finish);
    
    kIndustryCalendar::getInstance()->addJob(jobEnd, waitJob3Finish);
    
    //Bắt đầu tính giờ thời gian của quy trình đầu tiên
    kIndustryCalendar::getInstance()->startFirstJob();
}

//trong hàm loop chỉ nên có những hàm này, bạn muốn viết một chức năng khác? Xin hãy tạo một job và đưa vào thời khóa biểu scheduler như hàm dưới

void loop()
{
    //đầu hàm loop phải có để cập nhập thời điểm diễn ra việc kiểm tra lại các tiến trình
    Timer::getInstance()->update();
    
    kIndustryCalendar::getInstance()->update();
    
    //cuối hàm loop phải có để cập nhập lại THỜI ĐIỂM (thời điểm chứ ko phải thời gian nha, tuy tiếng Anh chúng đều là time) để cho lần xử lý sau
    Timer::getInstance()->resetTick();
    stepper1.run();stepper2.run(); //cho 2 động cơ bước chạy
}

V. Kết luận

Thử và cảm nhận và đóng góp ý kiến cho mình dưới mục bình luận nhé. Và đừng quên chụp hình sản phẩm để mình cập nhập vào bài viết nha haha.

lên
11 thành viên đã đánh giá bài viết này hữu ích.
Các dự án được truyền cảm hứng

Select any filter and click on Apply to see results

Các bài viết cùng tác giả

Kết nối điều khiển từ xa sử dụng ESP8266 và Arduino với hệ thống firmware iNut Cảm biến CloudMQTT - 1000 firmware miễn phí

Chuyện kể rằng, có 02 sinh viên Việt Nam, trong lúc làm đồ án đại học kết nối điều khiển từ xa qua Internet. Một người thì chọn phương án truyền thống sử dụng máy tính làm máy chủ và demo các tính năng theo yêu cầu đồ án. Người còn lại biết đến iNut Sensor và tìm cách tối ưu hóa phần mềm và phần cứng nhằm chau chuốt cho đồ án của mình trở nên "xịn" và "nhiều tính năng bá đạo". Đến lúc bảo vệ đồ án, cậu sinh viên 01 cảm thấy choáng ván với muôn vàn vấn đề từ việc nơi trình bày đồ án không có wifi, mạng chập chờn, máy tính mở không lên, đứt cáp biển,... Cuối cùng cũng bảo vệ được với điểm số không ưng ý lắm dù tốn rất nhiều thời gian và công sức. Cậu còn lại nhờ vào việc chau chuốt phần mềm, tối ưu hóa và comment kĩ từng lệnh trong dòng code, viết báo cáo bài bản chuẩn bị slide như ý, dùng điện thoại cài wifi, quét mã QRcode để chia sẻ quyền truy cập đến phần mềm rất chuyên nghiệp, mọi thứ cậu chủ động hoàn toàn mà không bị các vấn đề "học tài thi phận" bủa vây mà kết quả hết sức mĩ mãn, điểm số mĩ miều, kiến thức IoT được chuẩn hóa. Thực vậy, các dự án, đồ án sử dụng nền tảng iNut Platform bên dưới cho phép các bạn sinh viên làm các dự án hết sức hoàn hảo: từ xe điều khiển, bãi giữ xe thông minh, hệ thống máy lạnh, máy bơm, điều hòa thông minh,... do chinh các bạn tự làm nên đã đạt được những điểm số tốt và tuyệt đối. Cũng chính vì thế, iNut JSC (công ty chủ quản của iNut Platform) đã kết hợp với Khu Công nghệ phần mềm - ĐHQGHCM để tổ chức những khóa đào tạo ngắn hạn cho sinh viên Việt Nam sử dụng nền tảng IoT do iNut JSC phát triển. Và để mở con đường tri thức tiếp cận IoT trong nháy mắt, iNut JSC đã tạo ra một phiên bản firmware trị giá 50.000 đồng sử dụng clouding của CloudMQTT và tài trợ 1000 firmware cho tất cả các bạn học sinh, sinh viên Việt Nam có thể tiếp cận IoT một cách dễ dàng và nhanh chóng nhất!

lên
14 thành viên đã đánh giá bài viết này hữu ích.

noTone()

Hàm này có nhiệm vụ kết thúc một sự kiện tone() trên một pin nào đó (đang chạy lệnh tone()). Nếu không có bất kỳ hàm tone() nào đang hoạt động thì hàm này sẽ không gây bất kỳ ảnh hưởng gì đến chương trình.

lên
5 thành viên đã đánh giá bài viết này hữu ích.