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 library
  • geometry_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_control

This 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.py

5. 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_control

Loading Environment Settings

source install/setup.bash

Running the Node

ros2 run kachaka_feedforward_control kachaka_feedforward_control

8. Detailed Code Explanation

Classes and Methods

  • KachakaFeedforwardControl: Main node class
    • __init__: Node initialization and publisher setup
    • time_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:

  1. Stop (0.5 seconds)
  2. Forward (2.0 seconds)
  3. Stop (0.5 seconds)
  4. Backward (2.0 seconds)
  5. Stop (0.5 seconds)
  6. Rotate left (2.0 seconds)
  7. Stop (0.5 seconds)
  8. Rotate right (2.0 seconds)

Implementation Points of Feedforward Control

  1. Time-based Control:

    • The time_control method 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
  2. Continuous Publishing of Velocity Commands:

    • In ROS2, velocity commands must be published continuously
    • It calls the publish method within a while loop and publishes velocity commands at regular intervals (0.1 seconds)
  3. 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!