Differences

This shows you the differences between two versions of the page.

Link to this comparison view

pm:prj2023:alucaci:water-refilling-system [2023/05/28 22:03]
robert.popovici
pm:prj2023:alucaci:water-refilling-system [2023/05/29 20:53] (current)
robert.popovici [Bibliografie/Resurse]
Line 88: Line 88:
 === LedMatrix === === LedMatrix ===
  
-Principalul modul folosit pentru a afisa mesaje cu rol informativ legate ​de starea sistemului.+Driver ​folosit pentru a controla matricea de leduri. Acesta poate fi configurat la modul general pentru a controla orice matrice de leduri (indiferent de dimensiune) sau chiar o grupare ​de mai multe matrici.
  
 Componente: Componente:
Line 99: Line 99:
 === Logger === === Logger ===
  
-Driver ​folosit pentru a controla matricea de leduri. Acesta poate fi configurat la modul general pentru a controla orice matrice de leduri (indiferent de dimensiune) sau chiar o grupare ​de mai multe matrici.+Principalul modul folosit pentru a afisa mesaje cu rol informativ legate ​de starea sistemului.
  
 Componente: Componente:
Line 126: Line 126:
   * waterPumpConfig.h   * waterPumpConfig.h
   * waterPumpConfig.cpp   * waterPumpConfig.cpp
- 
-Intregul cod este disponibil [[https://​github.com/​popovicirobert/​PM-WaterRefillingSystem|aici]]: ​ 
  
  
Line 374: Line 372:
 Modulul ledmatrix este alcatui in mod simlar din 2 parti: Modulul ledmatrix este alcatui in mod simlar din 2 parti:
  
-  * In **ledMatrixConfig.cpp** vom initializa driver-ul pentru matricea de leduri. Acesta primeste ca argumente in constructor doi vectori de tipul PinInfo. Primul vector reprezinta pinii care vor controla randurile matricei de leduri, iar al doilea vector reprezinta pinii de pe coloane. Dupa cum se poate vedea implementarea este destul de generica si nu tine cont de dimensiunea matricei.+  * In **ledMatrixConfig.cpp** vom initializa driver-ul pentru matricea de leduri. Acesta primeste ca argumente in constructor doi vectori de tipul PinInfo. Primul vector reprezinta pinii care vor controla randurile matricei de leduri, iar al doilea vector reprezinta pinii de pe coloane. Functia updateLedMatrix este folosita pentru a afisa valoarea tensiunii de pe potentiometru,​ dupa ce o convertim la o valoarea normalizata. Dupa cum se poate vedea implementarea este destul de generica si nu tine cont de dimensiunea matricei
  
 <code cpp> <code cpp>
Line 411: Line 409:
 } }
 </​code>​ </​code>​
 +
 +  * In **ledMatrix.h** avem implementarea efectiva a driver-ului. In functie de sablonul pe care vrem sa-l afisam vom aprinde/​stinge pe rand ledurile din matrice, iar ochiul uman va percepe o iluminare continua datorita frecventei ridicate.
 +
 +<code cpp>
 +template<​size_t _RowSize, size_t _ColSize>​
 +class LedMatrix {
 +private:
 + void setUpLedMatrix() {
 + // set row pins as OUTPUT
 + for (auto pin : this->​getRowPins()) {
 + pin.configure(PinInfo::​PinType::​_OUTPUT);​
 + }
 +
 + // set column pins as OUTPUT
 + for (auto pin : this->​getColPins()) {
 + pin.configure(PinInfo::​PinType::​_OUTPUT);​
 + }
 +
 + // turn off all matrix leds
 + this->​turnAllOff();​
 + }
 +
 + inline void write(PinInfo pin, int value) {
 + pin.write(value);​
 + }
 +
 +public:
 + LedMatrix(const std::​array<​PinInfo,​ _RowSize>&​ rowPins, const std::​array<​PinInfo,​ _ColSize>&​ colPins) ​
 + : rowPins(rowPins),​
 +   colPins(colPins) {
 +  
 + this->​setUpLedMatrix();​
 + }
 +
 + void turnOnLed(int row, int col) {
 + for (int i = 0; i < _ColSize; i++) {
 + if (i != col) {
 + write(colPins[i],​ HIGH);
 + } else {
 + write(colPins[i],​ LOW);
 + }
 + }
 + write(rowPins[row],​ HIGH);
 + }
 +
 + void turnOffLed(int row, int col) {
 + write(rowPins[row],​ LOW);
 + for (int i = 0; i < _ColSize; i++) {
 + write(colPins[i],​ LOW);
 + }
 + }
 +
 + void turnAllOff() {
 + for (auto pin : rowPins) {
 + write(pin,​ LOW);
 + }
 +
 + for (auto pin : colPins) {
 + write(pin,​ LOW);
 + }
 + }
 +
 + const std::​array<​PinInfo,​ _RowSize>&​ getRowPins() {
 + return rowPins;
 + }
 +
 + const std::​array<​PinInfo,​ _ColSize>&​ getColPins() {
 + return colPins;
 + }
 +
 +private:
 + std::​array<​PinInfo,​ _RowSize>​ rowPins;
 + std::​array<​PinInfo,​ _ColSize>​ colPins;
 +};
 +
 +
 +template<​size_t _RowSize, size_t _ColSize>​
 +class LedMatrixDriver : public LedMatrix<​_RowSize,​ _ColSize>​ {
 +public:
 + LedMatrixDriver(const std::​array<​PinInfo,​ _RowSize>&​ rowPins, const std::​array<​PinInfo,​ _ColSize>&​ colPins) ​
 + : LedMatrix<​_RowSize,​ _ColSize>​(rowPins,​ colPins) {}
 +      ​
 + void drawDigit(int digit, int offsetRow, int offsetCol) {
 + for (int r = 0; r < DIGIT_ROWS; r++) {
 + for (int c = 0; c < DIGIT_COLS; c++) {
 + int row = r + offsetRow;
 + int col = c + offsetCol;
 + if (digits[digit][r][c] == '​1'​) {
 + this->​turnOnLed(row,​ col);
 + this->​turnOffLed(row,​ col);
 + }
 + }
 + }
 + }
 +
 + void drawDigit(int digit) {
 + drawDigit(digit,​ 0, 0);
 + }
 +
 + void drawNumber(int number, int offsetRow, int offsetCol) {
 + int firstDigit = number / 10;
 + int secondDigit = number % 10;
 + drawDigit(firstDigit,​ offsetRow, offsetCol);
 + drawDigit(secondDigit,​ offsetRow, offsetCol + DIGIT_COLS + 1);
 + }
 +
 + void drawNumber(int number) {
 + drawNumber(number,​ 0, 0);
 + }
 +};
 +</​code>​
 +
 +Modulul waterpump este folosit pentru a interactiona cu pompa de apa. Acesta expune doua metode startPump si stopPump pentru a porni 
 +respectiv opri pompa.
 +
 +<code cpp>
 +#include "​waterPump.h"​
 +
 +WaterPump::​WaterPump(PinInfo pinInfo) {
 + this->​pinInfo = pinInfo;
 + pinInfo.configure(PinInfo::​PinType::​_OUTPUT);​
 + stopPump();​
 +}
 +
 +void WaterPump::​startPump() {
 + if (state == WorkingState::​RUNNING) {
 + return;
 + }
 + state = WorkingState::​RUNNING;​
 + pinInfo.write(LOW);​
 +}
 +
 +void WaterPump::​stopPump() {
 + pinInfo.write(HIGH);​
 + state = WorkingState::​NOT_RUNNING;​
 +}
 +</​code>​
 +
 +Fisierul **eventHandler.h** contine implementarea message bus-ului folosit pentru a opri pompa o data ce timpul de umplere s-a scurs. Acesta retine intern un set cu toate evenimentele care trebuie planificate sortate dupa timpul de expirare. Atunci cand apelam functia addEvent vom insera un nou eveniment in set, iar la apelarea functiei checkEvents vom scoate toate evenimentele care au expirat ruland in prealabil functiile de callback asociate lor. In implementarea curenta avem cel mult un eveniment activ in set, deoarece ignoram actiunile de apasarea ale butonului atunci cand este deja in functiune. Datorita acestui fapt memoria heap consumata este destul de mica.
 +
 +<code cpp>
 +#pragma once
 +
 +#include <​ArduinoSTL.h>​
 +#include <set>
 +
 +#include "​clock1ms.h"​
 +
 +class EventHandler {
 +public:
 + template<​typename T>
 + void addEvent(long long expireTime, const T& callback) {
 + static long long lastEventId = 0;
 + BaseEvent* event = new Event<​T>​(lastEventId,​ expireTime, callback);
 + lastEventId++;​
 + eventQueue.insert(event);​
 + }
 +
 + void checkEvents() {
 + long long tickCounter = clock_1ms::​getTickCounter();​
 + while (!eventQueue.empty()) {
 + BaseEvent* event = *eventQueue.begin();​
 + if (event->​expireTime <= tickCounter) {
 + eventQueue.erase(eventQueue.begin());​
 + event->​call();​
 + delete event;
 + } else {
 + break;
 + }
 + }
 + }
 +
 +private:
 + struct BaseEvent {
 + long long eventId;
 + long long expireTime;
 +
 + BaseEvent(long long eventId, long long expireTime) {
 + this->​eventId = eventId;
 + this->​expireTime = expireTime;
 + }
 +
 + bool operator<​(const BaseEvent&​ rhs) const {
 + if (expireTime == rhs.expireTime)
 + return eventId < rhs.eventId;​
 + return expireTime < rhs.expireTime;​
 + }
 +
 + virtual void call() {
 + // can't make it pure virtual because we need to use less than operator inside set comparator
 + }
 + };
 +
 + template<​typename T>
 + struct Event : public BaseEvent {
 + const T& callback;
 +
 + Event(long long eventId, long long expireTime, const T& callback) ​
 + : BaseEvent(eventId,​ expireTime),​
 +   callback(callback) {}
 +
 + void call() override {
 + callback();​
 + }
 + };
 +
 +private:
 +
 + struct EventComparator {
 + bool operator()(const BaseEvent* e1, const BaseEvent* e2) const {
 + return *e1 < *e2;
 + }
 + };
 +
 + std::​set<​BaseEvent*,​ EventComparator>​ eventQueue;
 +};
 +</​code>​
 +
 +Fisierul **pinInfo.h** reprezinta un wrapper peste un pin al Arduino. Acesta primeste ca parametrii in constructor pointeri catre registrele DDR, PIN si PORT alea pin-ului si le foloseste mai apoi pentru a scrie valori logice pe pin, sau pentru a configura pin-ul in diverse moduri (INPUT, OUTPUT, INPUT_PULLUP sau INPUT_PULLDOWN).
 +
 +<code cpp>
 +#pragma once
 +
 +#include <​Arduino.h>​
 +
 +struct PinInfo {
 + enum class PinType {
 + _INPUT,
 + _OUTPUT,
 + _INPUT_PULLUP,​
 + _INPUT_PULLDOWN
 + };
 +
 + volatile uint8_t* DDR;
 + volatile uint8_t* PIN;
 + volatile uint8_t* PORT;
 + uint8_t ID;
 +
 + inline volatile uint8_t&​ getDDR() {
 + return *DDR;
 + }
 +
 + inline volatile uint8_t&​ getPIN() {
 + return *PIN;
 + }
 +
 + inline volatile uint8_t&​ getPORT() {
 + return *PORT;
 + }
 +
 + inline uint8_t getID() {
 + return ID;
 + }
 +
 + inline int read() {
 + return getPIN() & (1 << getID());
 + }
 +
 + inline void write(int value) {
 + if (value == LOW) {
 + getPORT() &= ~(1 << getID());
 + } else {
 + getPORT() |= (1 << getID());
 + }
 + }
 +
 + inline int configure(PinType type) {
 + if (type == PinType::​_INPUT) {
 + getDDR() &= ~(1 << getID());
 + } else if (type == PinType::​_OUTPUT) {
 + getDDR() |= (1 << getID());
 + } else if (type == PinType::​_INPUT_PULLUP) {
 + getDDR() &= ~(1 << getID());
 + write(HIGH);​
 + } else if (type == PinType::​_INPUT_PULLDOWN) {
 + getDDR() &= ~(1 << getID());
 + write(LOW);​
 + }
 + }
 +};
 +</​code>​
 +
 +=== Biblioteci ===
 +
 +  * ArduinoSTL
 +
 +
 +=== Mediu de dezvoltare ===
 +
 +Mediul de dezvoltare folosit in realizare proiectului:​ **Arduino IDE**
 +
  
 ===== Rezultate Obţinute ===== ===== Rezultate Obţinute =====
  
-<note tip> + 
-Care au fost rezultatele obţinute în urma realizării proiectului vostru+==== Proiect final ==== 
-</note>+  
 +{{:​pm:​prj2023:​alucaci:​water_refilling_pic1.jpg?687|}} 
 + 
 +{{:​pm:​prj2023:​alucaci:​water_refilling_pic2.jpg?​687|}} 
 + 
 +==== Demo ==== 
 + 
 +Mai multe poze cu circuitul si un cateva filmulete cu scop demonstrativ se pot gasi la acest [[https://​drive.google.com/​drive/​folders/​1DWMVBsoSY0sINrkEvoiq90y-PRJ6FOik?​usp=sharing|link]] 
 + 
  
 ===== Concluzii ===== ===== Concluzii =====
 +
 +Proiectul a fost foarte interesant de realizat atat din punct de vedere hardware cat si software, iar timpul pe care l-am petrecut lucrand la acesta mi-a permis sa aprofundez mult mai bine conceptele prezentate la laborator si totodata mi-a oferit sansa sa imi exersez skill-urile de software design. Majoritatea cerintelor functionale pe care le-am mentionat in sectiunea de introducere a proiectului au fost indeplinite cu succes, iar overall sunt multumit de rezultatele obtinute. ​
 +
 +Singurul aspect care ar putea fi imbunatatit este momentul in care oprim pompa de apa. In varianta actuala am presupus ca aceasta are un debit relativ constant si pe baza acestuia am calculat timpul necesar de umplere. In realitate debitul nu este chiar constant, acesta fiind mai mic la inceput si dupa aceea crescand treptat pana ce pompa ajunge in modul optim de functionare. Din aceasta cauza, proiectul are o acuratete mai buna pentru volume mai mici de lichid, iar pentru volume mari exista un surplus introdus in recipient. Rezolvarea acestei probleme este relativ simpla prin adaugarea unui senzor de greutate care va monitoriza in permanenta canitatea de lichid care se afla in vas.
  
 ===== Download ===== ===== Download =====
  
-<note warning>​ +Intregul cod este disponibil la acest [[https://github.com/​popovicirobert/​PM-WaterRefillingSystem|link]] sau sub forma de arhiva zip: {{:​pm:​prj2023:​alucaci:​waterrefillingsystem.zip|water_refilling_system.zip}} 
-O arhivă (sau mai multe dacă este cazul) cu fişierele obţinute în urma realizării proiectuluisurse, scheme, etcUn fişier README, un ChangeLog, un script de compilare şi copiere automată pe uC crează întotdeauna o impresie bună ;-).+
  
-Fişierele se încarcă pe wiki folosind facilitatea **Add Images or other files**. Namespace-ul în care se încarcă fişierele este de tipul **:​pm:​prj20??:​c?​** sau **:​pm:​prj20??:​c?:​nume_student** (dacă este cazul). **Exemplu:​** Dumitru Alin, 331CC -> **:​pm:​prj2009:​cc:​dumitru_alin**. 
-</​note>​ 
  
 ===== Jurnal ===== ===== Jurnal =====
  
-<note tip+  * 24.04.2023 -Alegere tema proiect 
-Puteți avea și o secțiune ​de jurnal în care să poată urmări asistentul ​de proiect progresul proiectului+  * 01.05.2023 -> Comanda piese 
-</note>+  * 04.05.2023 -> Prima incercare ​de a programa matricea ​de leduri 
 +  * 05.05.2023 -> Citire date de pe potentiometru + afisare de cifre pe matricea de leduri 
 +  * 06.05.2023 -> Implementare timer cu intreruperi 
 +  * 14.05.2023 -> Hardware finalizat + restructurare minora a codului 
 +  * 21.05.2023 -> Adaugarea tuturor partilor de cod lipsa + impartirea in module 
 +  * 23.05.2023 -> Software finalizat 
 +  * 29.05.2023 -Finalizare pagina wiki
  
 ===== Bibliografie/​Resurse ===== ===== Bibliografie/​Resurse =====
  
-<​note>​ +=== Resure Hardware === 
-Listă cu documente, datasheet-uri, resurse Internet folosite, eventual grupate pe **Resurse Software** şi **Resurse Hardware**. + 
-</note>+  * https://​www.electronicshub.org/​arduino-mega-pinout/​ 
 +  ​https://​ocw.cs.pub.ro/​courses/​_media/​pm/​doc8272.pdf 
 +  ​https://​www.youtube.com/​watch?​v=58XWVDnB7Ss&​ab_channel=Robojax 
 +  ​https://​arduinogetstarted.com/​tutorials/​arduino-controls-pump 
 +  * https://​www.circuitstoday.com/​interfacing-8x8-led-matrix-with-arduino 
 + 
 +=== Resure Software ===
  
-<​html><​a class="​media mediafile mf_pdf"​ href="?​do=export_pdf">​Export to PDF</a></html>+  * https://github.com/​mike-matera/​ArduinoSTL 
 +  * https://​ocw.cs.pub.ro/​courses/​pm/​lab/​lab3-2023
  
pm/prj2023/alucaci/water-refilling-system.1685300609.txt.gz · Last modified: 2023/05/28 22:03 by robert.popovici
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0