Написание кода на Rust для ультразвукового датчика HC-SR04 с Pico 2
Начнём с создания проекта из шаблона, а затем изменим код под требования текущего проекта.
Создание проекта из шаблона
Подробности и инструкции см. в разделе о шаблоне.
Чтобы создать проект, выполните:
cargo generate --git https://github.com/ImplFerris/pico2-template.git --tag v0.3.2
Когда появится запрос, придумайте имя проекта — пусть будет «bat-beacon». Не забудьте выбрать rp-hal в качестве HAL.
Затем перейдите в папку проекта:
cd PROJECT_NAME
# Например, если вы назвали проект «bat-beacon»:
# cd bat-beacon
Настройка вывода светодиода
К этому моменту вы уже должны понимать этот код. Если нет, сначала пройдите раздел про мигание светодиодом.
Краткое напоминание: здесь мы настраиваем ШИМ для светодиода, что позволяет управлять яркостью, меняя коэффициент заполнения.
#![allow(unused)]
fn main() {
let pwm = &mut pwm_slices.pwm1; // Берём слайс ШИМ 1
pwm.set_ph_correct(); // Включаем фазово-корректный режим для более плавных переходов
pwm.enable(); // Включаем слайс ШИМ
let led = &mut pwm.channel_b; // Выбираем канал ШИМ B
led.output_to(pins.gpio3); // Назначаем GPIO 3 выходом ШИМ
}
Настройка вывода Trigger
Вывод Trigger ультразвукового датчика используется для запуска ультразвукового импульса. Его нужно настроить как выход, чтобы мы могли управлять им и посылать импульс.
#![allow(unused)]
fn main() {
let mut trigger = pins.gpio17.into_push_pull_output();
}
Настройка вывода Echo
Вывод Echo ультразвукового датчика принимает возвращающийся сигнал, что позволяет измерить время, за которое импульс дошёл до объекта и вернулся. Его настраивают как вход, чтобы обнаруживать возвращающийся импульс.
#![allow(unused)]
fn main() {
let mut echo = pins.gpio16.into_pull_down_input();
}
🦇 Зажигаем светодиод
Шаг 1: отправляем импульс Trigger
Сначала нужно отправить на вывод trigger короткий импульс, чтобы начать ультразвуковое измерение.
#![allow(unused)]
fn main() {
// Перед стартом убедимся, что вывод Trigger в низком уровне
trigger.set_low().ok().unwrap();
timer.delay_us(2);
// Отправляем высокий импульс длительностью 10 микросекунд
trigger.set_high().ok().unwrap();
timer.delay_us(10);
trigger.set_low().ok().unwrap();
}
Шаг 2: измеряем время эха
Далее используем два цикла. Первый цикл выполняется, пока состояние вывода echo — LOW. Как только оно станет HIGH, мы запишем текущее время в переменную. Затем запускаем второй цикл, который продолжается, пока вывод echo остаётся HIGH. Когда он вернётся в LOW, мы запишем текущее время в другую переменную. Разница между этими двумя временами даёт нам ширину импульса.
#![allow(unused)]
fn main() {
let mut time_low = 0;
let mut time_high = 0;
// Ждём, когда вывод Echo станет высоким, и запоминаем время
while echo.is_low().ok().unwrap() {
time_low = timer.get_counter().ticks();
}
// Ждём, когда вывод Echo станет низким, и запоминаем время
while echo.is_high().ok().unwrap() {
time_high = timer.get_counter().ticks();
}
// Вычисляем время, за которое сигнал вернулся
let time_passed = time_high - time_low;
}
Шаг 3: вычисляем расстояние
Чтобы вычислить расстояние, нужна ширина импульса. Она показывает, сколько времени ультразвуковым волнам понадобилось, чтобы дойти до препятствия и вернуться. Поскольку импульс представляет время туда и обратно, мы делим его на 2, чтобы учесть путь до препятствия и обратно.
Скорость звука в воздухе примерно 0,0343 см за микросекунду. Умножив время (в микросекундах) на это значение и разделив на 2, получаем расстояние до препятствия в сантиметрах.
#![allow(unused)]
fn main() {
let distance = time_passed as f64 * 0.0343 / 2.0;
}
Шаг 4: коэффициент заполнения ШИМ для светодиода
Наконец, регулируем яркость светодиода в зависимости от измеренного расстояния.
Процент коэффициента заполнения вычисляется по нашей собственной логике, вы можете изменить её под свои нужды. Когда предмет ближе 30 см, яркость светодиода будет расти. Чем ближе предмет к ультразвуковому модулю, тем выше получается вычисленное отношение, а значит, тем выше коэффициент заполнения. В итоге яркость светодиода постепенно увеличивается по мере приближения предмета к датчику.
#![allow(unused)]
fn main() {
let duty_cycle = if distance < 30.0 {
let step = 30.0 - distance;
(step * 1500.) as u16 + 1000
} else {
0
};
// Меняем яркость светодиода
led.set_duty_cycle(duty_cycle).unwrap();
}
Полная логика цикла
Примечание: этот фрагмент кода показывает только цикл и не включает всю программу.
#![allow(unused)]
fn main() {
loop {
timer.delay_ms(5);
trigger.set_low().ok().unwrap();
timer.delay_us(2);
trigger.set_high().ok().unwrap();
timer.delay_us(10);
trigger.set_low().ok().unwrap();
let mut time_low = 0;
let mut time_high = 0;
while echo.is_low().ok().unwrap() {
time_low = timer.get_counter().ticks();
}
while echo.is_high().ok().unwrap() {
time_high = timer.get_counter().ticks();
}
let time_passed = time_high - time_low;
let distance = time_passed as f64 * 0.0343 / 2.0;
let duty_cycle = if distance < 30.0 {
let step = 30.0 - distance;
(step * 1500.) as u16 + 1000
} else {
0
};
led.set_duty_cycle(duty_cycle).unwrap();
}
}
Клонируйте существующий проект
Можно клонировать проект, который я создал, и перейти в папку ultrasonic.
git clone https://github.com/ImplFerris/pico2-rp-projects
cd pico2-rp-projects/ultrasonic
Ваше задание
- Используйте фреймворк Embassy вместо
rp-hal - Используйте вместо этого встроенный светодиод