Загрузка данных
Задание 3 — по аналогии с квадратом, но для прямоугольника (стороны разной длины) и треугольника (повороты на 120°). Делай так:
**Шаг 1. Создай файл rectangle_publisher.py** в `~/ros2_ws/src/lab_turtlesim/lab_turtlesim/`
```python
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from geometry_msgs.msg import Twist
import math
class RectanglePublisher(Node):
LINEAR_SPEED = 1.0
ANGULAR_SPEED = math.pi / 2
SIDE_DURATIONS = [2.0, 1.0, 2.0, 1.0]
TURN_DURATION = 1.0
def __init__(self):
super().__init__('rectangle_publisher')
self.publisher_ = self.create_publisher(Twist, '/turtle1/cmd_vel', 10)
self.timer_period = 0.1
self.timer = self.create_timer(self.timer_period, self.timer_callback)
self.side_index = 0
self.state = 'forward'
self.state_start_time = self.get_clock().now()
self.get_logger().info('RectanglePublisher node started')
def timer_callback(self):
try:
if self.publisher_.get_subscription_count() == 0:
self.get_logger().warn('No subscribers on /turtle1/cmd_vel, is turtlesim running?')
return
msg = Twist()
current_time = self.get_clock().now()
state_elapsed_time = (current_time - self.state_start_time).nanoseconds / 1e9
if self.state == 'forward':
side_duration = self.SIDE_DURATIONS[self.side_index]
msg.linear.x = self.LINEAR_SPEED
msg.angular.z = 0.0
if state_elapsed_time >= side_duration:
self.state = 'turn'
self.state_start_time = self.get_clock().now()
self.get_logger().info('Turning 90 degrees...')
elif self.state == 'turn':
msg.linear.x = 0.0
msg.angular.z = self.ANGULAR_SPEED
if state_elapsed_time >= self.TURN_DURATION:
self.side_index = (self.side_index + 1) % len(self.SIDE_DURATIONS)
self.state = 'forward'
self.state_start_time = self.get_clock().now()
self.get_logger().info('Moving forward...')
self.publisher_.publish(msg)
except Exception as e:
self.get_logger().error(f'Error in timer_callback: {str(e)}')
def main(args=None):
rclpy.init(args=args)
rectangle_publisher = RectanglePublisher()
try:
rclpy.spin(rectangle_publisher)
except KeyboardInterrupt:
rectangle_publisher.get_logger().info('Node stopped by user')
except Exception as e:
rectangle_publisher.get_logger().error(f'Unexpected error: {str(e)}')
finally:
rectangle_publisher.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
```
**Шаг 2. Создай файл triangle_publisher.py** в той же папке
```python
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from geometry_msgs.msg import Twist
import math
class TrianglePublisher(Node):
LINEAR_SPEED = 1.0
SIDE_DURATION = 2.0
TURN_DURATION = 1.0
ANGULAR_SPEED = (2 * math.pi / 3) / TURN_DURATION
def __init__(self):
super().__init__('triangle_publisher')
self.publisher_ = self.create_publisher(Twist, '/turtle1/cmd_vel', 10)
self.timer_period = 0.1
self.timer = self.create_timer(self.timer_period, self.timer_callback)
self.state = 'forward'
self.state_start_time = self.get_clock().now()
self.get_logger().info('TrianglePublisher node started')
def timer_callback(self):
try:
if self.publisher_.get_subscription_count() == 0:
self.get_logger().warn('No subscribers on /turtle1/cmd_vel, is turtlesim running?')
return
msg = Twist()
current_time = self.get_clock().now()
state_elapsed_time = (current_time - self.state_start_time).nanoseconds / 1e9
if self.state == 'forward':
msg.linear.x = self.LINEAR_SPEED
msg.angular.z = 0.0
if state_elapsed_time >= self.SIDE_DURATION:
self.state = 'turn'
self.state_start_time = self.get_clock().now()
self.get_logger().info('Turning 120 degrees...')
elif self.state == 'turn':
msg.linear.x = 0.0
msg.angular.z = self.ANGULAR_SPEED
if state_elapsed_time >= self.TURN_DURATION:
self.state = 'forward'
self.state_start_time = self.get_clock().now()
self.get_logger().info('Moving forward...')
self.publisher_.publish(msg)
except Exception as e:
self.get_logger().error(f'Error in timer_callback: {str(e)}')
def main(args=None):
rclpy.init(args=args)
triangle_publisher = TrianglePublisher()
try:
rclpy.spin(triangle_publisher)
except KeyboardInterrupt:
triangle_publisher.get_logger().info('Node stopped by user')
except Exception as e:
triangle_publisher.get_logger().error(f'Unexpected error: {str(e)}')
finally:
triangle_publisher.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
```
**Шаг 3. Открой setup.py** и добавь обе новые ноды в `entry_points`:
```python
entry_points={
'console_scripts': [
'square_publisher = lab_turtlesim.square_publisher:main',
'rectangle_publisher = lab_turtlesim.rectangle_publisher:main',
'triangle_publisher = lab_turtlesim.triangle_publisher:main',
],
},
```
**Шаг 4. Пересобери пакет**
```bash
cd ~/ros2_ws
colcon build --packages-select lab_turtlesim
source install/setup.bash
```
**Шаг 5. Запусти и сделай скриншоты**
В одном терминале:
```bash
ros2 run turtlesim turtlesim_node
```
В другом:
```bash
ros2 run lab_turtlesim rectangle_publisher
```
Сделай скриншот траектории, потом перезапусти симулятор (`Ctrl+C` и заново `ros2 run turtlesim turtlesim_node`) и запусти:
```bash
ros2 run lab_turtlesim triangle_publisher
```
Скриншот траектории треугольника — для отчёта.