Compare commits

..

5 Commits

Author SHA1 Message Date
GarandPLG 6c0a1fc15b Make car mass configurable at runtime
Replace the compile‑time CAR_MASS constant with a runtime‑settable
_member _carMass. Add Engine::setCarMass, default it to 1200 kg, and
use it in the acceleration calculation. Prompt the user for the
car mass on startup via Serial and update the enable/disable messages.
2026-06-17 00:13:16 +02:00
GarandPLG c053a296a5 Add single‑pin Sonar support with periodic reading
Implemented Sonar constructor to use a single shared pin, added mode
flag and
helper method for single‑pin measurements. Updated measure() to select
the
appropriate implementation and added timeout to pulseIn. Integrated
periodic
sonar updates in the main loop, tracking last update time and toggling a
seatBelts flag based on distance thresholds.
2026-06-17 00:03:17 +02:00
GarandPLG 23d5003788 Add PWM motor control and refactor engine update
Introduce ENA pins for both motors and implement rpmToPwm and setMotor.
Replace extensive Serial debug prints with concise motor‑drive logic in
Engine::update. Consolidate sonar pins into a single TRIG_AND_ECHO_PIN.
Update pinMode calls in the sketch to configure the new ENA pins.
2026-06-16 23:35:23 +02:00
GarandPLG 17f888a11c Rename Projekt.ino to Projekt_Arduino.ino
Rename Projekt.ino to Projekt_Arduino.ino

- Rename the main sketch file and adjust references accordingly.
- Clean up Config.h spacing and delete unused turn‑signal constants.
- Remove direction‑related LCD character data and its update logic.
- Introduce Display::startOrEnd to control LCD power on/off.
- Simplify display initialization and eliminate the old delay in the
  loop.
- Add serial debug output for the car enable state.
2026-06-16 22:32:39 +02:00
GarandPLG a80a5bd9a7 Poprawić nazwę pliku głównego 2026-06-16 22:05:46 +02:00
9 changed files with 183 additions and 171 deletions
+8 -8
View File
@@ -4,16 +4,11 @@
const int SS_PIN = 10;
const int RST_PIN = 7;
const byte AUTH_UID[4] = {145, 136, 97, 102};
const byte AUTH_UID[4] = { 145, 136, 97, 102 };
const byte AUTH_UID_SIZE = sizeof(AUTH_UID);
// // Kierunkowskazy
// const int TS_RIGHT = 9;
// const int TS_LEFT = 8;
// // Odległościomierz
// const int TRIG_PIN = 6;
// const int ECHO_PIN = 5;
const int TRIG_AND_ECHO_PIN = 3;
const long SONAR_MAX_DIST_CM = 400;
@@ -34,7 +29,12 @@ const uint8_t BRAKE_PIN = A2;
const uint8_t THROTTLE_PIN = A3;
// Silniki
// Prawy silnik
const int IN_1 = 9;
const int IN_2 = 8;
const int ENA_1 = 5;
// Lewy silnik
const int IN_3 = 4;
const int IN_4 = 3;
const int IN_4 = 2;
const int ENA_2 = 6;
+10 -28
View File
@@ -2,22 +2,23 @@
void Display::begin(int cols, int rows) {
_lcd.begin(cols, rows);
_lcd.createChar(CHAR_LEFT, _leftChar);
_lcd.createChar(CHAR_RIGHT, _rightChar);
_lcd.createChar(CHAR_LEFT_BLINK, _leftCharBlink);
_lcd.createChar(CHAR_RIGHT_BLINK, _rightCharBlink);
_lcd.noDisplay();
_lcd.setCursor(0, 0);
_lcd.print("km/h: 000 | ");
_lcd.write((uint8_t)CHAR_LEFT);
_lcd.print(" ");
_lcd.write((uint8_t)CHAR_RIGHT);
_lcd.setCursor(0, 1);
_lcd.print("rpm: 0000 | G:0");
}
void Display::startOrEnd(bool enable) {
if (enable) {
delay(3000);
_lcd.display();
} else {
_lcd.noDisplay();
}
}
void Display::updateSpeed(int kmh) {
if (kmh < 0) kmh = 0;
if (kmh > 999) kmh = 999;
@@ -44,22 +45,3 @@ void Display::updateGear(char gearChar) {
_lcd.print(gearChar);
_lcd.print(' ');
}
// void Display::updateDirection(bool leftOn, bool rightOn) {
// if (leftOn && rightOn) {
// _lcd.setCursor(12, 0);
// _lcd.write((uint8_t)CHAR_LEFT);
// _lcd.print(' ');
// _lcd.write((uint8_t)CHAR_RIGHT);
// return;
// }
// unsigned long now = millis();
// bool leftBlink = leftOn && ((now / 1000UL) % 2 == 0);
// bool rightBlink = rightOn && ((now / 1000UL) % 2 == 0);
// _lcd.setCursor(12, 0);
// _lcd.write((uint8_t)(leftBlink ? CHAR_LEFT_BLINK : CHAR_LEFT));
// _lcd.print(' ');
// _lcd.write((uint8_t)(rightBlink ? CHAR_RIGHT_BLINK : CHAR_RIGHT));
// }
+2 -7
View File
@@ -13,19 +13,14 @@ class Display {
public:
void begin(int cols, int rows);
void startOrEnd(bool enable);
void updateSpeed(int kmh);
void updateRPM(int rpm);
void updateGear(char gearChar);
// void updateDirection(bool leftOn, bool rightOn);
private:
rgb_lcd _lcd;
byte _leftChar[8] = { 0x00, 0x04, 0x08, 0x1F, 0x1F, 0x08, 0x04, 0x00 };
byte _leftCharBlink[8] = { 0x1F, 0x1B, 0x17, 0x00, 0x00, 0x17, 0x1B, 0x1F };
byte _rightChar[8] = { 0x00, 0x04, 0x02, 0x1F, 0x1F, 0x02, 0x04, 0x00 };
byte _rightCharBlink[8] = { 0x1F, 0x1B, 0x1D, 0x00, 0x00, 0x1D, 0x1B, 0x1F };
};
+20 -47
View File
@@ -1,4 +1,5 @@
#include "Engine.h"
#include "Config.h"
using namespace EngineConsts;
Engine::Engine(uint8_t throttlePin,
@@ -6,82 +7,41 @@ Engine::Engine(uint8_t throttlePin,
uint8_t brakePin)
: _throttlePin(throttlePin), _clutchPin(clutchPin), _brakePin(brakePin) {}
void Engine::begin() {
}
void Engine::begin() {}
float Engine::readNormalized(uint8_t pin) const {
return analogRead(pin) / 1023.0f;
}
void Engine::update(float dt, uint8_t gearIdx) {
// Serial.println("----------------");
const float throttle = readNormalized(_throttlePin);
// Serial.print("Throttle: ");
// Serial.println(throttle);
const float clutch = readNormalized(_clutchPin);
// Serial.print("Clutch: ");
// Serial.println(clutch);
const float brake = readNormalized(_brakePin);
// Serial.print("Brake: ");
// Serial.println(brake);
const float targetRPM = RPM_IDLE + throttle * (RPM_MAX - RPM_IDLE);
// Serial.print("targetRPM: ");
// Serial.println(targetRPM);
const float wheelRPM = (_speedMs / (2.0f * PI * WHEEL_RADIUS)) * 60.0f;
// Serial.print("wheelRPM: ");
// Serial.println(wheelRPM);
const float gearRatio = GEAR_RATIO[gearIdx];
// Serial.print("gearRatio: ");
// Serial.println(gearRatio);
const float drivenRPM = wheelRPM * fabs(gearRatio) * FINAL_DRIVE;
// Serial.print("drivenRPM: ");
// Serial.println(drivenRPM);
_engineRPM = clutch * drivenRPM + (1.0f - clutch) * targetRPM;
// Serial.print("_engineRPM: ");
// Serial.println(_engineRPM);
_engineRPM = constrain(_engineRPM, RPM_IDLE, 7500.0f);
// Serial.print("_engineRPM (constrain): ");
// Serial.println(_engineRPM);
const float engineForce = (_engineRPM / RPM_MAX) * (1.0f - clutch) * ENGINE_FORCE_FACTOR;
// Serial.print("engineForce: ");
// Serial.println(engineForce);
const float brakeForce = brake * BRAKE_FORCE_MAX;
// Serial.print("brakeForce: ");
// Serial.println(brakeForce);
const float dragForce = 0.5f * DRAG_COEFF * FRONTAL_AREA * (_speedMs * _speedMs);
// Serial.print("dragForce: ");
// Serial.println(dragForce);
const int direction = (gearIdx == -1) ? -1 : 1;
// Serial.print("direction: ");
// Serial.println(direction);
const float netForce = direction * engineForce - brakeForce - dragForce;
// Serial.print("netForce: ");
// Serial.println(netForce);
const float acceleration = netForce / CAR_MASS;
// Serial.print("acceleration: ");
// Serial.println(acceleration);
const float acceleration = netForce / _carMass;
_speedMs += acceleration * dt;
if (_speedMs < 0.0f) _speedMs = 0.0f;
// Serial.print("_speedMs: ");
// Serial.println(_speedMs);
// delay(1000);
setMotor(IN_3, IN_4, ENA_2, targetRPM, false);
bool reverseWheel = (gearIdx == -1);
setMotor(IN_1, IN_2, ENA_1, wheelRPM * 10.0f, reverseWheel);
}
int Engine::getRPM() const {
@@ -91,3 +51,16 @@ int Engine::getRPM() const {
int Engine::getSpeedKmh() const {
return static_cast<int>((_speedMs * 3.6f) + 0.5f);
}
uint8_t Engine::rpmToPwm(float rpm) {
rpm = constrain(rpm, 0.0f, RPM_MAX);
return static_cast<uint8_t>(roundf(rpm / RPM_MAX * 255.0f));
}
void Engine::setMotor(uint8_t inA, uint8_t inB, uint8_t ena,
float rpm, bool reverse) {
digitalWrite(inA, reverse ? LOW : HIGH);
digitalWrite(inB, reverse ? HIGH : LOW);
analogWrite(ena, rpmToPwm(rpm));
}
+6 -1
View File
@@ -13,7 +13,6 @@ constexpr float GEAR_RATIO[6] = {
constexpr float FINAL_DRIVE = 3.74f; // przekładnia różnicowa
constexpr float WHEEL_RADIUS = 0.30f; // m
constexpr float CAR_MASS = 1200.0f; // kg
constexpr float RPM_IDLE = 800.0f; // obroty jałowe
constexpr float RPM_MAX = 7000.0f; // maksymalne obroty
@@ -31,11 +30,16 @@ public:
void begin();
void setCarMass(float mass) { _carMass = mass; }
void update(float dt, uint8_t gearIdx);
int getRPM() const;
int getSpeedKmh() const;
uint8_t rpmToPwm(float rpm);
void setMotor(uint8_t inA, uint8_t inB, uint8_t ena, float rpm, bool reverse = false);
private:
const uint8_t _throttlePin;
const uint8_t _clutchPin;
@@ -43,6 +47,7 @@ private:
float _engineRPM = EngineConsts::RPM_IDLE;
float _speedMs = 0.0f;
float _carMass = 1200.0f;
float readNormalized(uint8_t pin) const;
};
-67
View File
@@ -1,67 +0,0 @@
#include <Wire.h>
#include "Config.h"
#include "Display.h"
#include "Gear.h"
// #include "Sonar.h"
#include "RFID.h"
#include "Engine.h"
Display display;
GearSelector gear(GEAR_X_PIN, GEAR_Y_PIN, GEAR_THRESH_LOW, GEAR_THRESH_HIGH);
// Sonar sonar(TRIG_PIN, ECHO_PIN, SONAR_MAX_DIST_CM);
RFIDReader rfid(SS_PIN, RST_PIN);
Engine engine(THROTTLE_PIN, CLUTCH_PIN, BRAKE_PIN);
unsigned long prevUpdate = 0;
bool carEnabled = false;
void setup() {
Serial.begin(9600);
// pinMode(TS_LEFT, INPUT);
// pinMode(TS_RIGHT, INPUT);
pinMode(IN_1, OUTPUT);
pinMode(IN_2, OUTPUT);
rfid.begin();
display.begin(LCD_COLS, LCD_ROWS);
engine.begin();
}
void loop() {
bool check = rfid.check();
bool matches = rfid.matches(AUTH_UID, AUTH_UID_SIZE);
bool rfidOk = check && matches;
if (rfid.check() && rfid.matches(AUTH_UID, AUTH_UID_SIZE)) {
delay(3000);
carEnabled = !carEnabled;
};
if (carEnabled) {
Serial.println("Działa");
if (gear.update())
display.updateGear(gear.getGearChar());
// display.updateDirection(
// digitalRead(TS_LEFT),
// digitalRead(TS_RIGHT));
unsigned long now = millis();
float dt = (now - prevUpdate) / 1000.0f;
if (dt >= 0.02f) {
prevUpdate = now;
engine.update(dt, gear.getGear());
display.updateRPM(engine.getRPM());
display.updateSpeed(engine.getSpeedKmh());
}
// long dist = sonar.measure();
// Serial.println(dist);
}
}
+98
View File
@@ -0,0 +1,98 @@
#include <Wire.h>
#include "Config.h"
#include "Display.h"
#include "Gear.h"
#include "Sonar.h"
#include "RFID.h"
#include "Engine.h"
Display display;
GearSelector gear(GEAR_X_PIN, GEAR_Y_PIN, GEAR_THRESH_LOW, GEAR_THRESH_HIGH);
Sonar sonar(TRIG_AND_ECHO_PIN, SONAR_MAX_DIST_CM);
RFIDReader rfid(SS_PIN, RST_PIN);
Engine engine(THROTTLE_PIN, CLUTCH_PIN, BRAKE_PIN);
unsigned long prevUpdate = 0;
bool carEnabled = false;
unsigned long prevSonarUpdate = 0;
bool seatBelts = false;
void setup() {
Serial.begin(9600);
// -----------------------------------------------------------------
// 1. Ask the user for the car mass (kg) via the Serial monitor.
// We block only until a valid number is received this is OK
// because it happens once at startup.
// -----------------------------------------------------------------
Serial.println(F("Enter car mass in kg (e.g. 1200):"));
while (true) {
// Wait until something is typed
if (Serial.available() > 0) {
float mass = Serial.parseFloat(); // reads the number
if (mass > 0) { // basic sanity check
engine.setCarMass(mass);
Serial.print(F("Car mass set to "));
Serial.print(mass);
Serial.println(F(" kg"));
break;
} else {
Serial.println(F("Invalid value try again:"));
}
}
}
pinMode(IN_1, OUTPUT);
pinMode(IN_2, OUTPUT);
pinMode(ENA_1, OUTPUT);
pinMode(IN_3, OUTPUT);
pinMode(IN_4, OUTPUT);
pinMode(ENA_2, OUTPUT);
rfid.begin();
display.begin(LCD_COLS, LCD_ROWS);
engine.begin();
}
void loop() {
bool check = rfid.check();
bool matches = rfid.matches(AUTH_UID, AUTH_UID_SIZE);
bool rfidOk = check && matches;
if (rfid.check() && rfid.matches(AUTH_UID, AUTH_UID_SIZE)) {
carEnabled = !carEnabled;
if (carEnabled)
Serial.println("Uruchamiam auto");
else
Serial.println("Gaszę auto");
display.startOrEnd(carEnabled);
};
if (carEnabled) {
if (gear.update())
display.updateGear(gear.getGearChar());
unsigned long now = millis();
float dt = (now - prevUpdate) / 1000.0f;
if (dt >= 0.02f) {
prevUpdate = now;
engine.update(dt, gear.getGear());
display.updateRPM(engine.getRPM());
display.updateSpeed(engine.getSpeedKmh());
}
if (millis() - prevSonarUpdate >= 100) {
prevSonarUpdate = millis();
long dist = sonar.measure();
if (!seatBelts)
if (dist < 200)
seatBelts = true;
else if (dist >= 200) seatBelts = true;
}
}
}
+35 -12
View File
@@ -1,21 +1,26 @@
#include "Sonar.h"
Sonar::Sonar(int trigPin, int echoPin, long maxDistCm)
: _trigPin(trigPin), _echoPin(echoPin),
_maxDistCm(maxDistCm), _lastDistance(0) {
pinMode(_trigPin, OUTPUT);
pinMode(_echoPin, INPUT);
Sonar::Sonar(int sharedPin, long maxDistCm)
: _trigPin(sharedPin),
_echoPin(sharedPin),
_singlePinMode(true),
_maxDistCm(maxDistCm),
_lastDistance(0) {
}
long Sonar::measure() {
digitalWrite(_trigPin, LOW);
delayMicroseconds(2);
digitalWrite(_trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(_trigPin, LOW);
if (_singlePinMode) {
_lastDistance = _measureSinglePin();
} else {
digitalWrite(_trigPin, LOW);
delayMicroseconds(2);
digitalWrite(_trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(_trigPin, LOW);
long duration = pulseIn(_echoPin, HIGH);
_lastDistance = duration / 58;
long duration = pulseIn(_echoPin, HIGH, 30000UL);
_lastDistance = duration / 58;
}
if (_lastDistance > _maxDistCm) {
_lastDistance = _maxDistCm;
@@ -24,6 +29,24 @@ long Sonar::measure() {
return _lastDistance;
}
long Sonar::_measureSinglePin() {
pinMode(_trigPin, OUTPUT);
digitalWrite(_trigPin, LOW);
delayMicroseconds(4);
digitalWrite(_trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(_trigPin, LOW);
pinMode(_echoPin, INPUT);
delayMicroseconds(15);
long duration = pulseIn(_echoPin, HIGH, 30000UL);
return duration / 58;
}
long Sonar::getDistance() const {
return _lastDistance;
}
+4 -1
View File
@@ -3,7 +3,7 @@
class Sonar {
public:
Sonar(int trigPin, int echoPin, long maxDistCm = 400);
Sonar(int sharedPin, long maxDistCm = 400);
long measure();
@@ -12,6 +12,9 @@ public:
private:
int _trigPin;
int _echoPin;
bool _singlePinMode;
long _maxDistCm;
long _lastDistance;
long _measureSinglePin();
};