Я пишу код ROS, чтобы автоматически воспроизводить музыку в зависимости от ситуации в Ubuntu 22.04. Подробно, цель кода заключается в том, чтобы сообщать о статусе робота через динамик. Робот разработан, чтобы следовать за целью, поэтому, если цель нейтральная, звук не воспроизводится, если цель обнаружена — воспроизводится музыка1, а если цель потеряна — воспроизводится музыка2.
int g_target_detecting_state = 0; // глобальная переменная для хранения статуса
void clusteringNode::timer_callback()
{
// Определение статуса, код ROS
}
void followingSoundPlay(void) // (const char* filename)
{
sf::SoundBuffer go_buffer, stop_buffer;
if (!go_buffer.loadFromFile("audio/music1.wav") || !stop_buffer.loadFromFile("audio/music2.wav"))
{
std::cerr << "загрузка не удалась!";
}
sf::Sound go_sound, stop_sound;
go_sound.setBuffer(go_buffer);
stop_sound.setBuffer(stop_buffer);
while(1)
{
if(g_target_detecting_state == 0)
{
go_sound.stop();
stop_sound.stop();
}
else if(g_target_detecting_state == 1)
{
stop_sound.stop();
go_sound.play();
}
else if(g_target_detecting_state == 2)
{
go_sound.stop();
stop_sound.play();
}
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
}
int main(int nArgc,const char* pszArgv[])
{
rclcpp::init(nArgc, pszArgv);
auto node = std::make_shared<clusteringNode>();
std::thread ros_thread([&](){
rclcpp::spin(node);
});
std::thread play_thread(followingSoundPlay);
if(ros_thread.joinable())
ros_thread.join();
if(play_thread.joinable())
play_thread.join();
rclcpp::shutdown();
return 0;
}
Это мой код в кратком виде. Если вам нужно больше объяснений, пожалуйста, дайте знать.
Я пробовал crontab -e, чтобы запустить мой код автоматически при загрузке (я слышал, что systemd довольно критичен, так что пока не пробовал). Конечно, я создал скрипт и дал разрешение 755, и crontab -e — это пользовательский crontab.
Я запускал код вручную — он работает с музыкой, и crontab -e также работает, но только часть с музыкой не сработала. Есть ли что-то, что я пропустил? Если вы это найдете, пожалуйста, дайте мне знать.
PS. Спасибо, что прочитали мой вопрос, несмотря на мой плохой английский.
Одно странное — я пробовал на 2 ПК, но один работает, а другой — нет. Есть ли вероятность, что я неправильно установил Ubuntu?
<div class="s-prose js-post-body" itemprop="text">
<p>Спасибо всем, кто дал совет. Проблема была в переменной DISPLAY cron. Библиотеки, такие как SFML, должны взаимодействовать с GUI дисплеем, но cron не создает его по умолчанию. Поэтому я изменил свой cron на</p>
<pre><code>
DISPLAY=:0
XDG_RUNTIME_DIR=/run/user/(номер из id -u)
***** /path/of/script
Ответ или решение
Для автоматического воспроизведения музыки на Ubuntu 22.04.5 с использованием ROS2 и языка C++ необходимо учесть несколько важных аспектов, таких как правильное использование библиотек, работа с графическим интерфейсом и конфигурация системы для запуска скрипта при загрузке. В данном ответе мы рассмотрим, как правильно организовать воспроизведение музыки в зависимости от состояния робота, а также прокомментируем проблемы, с которыми вы столкнулись.
1. Код для воспроизведения музыки
Ваш код выглядит в целом корректно, но есть некоторые моменты, на которые стоит обратить внимание. Ваша основная функция для воспроизведения звуков (followingSoundPlay) на основе глобального состояния g_target_detecting_state реализована хорошо, однако стоит хорошенько протестировать загрузку и воспроизведение звуков.
Вот как выглядит ваша функция с небольшими улучшениями. Убедитесь, что файлы music1.wav и music2.wav находятся в указанной директории:
#include <SFML/Audio.hpp>
#include <rclcpp/rclcpp.hpp>
#include <thread>
#include <iostream>
#include <chrono>
int g_target_detecting_state = 0; // Глобальная переменная для хранения состояния
void followingSoundPlay() {
sf::SoundBuffer music1_buffer, music2_buffer;
if (!music1_buffer.loadFromFile("audio/music1.wav") || !music2_buffer.loadFromFile("audio/music2.wav")) {
std::cerr << "Не удалось загрузить аудиофайлы!" << std::endl;
return; // Выход из функции, если не удалось загрузить
}
sf::Sound music1_sound, music2_sound;
music1_sound.setBuffer(music1_buffer);
music2_sound.setBuffer(music2_buffer);
while (true) {
switch (g_target_detecting_state) {
case 0: // Цель не обнаружена
music1_sound.stop();
music2_sound.stop();
break;
case 1: // Цель обнаружена
music2_sound.stop();
music1_sound.play();
break;
case 2: // Цель потеряна
music1_sound.stop();
music2_sound.play();
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // Задержка 1 секунда
}
}
2. Настройка автоматического запуска
Для автоматического запуска приложения при загрузке вы используете cron. Действительно, при запуске из пользовательского cron могут возникнуть проблемы с доступом к графическому интерфейсу, так как переменные окружения, такие как DISPLAY, не устанавливаются автоматически. Чтобы решить эту проблему, вы уже нашли правильное решение, добавив соответствующие переменные окружения. Вот правильный формат вашего cron-job:
Убедитесь, что в path/to/your/script указан абсолютный путь к вашему скрипту, и предоставлены права на выполнение (755). Также убедитесь, что скрипт правильно инициализирует ROS и создает необходимые ноды.
3. Отладка
Если на одном компьютере ваш код работает, а на другом – нет, стоит проверить несколько моментов:
Установлены ли все необходимые зависимости? Убедитесь, что на всех компьютерах установлены все необходимые пакеты (включая SFML и ROS2).
Права на доступ к аудиоустройству. Убедитесь, что пользователь, под которым запускается cron, имеет права на доступ к аудиоустройствам.
Проблемы с окружением. Возможные различия в конфигурации и окружении. Выполните env в терминале и в cron для сопоставления окружения.
Заключение
Следуя вышеуказанным рекомендациям, вы сможете улучшить свой код и настроить его для автоматического запуска. Вопросы с переменными окружения в cron не редкость, но их можно успешно решить с помощью установки соответствующих настроек. Если будут еще вопросы или потребуются дополнительные уточнения, не стесняйтесь их задавать.