diff --git a/.github/workflows/foxy.yaml b/.github/workflows/foxy.yaml index ec512f3..c9f011e 100644 --- a/.github/workflows/foxy.yaml +++ b/.github/workflows/foxy.yaml @@ -1,4 +1,4 @@ -name: foxy +name: Build and Test on: push: @@ -10,9 +10,16 @@ on: jobs: build-and-test: + strategy: + matrix: + env: + - { ROS_DISTRO: foxy} + - { ROS_DISTRO: humble } + - { ROS_DISTRO: jazzy } + runs-on: ubuntu-latest container: - image: ros:foxy-ros-base + image: ros:${{ matrix.env.ROS_DISTRO }}-ros-base steps: - name: Install pigpio run: | @@ -23,7 +30,7 @@ jobs: sudo make install - name: Build Workspace run: | - . /opt/ros/foxy/setup.sh + . /opt/ros/${{ matrix.env.ROS_DISTRO }}/setup.sh mkdir -p ros2_ws/src cd ros2_ws colcon build @@ -33,7 +40,7 @@ jobs: path: ros2_ws/src/frootspi - name: Build run: | - . /opt/ros/foxy/setup.sh + . /opt/ros/${{ matrix.env.ROS_DISTRO }}/setup.sh cd ros2_ws/src git clone https://github.com/SSL-Roots/consai_frootspi_msgs.git git clone https://github.com/SSL-Roots/frootspi_msgs.git @@ -44,7 +51,7 @@ jobs: colcon build --symlink-install - name: Test run: | - . /opt/ros/foxy/setup.sh + . /opt/ros/${{ matrix.env.ROS_DISTRO }}/setup.sh . ros2_ws/install/setup.sh cd ros2_ws colcon test diff --git a/README.md b/README.md index 0ed29f0..8f4a20f 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,14 @@ $ source ~/ros2_ws/install/setup.bash [SSL-Roots/init_frootspi_gpio_script](https://github.com/SSL-Roots/init_frootspi_gpio_script) のスクリプトを実行してください。 +### Robot IDの設定 + +ホームディレクトリに`robot_config.yaml`ファイルを作成し、ロボットIDを設定します。 + +```yaml +robot_id: 1 +``` + ## Examples ### Start frootspi @@ -81,6 +89,12 @@ $ ros2 launch frootspi_examples hardware.launch.py $ ros2 topic echo /switch_state ``` +### Robotを起動する + +```sh +$ ros2 launch frootspi_examples robot.launch.py +``` + ### Joystickを用いた動作確認 1. 手持ちのJoystickをRaspberryPiに接続します。 2. `frootspi_examples/launch/joycon.launch.py` の `joy_config` が、手持ちのJoystickに対応したコンフィグに設定されていることを確認します。 diff --git a/frootspi_examples/launch/conductor.launch.py b/frootspi_examples/launch/conductor.launch.py index fd8681c..9e91212 100644 --- a/frootspi_examples/launch/conductor.launch.py +++ b/frootspi_examples/launch/conductor.launch.py @@ -15,6 +15,7 @@ from launch import LaunchDescription from launch.actions import DeclareLaunchArgument from launch.substitutions import LaunchConfiguration + from launch_ros.actions import ComposableNodeContainer from launch_ros.actions import PushRosNamespace from launch_ros.descriptions import ComposableNode diff --git a/frootspi_examples/launch/hardware.launch.py b/frootspi_examples/launch/hardware.launch.py index 81b4921..4a5d588 100644 --- a/frootspi_examples/launch/hardware.launch.py +++ b/frootspi_examples/launch/hardware.launch.py @@ -13,12 +13,15 @@ # limitations under the License. import os + from ament_index_python.packages import get_package_share_directory + from launch import LaunchDescription from launch.actions import ExecuteProcess from launch.actions import RegisterEventHandler from launch.event_handlers import OnProcessExit from launch.event_handlers import OnProcessStart + from launch_ros.actions import ComposableNodeContainer from launch_ros.descriptions import ComposableNode diff --git a/frootspi_examples/launch/joycon.launch.py b/frootspi_examples/launch/joycon.launch.py index 2c409ab..07766c7 100644 --- a/frootspi_examples/launch/joycon.launch.py +++ b/frootspi_examples/launch/joycon.launch.py @@ -14,10 +14,13 @@ import os + from ament_index_python.packages import get_package_share_directory + from launch import LaunchDescription from launch.actions import DeclareLaunchArgument from launch.substitutions import LaunchConfiguration + from launch_ros.actions import Node diff --git a/frootspi_examples/launch/robot.launch.py b/frootspi_examples/launch/robot.launch.py index 8700dc5..4fe6e90 100644 --- a/frootspi_examples/launch/robot.launch.py +++ b/frootspi_examples/launch/robot.launch.py @@ -13,19 +13,23 @@ # limitations under the License. import os +from pathlib import Path + from ament_index_python.packages import get_package_share_directory + from launch import LaunchDescription from launch.actions import ExecuteProcess from launch.actions import IncludeLaunchDescription from launch.launch_description_sources import PythonLaunchDescriptionSource + from launch_ros.actions import ComposableNodeContainer from launch_ros.actions import PushRosNamespace from launch_ros.descriptions import ComposableNode + import yaml -from pathlib import Path -DEFAULT_FILE_PATH = Path.home() / Path("robot_config.yaml") +DEFAULT_FILE_PATH = Path.home() / Path('robot_config.yaml') def get_configuration_from_file(file_path): @@ -34,7 +38,7 @@ def get_configuration_from_file(file_path): # yamlで書かれた設定ファイルから値を取得する with open(file_path, 'r') as f: config = yaml.safe_load(f) - print(f"Read robot config from {file_path}") + print(f'Read robot config from {file_path}') return config diff --git a/frootspi_examples/systemd/robot_launch.sh b/frootspi_examples/systemd/robot_launch.sh index 5a0455a..57b2df5 100755 --- a/frootspi_examples/systemd/robot_launch.sh +++ b/frootspi_examples/systemd/robot_launch.sh @@ -6,7 +6,7 @@ ROS_DOMAIN_ID_VALUE=22 if [ -f ${ENVFILE} ]; then #環境変数読み込み echo "Loading ROS2 Env..." - source /opt/ros/foxy/setup.bash + source /opt/ros/jazzy/setup.bash source ${ENVFILE} export ROS_DOMAIN_ID=${ROS_DOMAIN_ID_VALUE} diff --git a/frootspi_hardware/src/kicker.cpp b/frootspi_hardware/src/kicker.cpp index 2a5ca74..881308f 100644 --- a/frootspi_hardware/src/kicker.cpp +++ b/frootspi_hardware/src/kicker.cpp @@ -84,12 +84,19 @@ bool Kicker::kickStraight(uint32_t powerMmps) if (this->debug_mode_) {return false;} uint32_t sleep_time_usec; - if (powerMmps < 2000) sleep_time_usec = OPENTIME_1MS; - else if (powerMmps < 3000) sleep_time_usec = OPENTIME_2MS; - else if (powerMmps < 4000) sleep_time_usec = OPENTIME_3MS; - else if (powerMmps < 5000) sleep_time_usec = OPENTIME_4MS; - else if (powerMmps < 6000) sleep_time_usec = OPENTIME_5MS; - else sleep_time_usec = OPENTIME_6MS; + if (powerMmps < 2000) { + sleep_time_usec = OPENTIME_1MS; + } else if (powerMmps < 3000) { + sleep_time_usec = OPENTIME_2MS; + } else if (powerMmps < 4000) { + sleep_time_usec = OPENTIME_3MS; + } else if (powerMmps < 5000) { + sleep_time_usec = OPENTIME_4MS; + } else if (powerMmps < 6000) { + sleep_time_usec = OPENTIME_5MS; + } else { + sleep_time_usec = OPENTIME_6MS; + } if (sleep_time_usec > MAX_SLEEP_TIME_USEC_FOR_STRAIGHT) { sleep_time_usec = MAX_SLEEP_TIME_USEC_FOR_STRAIGHT; diff --git a/frootspi_joycon/frootspi_joycon/joycon.py b/frootspi_joycon/frootspi_joycon/joycon.py index cc833c8..1435fd4 100755 --- a/frootspi_joycon/frootspi_joycon/joycon.py +++ b/frootspi_joycon/frootspi_joycon/joycon.py @@ -18,10 +18,13 @@ import math -import rclpy from geometry_msgs.msg import Twist + +import rclpy from rclpy.node import Node + from sensor_msgs.msg import Joy + from std_msgs.msg import Float32, Int16 diff --git a/frootspi_speaker/frootspi_speaker/speaker.py b/frootspi_speaker/frootspi_speaker/speaker.py index 75c8e64..4e2791b 100755 --- a/frootspi_speaker/frootspi_speaker/speaker.py +++ b/frootspi_speaker/frootspi_speaker/speaker.py @@ -16,11 +16,14 @@ # limitations under the License. import csv -from frootspi_msgs.msg import SpeakerVoice import os + +from frootspi_msgs.msg import SpeakerVoice + import rclpy from rclpy.executors import ExternalShutdownException from rclpy.node import Node + import simpleaudio @@ -52,14 +55,14 @@ class Speaker(Node): def __init__(self): super().__init__('speaker') - self._voices_path = self.declare_parameter('voices_path', "").value - self._file_list_path = self._voices_path + "/" + \ - self.declare_parameter('file_list_name', "voice_file_list.csv").value + self._voices_path = self.declare_parameter('voices_path', '').value + self._file_list_path = self._voices_path + '/' + \ + self.declare_parameter('file_list_name', 'voice_file_list.csv').value # TODO(ShotaAk): CSVファイルのフォーマットもチェックしたい if not os.path.isfile(self._file_list_path): self.get_logger().info('file exist') - raise ValueError("File:{} does not exist!".format(self._file_list_path)) + raise ValueError('File:{} does not exist!'.format(self._file_list_path)) self._file_dict = self.make_file_dict(self._file_list_path) @@ -72,9 +75,9 @@ def make_file_dict(self, file_list_path): with open(file_list_path, 'r') as f: reader = csv.DictReader(f) for r in reader: - voice_type = r["type"] + voice_type = r['type'] if hasattr(SpeakerVoice, voice_type): - file_dict[getattr(SpeakerVoice, voice_type)] = r["file_name"] + file_dict[getattr(SpeakerVoice, voice_type)] = r['file_name'] return file_dict @@ -83,8 +86,8 @@ def callback(self, msg): self.get_logger().info('Voice type:{} does not defined.'.format(msg.voice_type)) return - voice_file_path = self._voices_path + "/" + self._file_dict[msg.voice_type] - if not os.path.isfile(voice_file_path) or not voice_file_path.endswith(".wav"): + voice_file_path = self._voices_path + '/' + self._file_dict[msg.voice_type] + if not os.path.isfile(voice_file_path) or not voice_file_path.endswith('.wav'): self.get_logger().info('File:{} is not wav file.'.format(voice_file_path)) return diff --git a/frootspi_speaker/launch/speaker.launch.py b/frootspi_speaker/launch/speaker.launch.py index addf9eb..2564279 100644 --- a/frootspi_speaker/launch/speaker.launch.py +++ b/frootspi_speaker/launch/speaker.launch.py @@ -33,7 +33,7 @@ def generate_launch_description(): ) declare_file_list_name = DeclareLaunchArgument( - 'file_list_name', default_value="voice_file_list.csv", + 'file_list_name', default_value='voice_file_list.csv', description=('Set voice file list name.') )