Thông báo

Collapse
No announcement yet.

Hiệu ứng LED Cube 8x8x8 (LED 3D)

Collapse
X
 
  • Lọc
  • Giờ
  • Show
Clear All
new posts

  • #31
    Nguyên văn bởi minh_cly Xem bài viết
    Một số lưu ý khi lập trình trên MCU (not for Computer)
    1. Hãy giới hạn tốc độ hiển thị
    Mỗi khung hình hiển thị được gọi là một frame, và con người bình thường chúng ta chỉ có thể nhìn thấy 24-30 frame/s, vì vậy hãy giới hạn tốc độ này ít nhất có thể để có tài nguyên thực hiện những tác vụ khác.
    2. Hãy tính toán frame tiếp theo ngay sau khi chuyển frame
    Một số bạn thường có 1 thói quen thế này:
    Code:
    int fps = 30; // Tốc độ hiển thị
    float t_ref = get_time();
    while (true) { // Bạn nên dùng ngắt timer để giới hạn tốc độ hiển thị
    float t = get_time() - t_ref; if (t > 1.0 / fps) { // Giới hạn tốc độ hiển thị
    // Tính toán hiệu ứng // Thay frame t_ref = get_time();
    }
    }
    Hãy thay nó bằng thế này:
    Code:
    t_ref = get_time();
    // Thay frame
    // Tính toán hiệu ứng
    t_ref và lệnh thay frame cần phải sớm càng tốt để hiển thị đúng thời gian bởi vì chúng ta ko thể bik chính xác đc thuật toán của bạn nặng bao nhiu.
    Một số bạn có thể nói là thuật toán của "tôi" tính sau sau 10ms sau đó hiển thị thì cũng đều thoy, tôi chỉ cần thay t_ref lên đầu, còn lệnh thay frame để cuối vẫn đc. Nhưng các bạn có chắc chắn rằng thuật toán của bạn có tính toán đúng 10ms, vì trong thuật toán của bạn có rất nhìu lệnh if, lệnh for, và những lệnh này có thể làm thay đổi thời gian tính toán rất nhiều.
    3. Nếu thuật toán có SIN hoặc COS, hãy tạo một mảng chứa những giá trị có sẵn
    Việc tính Sin và Cos trên MCU tốn rất nhìu tài nguyên, nhưng chúng ta ko cần sự chính xác cho lắm, bởi vì LED Cube 8x8x8 thì cũng có 8 đơn vị mỗi chìu. Chúng ta nên vào excel, lập ra 1 mảng tên là Sin, Cos để lưu những giá trị tính sẵn. Đừng lo về RAM, vì nếu bạn khai báo đó là const (hằng số), thì dữ liệu sẽ đc lưu trong program memory.
    Kích cỡ của mảng tùy thuộc vào thuật toán và tốc độ hiển thị, có thể đc sử dụng cho nhìu thuật toán khác nhau. Hãy phân tích tham số trong hàm SIN xem có bao nhiu phần tử rời rạc có thể, hay bạn có thể làm gần đúng nó để lấy giá trị gần đúng.
    Ví dụ trong hiệu ứng sóng, SIN có tham số là 2*PI*t/T, với tốc độ hiển thị là 30, và T có giá trị là 2 chẳng hạn, thì 1 chu kỳ mấy 60 frame tương ứng vs các giá trị khác nhau của t/T. Vì vậy hãy tạo 1 mảng 60 để lưu giá trị của Sin và Cos.
    Một ví dụ khác, thuật toán sử dụng mảng Sin 100 phần tử, thuật toán 2 chỉ sử dụng 60. 2 thuật toán có thể share cho nhau một mảng Sin 100 để tiết kiệm tài nguyên. Nếu thuật toán 1 ko yêu cầu độ chính xác cao, 2 thuật toán có thể sử dụng chung mảng 60 hay thấp hơn cũng được.
    tạo hàm get_time() bằng cách nào bạn nhỉ?

    Comment


    • #32
      Nguyên văn bởi minh_cly Xem bài viết
      Đề nghị mún hỏi cách gì thêm thì nhấn vào sửa bài viết, ko có spam như thế.
      Câu thứ nhất, cái gì máy in lazer ở đây, máy in lazer in xong ra tờ giấy bác mới thấy mà, chứ bác đâu có chui vào đó để xem trực tiếp.
      Câu thứ hai, quét kiểu đấy thì đương nhiên code dài lên, nhưng nhìn kiểu "code dài thì ngán" như bác thì tôi nói bác làm ko xong cái cube này đâu.
      Câu thứ ba, máy quay phim chỉ quay đc 30fps thoy, bác cần loại máy xịn thì có cơ may quay đc từng lớp, mà bằng chứng là cái video tôi quay đấy, có bị gì đâu (Webcam tôi cùi, có 15fps àh).
      Câu thứ tư, Quét như thế hả, tôi cho delay là 200us đấy, tức 0,2ms cho từng lớp, chấp bác nào dùng máy thường quay nổi đấy.
      cube bạn quét lớp à, mình quét cột có lẽ như vậy tần số quét lớn nên led không sáng cho lắm

      Comment


      • #33
        Nguyên văn bởi pdsu Xem bài viết
        tạo hàm get_time() bằng cách nào bạn nhỉ?
        Một ví dụ khá đơn giản là như thế này:
        Cách 1: Ngắt timer, nhân biến đếm với thời gian tràn để tính ra thời gian.
        Cách 2: Chạy timer, đọc giá trị từ timer rồi sau đó tính thêm số lần tràn và thời gian tràn để biết đc thời gian.
        Có thể reset timer tùy ý miễn là chúng ta có thể tính đúng hiệu ứng là được. Thuật toán phải linh hoạt chứ ko thể cố định 1 kiểu đc.
        Computer Science major - Vietnamese-German University
        Sponsored by

        Comment


        • #34
          Có bạn nào bít cách quét 3bit x y z không chỉ cho mình với, search google hoài mà ko thấy

          Comment


          • #35
            đơn giản là thế này:
            Vi điều khiển sẽ dùng 3 PORT điều khiển tương ứng với 3 trục tọa độ trên khối LED3CHIEU , phần còn lại là dùng chính những con IC số , IC đệm , Transistor để tự động giải mã ra con LED bất kỳ trong khối LED3D. Ngoài ra còn cho phép lập trình theo kiểu quét tùy biến như : quét X và Y xuất dữ liệu ra Z , quét X và Z xuất dữ liệu ra Y , quét Y và Z xuất dữ liệu ra X ,...
            Phần cứng thì có rất nhiều kiểu thiết kế khác nhau tùy theo mỗi người thôi !!!
            Dạo này đang bận, vài bữa sẽ viết bài giới thiệu qua các kiểu thiết kế này, không chỉ áp dụng cho 3D mà cả 2D , 1D cũng có thể dùng cách này...

            Comment


            • #36
              Nguyên văn bởi minh_cly Xem bài viết
              Hiệu ứng sóng:
              Hiệu ứng này mô tả một điểm dao động theo hàm sin làm mặt phẳng xung quanh dao động theo gây nên cảm giác sóng. Hiệu ứng này e góp nhặt trên trang instructable và đc nhiều ng xài vì tính đơn giản nhưng đẹp của nó.

              Cơ bản về thuật toán:
              Gọi chu kỳ sóng là T, bước sóng L, biên độ A.
              • Chọn một điểm trong mặt phẳng xy làm gốc, đặt tên là O
              • Quét tất cả mọi điểm trong mặt phẳng xy, gọi từng điểm là A
              • Tính khoảng cách AO theo định lý Pytago, gọi là R
              • Dùng công thức sóng u = A*Cos (2*PI*t/T - 2*PI*R/L)
              • Add từng điểm vào mảng sáng

              Vs 8x8x8, L là 7, A là 3.5, tọa độ O là (3.5, 3.5), còn T là 1s. Việc lấy t tùy vào cách các bạn lấy, có thể dùng timer, có thể đếm frame.

              Code C:
              Code:
              float L = 7; // Bước sóng
              float T = 1; // Chu kỳ
              float A = 3.5; // Biên độ
              float xo = 3.5; // Tọa độ điểm gốc O
              float yo = 3.5;
              
              for (byte y = 0; y < 8; y++) // Quét Y
              {
                  for (byte x = 0; x < 8; x++) // Quét X
                  {
                      float r = Sqrt(Pow(x - xo, 2) + Pow(y - yo, 2)); // Lấy bán kính, Sqrt là căn bậc 2, Pow(x, y) là x mũ y
                      float t = get_time(); // Lấy thời gian
                      byte z = (byte)(A * Cos(2*PI*t/T - 2*PI*r/L) + 3.5); // Lấy cao độ z, 3.5 là vị trí cân bằng
                      Add(x, y, z); // Lưu vị trí LED sáng
                  }
              }
              Mình có một thắc mắc bạn giải thích giùm, sau mỗi lần quét đến điểm x,y ta sẽ tính đc độ cao z rồi lệnh bật led sáng với độ cao z tại toa độ x,y đó, vậy thì đến lần quết sau lại bật sáng cho độ cao z khác vẫn với tọa độ x,y đó mà ko tắt cái led sáng trc đó đi thì sẽ có nhiều led đc bật sáng sau nhiều lần quét, việc xóa cái cũ đi thực hiện dựa vào đâu , cảm ởn bạn giải thích

              Comment


              • #37
                Nguyên văn bởi sinhluc Xem bài viết
                Mình có một thắc mắc bạn giải thích giùm, sau mỗi lần quét đến điểm x,y ta sẽ tính đc độ cao z rồi lệnh bật led sáng với độ cao z tại toa độ x,y đó, vậy thì đến lần quết sau lại bật sáng cho độ cao z khác vẫn với tọa độ x,y đó mà ko tắt cái led sáng trc đó đi thì sẽ có nhiều led đc bật sáng sau nhiều lần quét, việc xóa cái cũ đi thực hiện dựa vào đâu , cảm ởn bạn giải thích
                Phần này mình đầu tiên nên đánh hơi thiếu, thực ra sau mỗi lần thực hiện giải thuật trên, thì phải xóa hết led trong bộ nhớ trước đã òy mới add led mới vào.
                Computer Science major - Vietnamese-German University
                Sponsored by

                Comment


                • #38
                  Nguyên văn bởi minh_cly Xem bài viết
                  Có thể các bạn sẽ thắc mắc, vì sao trong hiệu ứng trên lại dùng 7 và 3.5, trong khi LED Cube là 8x8x8. Bởi vì con số 8 là chỉ số LED 1 hàng, còn khoảng cách giữa chúng chỉ có 7 thoy, và bạn cũng có thể tự hỏi: "Hàng LED nào là hàng LED ngay chính giữa". Kết quả ko phải 3, cũng ko phải 4, nó là 3.5. Bạn nên lưu ý điều này trước khi lập trình hiệu ứng mới.
                  Có thể code mình bị lai một chút của C# và mã .NET, nhưng cơ bản nó là thế. Các bạn thông cảm cho mình là mình lập trình mấy cái đó bằng C#.

                  Hiệu ứng Pháo hoa (Firework)
                  Lại thêm một hiệu ứng trên trang instructable, nhưng hiệu ứng này mình đã rút ra công thức chung cho các bạn (trên trang đó nó chỉ nói dùng vật lý giải ra =="). Hiệu ứng này đẹp bởi vì sự ngẫu nhiên của mỗi lần bắn pháo hoa.

                  Thuật toán cơ bản:
                  Chúng ta có các thông số cơ bản sau: G là gia tốc trọng lực, B là hệ số cản không khí (lực cản F/m = Bv, có B nhìn mới đẹp ^^), n là số phần tử pháo hoa, v_max là vận tốc tối đa của một phần tử.
                  • Dùng Random xác định một điểm xo, yo bất kỳ để phóng pháo hoa. (ko quá sát cạnh)
                  • Điểm đó bay từ từ đến một điểm zo thì bắt đầu nổ. (ko quá cao cũng ko quá thấp)
                  • Tạo một mảng gồm n phần tử, mỗi phần tử đặc trưng cho một phần tử pháo hoa. Dùng Random để xác định vận tốc (từ 0 tới v_max), hướng (gồm 2 thành phần góc cực (vĩ độ) và góc phương vị (kinh độ) trong hệ tọa độ cầu).
                  • Vòng lặp n phần tử, sự dụng cái công thức vật lý sau:
                    • x = xo + (vx / B)*(1-e^(-B*t)) , vx là v theo phương x, trong đó e^ là e mũ, e là hằng số 2.72.
                    • y = yo + (vy / B)*(1-e^(-B*t))
                    • z = zo + (vz / B + G / B^2)*(1-e^(-B*t)) - G*t/B , các bạn có thể tính 1-e^(-B*t) trước sau đó mới lắp vào

                  • Khi tất cả các phần tử đang rơi xuống đất hết (z < 0) thì reset hiệu ứng.


                  Vs LED Cube 8x8x8, đẹp nhất là G = 18, B = 1.05, v_max = 15, n = 40 (MCU nào chậm thì giảm xuống một chút), 2 <= xo, yo <= 6, 5 <= zo <= 7, t là thời gian tính bằng giây, e = 2.718281828.

                  Code C:
                  Chú ý: hàm Random() của mình sẽ tạo ra một số float từ 0 cho đến 1, các bạn tự điều chỉnh vs các compiler khác nhau.
                  Code:
                  float G = 18, B = 1.05, v_max = 15;
                  int n = 40;
                  float vx[40], vy[40], vz[40]; //Ko đủ RAM thì giảm xuống
                  byte xo, yo, zo;
                  float t_ref; // Thời gian bắt đầu
                  bool state = false; //Trạng thái, false là phóng pháo hoa, true là nổ, bool có thể là int1 trong một số compiler
                  
                  // Một vài chương trình con
                  void RandomO() {
                  xo = (byte)(Random() * 4 + 2); // Lấy giá trị từ 2 đến 6 yo = (byte)(Random() * 4 + 2); zo = (byte)(Random() * 2 + 5); // Lấy gia trị từ 5 đến 7
                  } void RandomParticle() {
                  for (int i = 0; i < n; i ++) {
                  float v = Random() * v_max; float pol = Random() * PI / 2; // Góc cực float azi = Random() * 2 * PI; // Góc phương vị vx[i] = v * Cos(pol) * Cos(azi); // Tính toán vx, vy, vz vy[i] = v * Cos(pol) * Sin(azi); vz[i] = v * Sin(pol);
                  }
                  } //Chương trình chính RandomO(); while (true) {
                  t = get_time() - t_ref; //Lấy thời gian if (!state) {
                  float z = t * 15; Add(xo, yo, (byte)z); // Vẽ pháo hoa đang phóng if (z >= zo) {
                  RandomParticle(); // Tạo ra các phần tử random t_ref = get_time(); // Đổi thời gian bắt đầu state = true; // Chuyển trạng thái sang trạng thái nổ
                  }
                  } else {
                  bool reset = true; // Kiểm tra xem có reset hay ko float t_const = 1 - Exp(-B * t); // Hằng số thời gian là như nhau for (int i = 0; i < n; i++) {
                  byte x = (byte)(xo + (vx[i] / B) * t_const); byte y = (byte)(yo + (vy[i] / B) * t_const); byte z = (byte)(zo + (vy[i] / B + G / (B * B)) * t_const - G * t / B); if (z >= 0) reset = false; // Chưa reset vì còn điểm trên 0 if ((x >= 0) && (x <= 7) && (y >= 0) && (y <= 7) && (z >= 0) && (z <= 7)) Add(x, y, z);
                  } if (reset) { // Được reset
                  RandomO(); // Tạo điểm phóng random t_ref = get_time(); // Đổi thời gian bắt đầu state = false; // Chuyển trạng thái sang trạng thái phóng
                  }
                  }
                  }
                  Hy vọng mọi người làm được hiệu ứng này ^^.
                  Bạn cho mình hỏi, hàm random tạo ra bằng cách nào (vi dụ nếu mình dùng avr studio với avr gcc cho atmega128), mình cũng đã xem instructable rồi nhưng vẫn ko hiểu

                  Comment


                  • #39
                    Nguyên văn bởi sinhluc Xem bài viết
                    Bạn cho mình hỏi, hàm random tạo ra bằng cách nào (vi dụ nếu mình dùng avr studio với avr gcc cho atmega128), mình cũng đã xem instructable rồi nhưng vẫn ko hiểu
                    Hàm random() là một hàm tạo sẵn của trình dịch, cố gắng đọc help để bik hàm đó tên gì trong trình dịch của bạn nhá.
                    Computer Science major - Vietnamese-German University
                    Sponsored by

                    Comment


                    • #40
                      sao ko có ai làm cube 8x8x8 bằng asm ak`

                      Comment


                      • #41
                        Làm có mà chết hả bro?

                        Comment


                        • #42
                          ban cho minh hoi trang instructable ma ban noi la j khong
                          minh tim tren web mai ko thay

                          Comment


                          • #43
                            LED Cube 8x8x8
                            Quá dễ kiếm, chịu khó google một tí đi...
                            Computer Science major - Vietnamese-German University
                            Sponsored by

                            Comment


                            • #44
                              các đại ka oy

                              Comment


                              • #45
                                Nguyên văn bởi minh_cly Xem bài viết
                                Một ví dụ khá đơn giản là như thế này:
                                Cách 1: Ngắt timer, nhân biến đếm với thời gian tràn để tính ra thời gian.
                                Cách 2: Chạy timer, đọc giá trị từ timer rồi sau đó tính thêm số lần tràn và thời gian tràn để biết đc thời gian.
                                Có thể reset timer tùy ý miễn là chúng ta có thể tính đúng hiệu ứng là được. Thuật toán phải linh hoạt chứ ko thể cố định 1 kiểu đc.
                                Bạn có thể đưa cho mình tham khảo đoạn code get_time() của bạn được không?
                                Một thắc mắc nữa là hàm add(x,y,z) của bạn sẽ đưa giá trị các biến x, y, z đi đâu? Mình vẫn không hiểu lắm chỗ đó. mong bạn giúp! Nếu được thì mong bạn post đoạn code này lên giúp mình nhé.

                                Comment

                                Về tác giả

                                Collapse

                                minh_cly Tìm hiểu thêm về minh_cly

                                Bài viết mới nhất

                                Collapse

                                Đang tải...
                                X