// Наблюдение в MyRobotica включается сборщиком; обычный Arduino работает без библиотеки. #include #if defined(ROBOT_TELEMETRY_BUILD_ID) #include robot_telemetry::TelemetryStream courseTelemetry; #endif const int LEFT_SENSOR_PIN = A4; const int RIGHT_SENSOR_PIN = A5; // Измерения белого и чёрного из журнала (урок 3.1). const int LEFT_WHITE = 0; const int LEFT_BLACK = 0; const int RIGHT_WHITE = 0; const int RIGHT_BLACK = 0; // Переводит показание в шкалу: чёрное — 0, белое — 100. int level(int value, int white, int black) { long result = (long)(value - black) * 100 / (white - black); return constrain(result, 0, 100); } const int LEFT_DIR_PIN = 7; const int LEFT_SPEED_PIN = 6; const int RIGHT_DIR_PIN = 4; const int RIGHT_SPEED_PIN = 5; const int FORWARD = HIGH; float kp = 0.5; // сила поворота: подбираем на дорожке int baseSpeed = 100; // скорость на прямой void drive(int leftDir, int leftSpeed, int rightDir, int rightSpeed) { digitalWrite(LEFT_DIR_PIN, leftDir); digitalWrite(RIGHT_DIR_PIN, rightDir); analogWrite(LEFT_SPEED_PIN, leftSpeed); analogWrite(RIGHT_SPEED_PIN, rightSpeed); } void setup() { courseTelemetryBegin(); pinMode(LEFT_DIR_PIN, OUTPUT); pinMode(LEFT_SPEED_PIN, OUTPUT); pinMode(RIGHT_DIR_PIN, OUTPUT); pinMode(RIGHT_SPEED_PIN, OUTPUT); drive(FORWARD, 0, FORWARD, 0); // Без измерений робот не поедет. if (LEFT_WHITE == LEFT_BLACK || RIGHT_WHITE == RIGHT_BLACK) { while (true) { courseTelemetryPoll(); } } courseWait(2000); } void loop() { int leftRaw = analogRead(LEFT_SENSOR_PIN); int rightRaw = analogRead(RIGHT_SENSOR_PIN); int leftLevel = level(leftRaw, LEFT_WHITE, LEFT_BLACK); int rightLevel = level(rightRaw, RIGHT_WHITE, RIGHT_BLACK); int error = leftLevel - rightLevel; int correction = kp * error; int leftSpeed = constrain(baseSpeed + correction, 0, 255); int rightSpeed = constrain(baseSpeed - correction, 0, 255); drive(FORWARD, leftSpeed, FORWARD, rightSpeed); courseTelemetryReport(leftRaw, rightRaw, error, correction); } // ===== Готовое: передача наблюдений — не меняй ===== void courseTelemetryBegin() { #if defined(ROBOT_TELEMETRY_BUILD_ID) using namespace robot_telemetry::wire; courseTelemetry.begin((1UL << Line0) | (1UL << Line1) | (1UL << LineError) | (1UL << ControlOutput)); #else Serial.begin(9600); #endif } void courseTelemetryPoll() { #if defined(ROBOT_TELEMETRY_BUILD_ID) courseTelemetry.update(); #endif } // NAN означает «ещё не вычислено», а не нулевую ошибку или поправку. void courseTelemetryReport(int leftRaw, int rightRaw, float error, float output) { #if defined(ROBOT_TELEMETRY_BUILD_ID) using namespace robot_telemetry::wire; courseTelemetry.setUnsigned(Line0, leftRaw); courseTelemetry.setUnsigned(Line1, rightRaw); if (isnan(error)) courseTelemetry.setMissing(LineError); else courseTelemetry.setFloat(LineError, error); if (isnan(output)) courseTelemetry.setMissing(ControlOutput); else courseTelemetry.setFloat(ControlOutput, output); courseTelemetry.update(); #endif } void courseWait(unsigned long durationMs) { unsigned long started = millis(); while (millis() - started < durationMs) { courseTelemetryPoll(); delay(1); } }