#ifndef SensorGasModel #define SensorGasModel #include "SerialService.h" #include "Pinout.h" #include "Utils.h" #include "IComponenteCAN.h" class SensorGas : public ComponenteCAN { public: enum class TipoSensorGas : uint8_t { MQ2 = 0, MQ7 = 1, MQ135 = 2, }; SensorGas(String _modID, String _id) { Mod_ID = _modID; _ID = _id; } String Mod_ID = ""; String _ID; int ID_Num; PinoModel _pino; TipoSensorGas Tipo; float ppm = -1; float tensao = -1; bool Iniciado = false; bool Checando = false; void Inicializar() { if (Iniciado) { MostrarLog("Sensor já inicializado"); return; } _pino.Conectar(); Iniciado = _pino.Definido(); MostrarLog(Iniciado ? "Sensor iniciado" : "Sensor nao iniciado"); } void Desligar() { if (!Iniciado) { MostrarLog("Sensor nao esta inicializado"); return; } _pino.Desconectar(); // Desconecta o pino MostrarLog("Sensor Desligado"); Iniciado = false; } void RequisitarDados() { AferirGas(); } std::vector MontarMensagemCAN(CanMessagePosicaoDados posicao) { std::vector data; data.push_back(static_cast(posicao)); data.push_back(ID_Num); switch (posicao) { case CanMessagePosicaoDados::Status: { data.push_back(Iniciado ? 1 : 0); break; } case CanMessagePosicaoDados::Dados1: { int32_t leituraInt = static_cast(round(ppm * 100.0f)); data.push_back((uint8_t)(leituraInt >> 24)); data.push_back((uint8_t)(leituraInt >> 16)); data.push_back((uint8_t)(leituraInt >> 8)); data.push_back((uint8_t)(leituraInt & 0xFF)); break; } } return data; } static std::vector ConfigurarSensor(std::vector& lista, std::vector& data, const String& Mod_ID) { std::vector status; if (data.size() < 2) return status; CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0]; uint8_t idNum = data[1]; auto it = std::find_if(lista.begin(), lista.end(), [idNum](SensorGas* s) { return s->ID_Num == idNum; }); bool jaExiste = it != lista.end(); SensorGas* sensor; switch (posicao) { case CanMessagePosicaoDados::Config1: { if (data.size() < 8) return status; bool conectar = data[3] == 1; TiposBarramentos tipoBarramento = (TiposBarramentos)data[4]; int pino = data[5]; TipoSensorGas tipo = (TipoSensorGas)data[6]; int canalMux = (data[7] == 255) ? -1 : data[7]; if (conectar) { if (!jaExiste) sensor = new SensorGas(Mod_ID, "sGAS_" + String(idNum)); else sensor = *it; if (!sensor->Iniciado) { sensor->ID_Num = idNum; sensor->_pino = PinoModel(pino, tipoBarramento, _INPUT, ANALOGICO, idNum, canalMux); sensor->Tipo = tipo; sensor->Inicializar(); if (!jaExiste) { lista.push_back(sensor); sensor->MostrarLog("Sensor de gas adicionado via CAN: sGAS_" + String(idNum)); } } status = sensor->MontarMensagemCAN(CanMessagePosicaoDados::Status); } else { if (jaExiste) { sensor = *it; sensor->Desligar(); status = sensor->MontarMensagemCAN(CanMessagePosicaoDados::Status); sensor->MostrarLog("Sensor de gas removido via CAN: sGAS_" + String(idNum)); delete sensor; lista.erase(it); } } break; } } return status; } private: bool DegugMode = true; void MostrarLog(String mensagem) { if (DegugMode) { PrintTela("[GAS " + _ID + "] " + mensagem); } } void AferirGas() { if (!Iniciado) return; float leitura = _pino.get(); ppm = CalcularPPM(leitura); MostrarLog("Leitura Gas: " + String(leitura) + ", Tensao: " + String(tensao) + ", PPM estimado: " + String(ppm)); } float CalcularPPM(float leitura) { switch (Tipo) { case TipoSensorGas::MQ2: return CalcularPPM_MQ2(leitura); case TipoSensorGas::MQ7: return CalcularPPM_MQ7(leitura); default: return 0.0f; } } // Valor de R0 calibrado (ideal seria calibrar em tempo real, aqui é fixo) const float R0_MQ2 = 16.8f; static constexpr float vOffsetMQ2 = (0.475f / 0.18f); // v real / v ads const float R0_MQ7 = 75.1f; static constexpr float vOffsetMQ7 = (0.251f / 0.09f); // v real / v ads // Constantes do divisor resistivo const float RL = 10.0; // resistência de carga típica em kΩ const float Vs = 5.0f; // tensão de alimentação do MQ static constexpr float R1 = 9.94f; static constexpr float R2 = 5.4f; static constexpr float divisor = R1 / (R1 + R2); // R1 = 5K6, R2 = 10K float CalcularPPM_MQ2(float leituraADC) { float leituraADC_volts = (leituraADC / 4095.0f) * Vs; float Vadc = leituraADC_volts * divisor * vOffsetMQ2; tensao = Vadc; if (Vadc <= 0.01f || Vadc >= Vs) return 0; float Rs = (Vs - Vadc) * RL / Vadc; float ratio = Rs / R0_MQ2; float ppm = pow(10.0, (-0.45 * log10(ratio)) + 1.9); return ppm; } float CalcularPPM_MQ7(float leituraADC) { float leituraADC_volts = (leituraADC / 4095.0f) * Vs; float Vadc = leituraADC_volts * divisor * vOffsetMQ2; tensao = Vadc; if (Vadc <= 0.01f || Vadc >= Vs) return 0; float Rs = (Vs - Vadc) * RL / Vadc; float ratio = Rs / R0_MQ7; float ppm = pow(10.0, (-1.7 * log10(ratio)) + 1.7); return ppm; } }; #endif