Feedforward Control
In this lesson, we will learn how to implement feedforward control in Python in a ROS2 Humble environment and create a program to control a mobile robot. The node publishes geometry_msgs/Twist type messages to the /kachaka/manual_control/cmd_vel topic.
Learning Objectives
By the end of this lesson, you will be able to:
- Understand the concept of feedforward control and its applications
- Implement time-based robot control
- Create complex movement sequences by combining basic movements
- Apply feedforward control to generate robot trajectories
1. Program Overview
This program demonstrates feedforward control by:
- Controlling a mobile robot with feedforward control
- Executing movements based on predefined velocity and time
- Combining basic movements such as straight, rotate, and stop to achieve complex movements
2. What is Feedforward Control
Feedforward control is a control method that performs control based only on input without measuring the output of the control target. It executes predefined commands and determines actions by predicting the response of the control target.
In simple terms: Feedforward control is like following a recipe - you follow predetermined steps without checking if the result matches your expectations during the process. This is different from feedback control, which continuously monitors the output and adjusts accordingly.
Features of Feedforward control
- Pre-planning: Plan movements in advance and execute them by specifying time and velocity
- No feedback required: Execute predetermined movements without using sensor data
- Simple implementation: Can be implemented with relatively simple code
- Predictability: Easy to predict the results of movements
When to use Feedforward Control:
- When the robot’s environment is well-known and predictable
- For repetitive tasks with consistent conditions
- When sensor feedback is unavailable or unreliable
- For simple movements that don’t require precision
Difference from Feedback control
Feedback control measures the output of the control target and performs control based on the difference (error) from the target value. On the other hand, feedforward control does not measure the output and performs control based only on input.
3. Prerequisites
- ROS2 Humble is installed
- Python3 is available
- ROS2 workspace (e.g.,
~/ros2_ws) is set up
Required Packages
rclpy: ROS2 Python client librarygeometry_msgs: Package for handling geometric messages such as position and velocity
4. Creating a Package
First, create a package in the src directory of the ROS2 workspace.
cd ~/ros2_ws/src
ros2 pkg create --build-type ament_python kachaka_feedforward_control --dependencies rclpy geometry_msgs --node-name kachaka_feedforward_controlThis command generates a package with the following structure:
kachaka_feedforward_control/
├── resource/
│ └── kachaka_feedforward_control
├── kachaka_feedforward_control/
│ ├── __init__.py
│ └── kachaka_feedforward_control.py
├── test/
├── package.xml
└── setup.py5. Node Implementation
Create a kachaka_feedforward_control.py file with the following content in the kachaka_feedforward_control directory within the kachaka_feedforward_control package.
kachaka_feedforward_control.py
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from geometry_msgs.msg import Twist
from rclpy.duration import Duration
class KachakaFeedforwardControl(Node):
def __init__(self):
super().__init__('kachaka_feedforward_control')
# Create a Publisher that sends Twist type messages to the /kachaka/manual_control/cmd_vel topic
self.publisher = self.create_publisher(Twist, '/kachaka/manual_control/cmd_vel', 10)
def time_control(self, velocity, yawrate, time_seconds):
"""
Control the robot at specified speed and time using feedforward control.
This method implements time-based feedforward control. It publishes velocity
commands continuously for a specified duration without checking the robot's
actual position or state. This is the essence of feedforward control -
executing predetermined commands based on time.
Parameters:
velocity: Forward/backward speed [m/s]
- Positive: forward motion
- Negative: backward motion
- Zero: no linear motion
yawrate: Rotation speed [rad/s]
- Positive: counterclockwise rotation (left when moving forward)
- Negative: clockwise rotation (right when moving forward)
- Zero: no rotation
time_seconds: Movement duration [seconds]
- How long to maintain this velocity command
"""
# Create a Twist message to hold the velocity command
vel = Twist()
vel.linear.x = velocity # Set linear velocity (forward/backward)
vel.angular.z = yawrate # Set angular velocity (rotation)
# Calculate the target end time
# This is when we want to stop publishing this velocity command
end_time = self.get_clock().now() + Duration(seconds=time_seconds)
# Continue publishing velocity commands until the specified time
# This loop ensures commands are sent regularly (every 0.1 seconds)
# The robot needs continuous commands to maintain movement
while self.get_clock().now() < end_time:
# Publish the velocity command
self.publisher.publish(vel)
# Process callbacks and wait 0.1 seconds
# This prevents the loop from consuming too much CPU
rclpy.spin_once(self, timeout_sec=0.1)
# Note: Unlike the simple control example, this method doesn't explicitly stop
# The next command in the sequence will determine the robot's next action
def main(args=None):
rclpy.init(args=args)
kachaka_feedforward_control = KachakaFeedforwardControl()
try:
# Execute the following movement sequence
kachaka_feedforward_control.time_control(0.0, 0.0, 0.5) # Stop
kachaka_feedforward_control.time_control(0.1, 0.0, 2.0) # Forward
kachaka_feedforward_control.time_control(0.0, 0.0, 0.5) # Stop
kachaka_feedforward_control.time_control(-0.1, 0.0, 2.0) # Backward
kachaka_feedforward_control.time_control(0.0, 0.0, 0.5) # Stop
kachaka_feedforward_control.time_control(0.0, 0.5, 2.0) # Rotate left
kachaka_feedforward_control.time_control(0.0, 0.0, 0.5) # Stop
kachaka_feedforward_control.time_control(0.0, -0.5, 2.0) # Rotate right
except KeyboardInterrupt:
pass
finally:
kachaka_feedforward_control.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()6. Editing setup.py
If you are not using –node-name, set the entry point in setup.py at the package root.
entry_points={
'console_scripts': [
'kachaka_feedforward_control = kachaka_feedforward_control.kachaka_feedforward_control:main'
],
},7. Building and Running the Package
Building the Package
cd ~/ros2_ws
colcon build --packages-select kachaka_feedforward_controlLoading Environment Settings
source install/setup.bashRunning the Node
ros2 run kachaka_feedforward_control kachaka_feedforward_control8. Detailed Code Explanation
Classes and Methods
KachakaFeedforwardControl: Main node class__init__: Node initialization and publisher setuptime_control: Method to control the robot at specified speed and time
Control Parameters
velocity: Forward speed [m/s]- Positive value: Forward
- Negative value: Backward
- 0: Stop
yawrate: Rotation speed [rad/s]- Positive value: Rotate left
- Negative value: Rotate right
- 0: No rotation
time_seconds: Time to continue the movement [seconds]
Movement Sequence
The program executes the following movement sequence:
- Stop (0.5 seconds)
- Forward (2.0 seconds)
- Stop (0.5 seconds)
- Backward (2.0 seconds)
- Stop (0.5 seconds)
- Rotate left (2.0 seconds)
- Stop (0.5 seconds)
- Rotate right (2.0 seconds)
Implementation Points of Feedforward Control
Time-based Control:
- The
time_controlmethod moves the robot at a constant speed (velocity,yawrate) for the specified time (time_seconds) - It calculates the end time (
end_time) and continues publishing velocity commands until that time
- The
Continuous Publishing of Velocity Commands:
- In ROS2, velocity commands must be published continuously
- It calls the
publishmethod within awhileloop and publishes velocity commands at regular intervals (0.1 seconds)
Combining Movements:
- Combine basic movements such as straight, rotate, and stop to achieve complex movement sequences
- Insert stops between each movement to make movement transitions clear
Exercises
Trajectory Generation
Feedforward control is suitable for moving a robot along a pre-planned trajectory. For example, you can generate the following trajectories:
- Square trajectory
- Circular trajectory
- Figure-8 trajectory
Parameter Adjustment
By adjusting the following parameters according to the robot’s characteristics, more accurate control becomes possible:
- Velocity (
velocity,yawrate) - Movement time (
time_seconds) - Stop time between movements
Triangular Trajectory
Let’s implement a function to make the robot draw a triangular trajectory using feedforward control.
Application
Try creating your favorite trajectory!