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
8 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ả

kLaserCutter - Tự làm máy cắt laser bằng mã nguồn người Việt - Phần 2: Máy cắt laser thành thiết bị IOT

Như ở bài viết trước trong chuỗi bài viết về máy cắt laser của mình. Chúng ta đã cùng nhau tìm cách dựng một máy cắt bằng chính khả năng sáng tạo của riêng bản thân mỗi người. Hôm nay, mình xin giới thiệu về cách mà mình đã biến chiếc máy cắt của mình thành một thiết bị IOT. Hay ở chỗ, qua bài viết này, bạn có thể biến bất kỳ chiếc máy cắt laser nào (đã được nạp firmware) trở thành một chiếc bị IOT. Thật hay phải không nào? Còn chần chờ gì nữa, hãy bắt nay vào làm thôi.

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

Arduino Leonardo là gì ?

Chúng ta đã quá quen thuộc với các board mạch Arduino "truyền thống" như Arduino Uno R3, Nano hay phiên bản tối giản là Arduino Pro Mini. Nếu là một người tinh ý, các bạn sẽ dễ dàng nhận thấy board Arduino Leonardo có kích thước giốn với Arduino, pinout cũng tương tự luôn. Thật vậy, với một người yêu thích Arduino, bạn sẽ có một thắc mắc: Tại sao người ta lại làm ra mạch Arduino Leonardo, trong khi nó "khá giống" với Arduino Uno R3, chứ không muốn nói là giống "hệt", liệu nhà phát triển Arduino quá "rãnh"? Vâng, qua bài viết này, bạn sẽ hiểu được vì sao Arduino Leonardo lại ra đời, khi nào nên dùng nó, khi nào không và các thông số kĩ thuật cơ bản.

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