Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ FROM ubuntu:noble@sha256:c4a8d5503dfb2a3eb8ab5f807da5bc69a85730fb49b5cfca2330194
# інтерактивного stdin немає - без цього build може зависнути назавжди.
ARG DEBIAN_FRONTEND="noninteractive"


RUN dpkg --add-architecture arm64 && apt update
RUN apt install --no-install-recommends -y libgpiod-dev:arm64
# Пакети зі списку apt-packages.in (по одному на рядок, коментарі через #).
#
# Прапори й чистка:
Expand Down
8 changes: 8 additions & 0 deletions .devcontainer/apt-packages.in
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,11 @@ cmake
clang-format
cmake-format
ninja-build


# work with rpi pins
libgpiod-dev
socat

pkg-config
file
14 changes: 10 additions & 4 deletions drone_simulation/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,22 @@ add_library(drone_simulation_lib
src/drone_states/state_turning.cpp
src/drone_states/state_moving.cpp
src/drone_physics.cpp
src/port_controllers/uart_port.cpp
src/port_controllers/gpio_controller.cpp
src/drone_controller.cpp
)

find_package(Threads REQUIRED)
target_link_libraries(drone_simulation_lib PUBLIC Threads::Threads)
target_link_libraries(drone_simulation_lib PUBLIC Threads::Threads ${GPIOD_LIBRARIES})

target_include_directories(drone_simulation_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_compile_options(drone_simulation_lib PRIVATE -Wall -Wextra -pedantic)
find_package(PkgConfig REQUIRED)
pkg_check_modules(GPIOD REQUIRED libgpiod)

target_include_directories(drone_simulation_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include ${GPIOD_INCLUDE_DIRS})

add_executable(drone_simulation_check src/main.cpp)
target_link_libraries(drone_simulation_check PRIVATE drone_simulation_lib)
target_link_libraries(drone_simulation_check PRIVATE drone_simulation_lib ${GPIOD_LIBRARIES})
target_include_directories(drone_simulation_check PRIVATE ${GPIOD_INCLUDE_DIRS})
target_compile_options(drone_simulation_check PRIVATE -Wall -Wextra -pedantic)

file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/
Expand Down
11 changes: 6 additions & 5 deletions drone_simulation/include/config_loaders/factory.hpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#pragma once
#include <cstring>
#include <memory>
#include "simulation.hpp"
#include "interfaces/ballistic_solver.hpp"
#include "interfaces/target_provider.hpp"
#include "interfaces/config_loader.hpp"
#include <string>

struct DroneConfig;
class IBallisticSolver;
class ITargetProvider;
class IConfigLoader;

enum class SolverType { ANALYTICAL, TABLE };
enum class ProviderType { JSON, THREAD_SAFE };
Expand Down
14 changes: 14 additions & 0 deletions drone_simulation/include/drone_controller.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#pragma once
#include "simulation.hpp"

class DroneController {
public:
DroneController(const DroneConfig& config);
auto computeControl(const DroneTelemetry& telemetry, const Coord& aimPoint) -> dlink::Control;

private:
DroneConfig config;
float prevDesiredDir = 0.0f;
float prevTime = -1.0f;
bool hasPrev = false;
};
168 changes: 168 additions & 0 deletions drone_simulation/include/drone_link.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
// drone_link.h — бінарний UART-протокол ДЗ11 (заняття 4.4)
// Спільний для симулятора фізики, чекера і програми студента.
//
// Кадр на дроті:
// [0] MAGIC0 = 0xA5
// [1] MAGIC1 = 0x5A
// [2] TYPE (1 байт) — тип пакета (PacketType)
// [3] LEN (1 байт) — довжина payload у байтах
// [4..4+LEN-1] payload — корисні дані (little-endian)
// [..] CRC16 (2 байти, LE) — CRC-16/CCITT-FALSE по TYPE+LEN+payload
//
// Усі multi-byte поля — little-endian (як на ARM/x86 за замовчуванням).
// Кадр самосинхронізується: приймач шукає MAGIC0,MAGIC1, потім читає LEN і CRC.

#ifndef DRONE_LINK_H
#define DRONE_LINK_H

#include <cstdint>
#include <cstring>

namespace dlink {

constexpr uint8_t MAGIC0 = 0xA5;
constexpr uint8_t MAGIC1 = 0x5A;

enum PacketType : uint8_t {
PKT_TELEMETRY = 0x01, // стан дрона в момент часу
PKT_TARGET = 0x02, // позиція однієї цілі (шлеться періодично по кожній цілі)
PKT_AMMO = 0x03, // параметри боєприпасу + hitRadius (один раз на старті)
PKT_RESULT = 0x04, // вердикт чекера (HIT/MISS) — лише на реальній малині по UART назад
PKT_CONTROL = 0x05, // КЕРУВАННЯ: студент -> чекер (прискорення і швидкість повороту)
};

#pragma pack(push, 1)

// PKT_TELEMETRY — те, що читає і парсить студент
struct Telemetry {
uint32_t t_ms; // час від старту, мілісекунди (таймстемп)
float x, y; // позиція дрона в площині, метри
float z; // висота (altitude), метри
float vx, vy; // швидкість у площині, м/с
float speed; // модуль горизонтальної швидкості, м/с
float dir; // курс (напрямок польоту), радіани
uint8_t state; // стан стейт-машини (0..4, як у DZ3)
};

// PKT_TARGET — позиція цілі «зараз» (ціль може рухатися)
struct TargetPos {
uint8_t id; // індекс цілі
float x, y; // поточна позиція цілі, метри
};

// PKT_AMMO — конфіг пострілу (надсилається раз на старті)
struct AmmoCfg {
char name[16]; // напр. "VOG-17"
float mass; // m
float drag; // d
float lift; // l
float hitRadius; // радіус успішного влучання, метри
uint8_t nTargets; // скільки цілей у місії
};

// PKT_RESULT — вердикт (зворотний канал на залізі)
struct Result {
uint8_t hit; // 1 = влучив, 0 = промах
uint8_t targetId; // у яку ціль (або 0xFF)
float miss_m; // відстань промаху, метри
uint32_t drop_t_ms; // коли спрацював скид
};

// PKT_CONTROL — команда керування дроном (студент шле чекеру кожен такт)
// Нормовані значення; чекер множить на фізичні ліміти дрона (maxAccel, maxTurnRate).
struct Control {
float accel; // прискорення вздовж курсу, [-1..1] (1 = повний газ, -1 = гальмо)
float turnRate; // швидкість повороту, [-1..1] (1 = макс. вліво, -1 = вправо)
};

#pragma pack(pop)

// ---- CRC-16/CCITT-FALSE (poly 0x1021, init 0xFFFF) ----
inline uint16_t crc16(const uint8_t* data, size_t len)
{
uint16_t crc = 0xFFFF;
for (size_t i = 0; i < len; ++i) {
crc ^= (uint16_t)data[i] << 8;
for (int b = 0; b < 8; ++b)
crc = (crc & 0x8000) ? (crc << 1) ^ 0x1021 : (crc << 1);
}
return crc;
}

// Запакувати кадр у буфер out (повертає кількість записаних байтів).
// out має бути >= 6 + payloadLen.
inline size_t encode(uint8_t type, const void* payload, uint8_t payloadLen, uint8_t* out)
{
out[0] = MAGIC0;
out[1] = MAGIC1;
out[2] = type;
out[3] = payloadLen;
if (payloadLen && payload)
std::memcpy(out + 4, payload, payloadLen);
uint16_t c = crc16(out + 2, (size_t)payloadLen + 2); // по TYPE+LEN+payload
out[4 + payloadLen] = (uint8_t)(c & 0xFF);
out[4 + payloadLen + 1] = (uint8_t)(c >> 8);
return (size_t)payloadLen + 6;
}

// Інкрементальний парсер: годуєш байтами, на готовому валідному кадрі feed() повертає true.
// Тримає стан між викликами — зручно читати з UART по шматках.
struct Parser {
enum { S_M0, S_M1, S_TYPE, S_LEN, S_PAYLOAD, S_CRC0, S_CRC1 } st = S_M0;
uint8_t type = 0, len = 0, idx = 0;
uint8_t buf[260];
uint16_t crc_rx = 0;

// Повертає true, коли зібрано повний валідний кадр.
// type/payload/payloadLen — вихідні (валідні лише при true).
bool feed(uint8_t byte, uint8_t& outType, uint8_t* outPayload, uint8_t& outLen)
{
switch (st) {
case S_M0:
if (byte == MAGIC0)
st = S_M1;
break;
case S_M1:
st = (byte == MAGIC1) ? S_TYPE : S_M0;
break;
case S_TYPE:
type = byte;
st = S_LEN;
break;
case S_LEN:
len = byte;
idx = 0;
st = len ? S_PAYLOAD : S_CRC0;
break;
case S_PAYLOAD:
buf[idx++] = byte;
if (idx >= len)
st = S_CRC0;
break;
case S_CRC0:
crc_rx = byte;
st = S_CRC1;
break;
case S_CRC1: {
crc_rx |= (uint16_t)byte << 8;
st = S_M0;
// перерахувати CRC по TYPE+LEN+payload
uint8_t tmp[262];
tmp[0] = type;
tmp[1] = len;
std::memcpy(tmp + 2, buf, len);
if (crc16(tmp, (size_t)len + 2) == crc_rx) {
outType = type;
outLen = len;
std::memcpy(outPayload, buf, len);
return true;
}
break; // биті дані — кадр відкинуто, синхронізуємось далі
}
}
return false;
}
};

} // namespace dlink
#endif // DRONE_LINK_H
17 changes: 17 additions & 0 deletions drone_simulation/include/log.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once
#include <iostream>

#define ENABLE_LOG 1
#define ENABLE_DEBUG 0

#if ENABLE_LOG
#define LOG(msg) std::cout << "[LOG] " << msg << std::endl
#else
#define LOG(msg)
#endif

#if ENABLE_DEBUG
#define DEBUG(msg) std::cout << "[DEBUG] " << msg << std::endl
#else
#define DEBUG(msg)
#endif
51 changes: 19 additions & 32 deletions drone_simulation/include/mission_processor.hpp
Original file line number Diff line number Diff line change
@@ -1,48 +1,35 @@
#pragma once
#include <atomic>
#include <thread>
#include <vector>
#include "interfaces/ballistic_solver.hpp"
#include "interfaces/config_loader.hpp"
#include "interfaces/target_provider.hpp"
#include "interfaces/drone_state.hpp"
#include "drone_physics.hpp"
#include "simulation.hpp"

class MissionProcessor {
public:
MissionProcessor(std::unique_ptr<ITargetProvider> targetProvider, std::unique_ptr<IBallisticSolver> solver, DronePhysics* physics);
MissionProcessor(std::unique_ptr<IBallisticSolver> solver, const DroneConfig& config);

auto init(std::unique_ptr<IConfigLoader> configLoader) -> void;
auto getCurrentStep() -> int;
auto step() -> SimulationStep;
auto init(const dlink::AmmoCfg& ammoCfg, float altitude) -> void;
auto process(const dlink::Telemetry& telem, const std::vector<dlink::TargetPos>& targets, int targetCount) -> MissionResult;
auto reset() -> void;
auto changeSolver(std::unique_ptr<IBallisticSolver> ballisticSolver) -> void;
auto run() -> void;
auto start() -> void;
auto isThreadReady() const -> bool;
auto getSteps() const -> const std::vector<SimulationStep>&;

private:
auto evaluateTarget(int targetIndex, const DroneTelemetry& telemetry, Coord& outFireCoord) -> float;
auto getSimulationStep(int targetIndex, const Coord& fireCoord, const DroneTelemetry& telemetry) -> SimulationStep;
auto hasNext() -> bool;
auto evaluateTarget(int targetIndex,
const DroneTelemetry& telemetry,
const Coord& targetPos,
const Coord& targetVelocity,
Coord& outFireCoord,
Coord& outAimCoord) -> float;
auto checkDrop(const DroneTelemetry& telemetry, const Coord& targetPos, const Coord& targetVelocity) -> bool;

const int MAX_STEPS = 10000;
std::unique_ptr<ITargetProvider> targets;
std::unique_ptr<IBallisticSolver> ballisticSolver;
DroneConfig droneConfig;
AmmoParams ammo;
int currentStep = 1;
DroneConfig droneConfig;
int prevTargetIndex = -1;
float currentTime = 0.0f;
float ammoFlightTime;
float ammoHorizontalFlightDistance;
float acceleration;
float prevDirectionToTarget = 0.0f;
bool hit = false;
DronePhysics* dronePhysics;
std::atomic<bool> ready{false};
std::atomic<bool> running{false};
std::vector<SimulationStep> simulationSteps;
std::unique_ptr<IDroneState> droneState;
float ammoFlightTime = 0.0f;
float ammoHorizontalFlightDistance = 0.0f;
float hitRadius = 0.0f;
bool initialized = false;
std::vector<Coord> prevTargetPositions;
std::vector<Coord> targetVelocities;
float prevTime = -1.0f;
};
16 changes: 16 additions & 0 deletions drone_simulation/include/port_controllers/gpio_controller.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once
#include <gpiod.h> // libgpiod — Linux API для роботи з GPIO

class GpioController {
public:
GpioController(const char* chipName, int startLine, int dropLine);
~GpioController();

auto signalStart() -> void;
auto signalDrop() -> void;

private:
gpiod_chip* chip;
gpiod_line* startLine;
gpiod_line* dropLine;
};
15 changes: 15 additions & 0 deletions drone_simulation/include/port_controllers/uart_port.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once
#include <cstdint>
#include <cstddef>

class UartPort {
public:
explicit UartPort(const char* device);
~UartPort();

auto readBytes(uint8_t* buffer, size_t maxByteCount) -> int;
auto writeBytes(const uint8_t* buffer, size_t byteCount) -> void;

private:
int fd;
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <cstring>
#include <vector>
#include <atomic>
#include <mutex>
#include "interfaces/target_provider.hpp"

class ThreadSafeTargetProvider : public ITargetProvider {
Expand Down
Loading
Loading