Да, мы можем запустить эволюцию на микроконтроллере! Генетические алгоритмы идеально подходят для оптимизации параметров (например, настройка PID-регулятора).
Генетический алгоритм для нахождения минимума функции:
#include <avr/random.h>
#define POPULATION_SIZE 20
#define GENOME_SIZE 8
#define GENERATIONS 100
// Структура особи
struct Individual {
uint8_t genes[GENOME_SIZE];
uint16_t fitness;
};
Individual population[POPULATION_SIZE];
Individual best;
// Функция приспособленности (чем меньше, тем лучше)
uint16_t calculateFitness(uint8_t* genes) {
uint16_t result = 0;
for (uint8_t i = 0; i < GENOME_SIZE; i++) {
// Целевая функция: найти минимум
result += (genes[i] - 128) * (genes[i] - 128);
}
return result;
}
// Создание начальной популяции
void initPopulation() {
for (uint8_t i = 0; i < POPULATION_SIZE; i++) {
for (uint8_t j = 0; j < GENOME_SIZE; j++) {
population[i].genes[j] = random(256);
}
population[i].fitness = calculateFitness(population[i].genes);
}
}
// Селекция (турнирная)
uint8_t tournamentSelection() {
uint8_t bestIndex = random(POPULATION_SIZE);
for (uint8_t i = 0; i < 3; i++) {
uint8_t contender = random(POPULATION_SIZE);
if (population[contender].fitness < population[bestIndex].fitness) {
bestIndex = contender;
}
}
return bestIndex;
}
// Кроссинговер (одноточечный)
void crossover(uint8_t* parent1, uint8_t* parent2, uint8_t* child1, uint8_t* child2) {
uint8_t point = random(GENOME_SIZE);
for (uint8_t i = 0; i < GENOME_SIZE; i++) {
if (i < point) {
child1[i] = parent1[i];
child2[i] = parent2[i];
} else {
child1[i] = parent2[i];
child2[i] = parent1[i];
}
}
}
// Мутация
void mutate(uint8_t* genes) {
for (uint8_t i = 0; i < GENOME_SIZE; i++) {
if (random(100) < 5) { // 5% вероятность мутации
genes[i] += random(-10, 10);
}
}
}
// Основной цикл эволюции
void evolve() {
Individual newPopulation[POPULATION_SIZE];
// Элитизм: сохраняем лучшую особь
best = population[0];
for (uint8_t i = 1; i < POPULATION_SIZE; i++) {
if (population[i].fitness < best.fitness) {
best = population[i];
}
}
newPopulation[0] = best;
// Создаем остальную популяцию
for (uint8_t i = 1; i < POPULATION_SIZE; i += 2) {
uint8_t p1 = tournamentSelection();
uint8_t p2 = tournamentSelection();
crossover(population[p1].genes, population[p2].genes,
newPopulation[i].genes, newPopulation[i+1].genes);
mutate(newPopulation[i].genes);
mutate(newPopulation[i+1].genes);
newPopulation[i].fitness = calculateFitness(newPopulation[i].genes);
newPopulation[i+1].fitness = calculateFitness(newPopulation[i+1].genes);
}
// Копируем новую популяцию
memcpy(population, newPopulation, sizeof(population));
}
void setup() {
Serial.begin(115200);
randomSeed(analogRead(A0));
initPopulation();
for (uint16_t gen = 0; gen < GENERATIONS; gen++) {
evolve();
Serial.print("Поколение ");
Serial.print(gen);
Serial.print(": лучшее значение = ");
Serial.println(best.fitness);
}
Serial.print("Оптимальные гены: ");
for (uint8_t i = 0; i < GENOME_SIZE; i++) {
Serial.print(best.genes[i]);
Serial.print(" ");
}
Serial.println();
}
void loop() {}