# RAE SDK

RAE Python SDK contains a set of Python classes and functions that allow you to interact with the RAE robot. Underneath, it uses
ROS2 interfaces for communication with peripherals, as well as ROS libraries.

## Requirements

To be able to use the RAE SDK in Luxonis Hub, you need to:

 * Upgrade your robot's firmware to the latest version (Luxonis OS 1.14).

> **Note**
> After firmware update you could still see an option to upgrade to the latest version. This is a known issue and you can safely ignore it. As long as you have Luxonis OS 1.14 installed and Agent version 23.223.1855, you are good to go.

 * Specify correct image in robotapp.toml file. As of the moment of writing this guide, latest image is
   `ghcr.io/luxonis/rae-ros:v0.2.2-humble`.

## Robot

`Robot` class is the main entry point for the SDK. It provides access to all the robot's components and allows you to control
them. It contains following properties (more on them in later sections):

 * ROS Interface
 * LED
 * Display
 * Audio
 * Movement
 * Perception system

Initializing Robot class also by default launches hardware drivers for peripherals and for wheels unless specified otherwise in
robot's options.

```python
from rae_sdk.robot import Robot

robot = Robot()
```

### Robot Options

You can pass options to the Robot class to customize its behavior. Example showing all available options:

```python

from rae_sdk.robot import Robot, RobotOptions

options = RobotOptions(name='rae_sdk', namespace='', launch_controllers=True, start_hardware=True, launch_mock=False)

robot = Robot(options)
```

 * `name` - name of the ROS node that will be created by the Robot class. Default: `rae_sdk`
 * `namespace` - namespace of the ROS node that will be created by the Robot class. Default: `''`
 * `launch_controllers` - whether to initialize SDK Components such as LED, Display, Audio, Navigation, State. Default: `True`
 * `launch_mock` - whether to launch mock hardware drivers instead of real ones, mostly used for testing. Default: `False`
 * `start_hardware` - whether to start hardware drivers for peripherals and wheels. Default: `True`

To ensure clean shutdown of the robot, you should call `robot.stop()` at the end of your program.

## SDK Components

For the complete list of API methods and properties, please refer to the [API
Reference](https://docs.luxonis.com/hardware/rae/rae-sdk/api-reference.md).

### LED

LED class provides access to the robot's LED. It allows you to set the color of the LED and turn it on and off.

```python
from rae_sdk.robot import Robot

robot = Robot()

robot.led.set_leds('#FF0000', 100, 'solid', 1)  # set color to red
```

You can also use the LEDControl message directly:

```python
from rae_sdk.robot import Robot
from rae_msgs.msg import LEDControl, ColorPeriod

robot = Robot()

led_control = LEDControl()

color_msg = ColorPeriod()
color_msg.frequency = 1.0
color_msg.color.a = 1.0
color_msg.color.r = 1.0
color_msg.color.g = 0.0
color_msg.color.b = 0.0
led_msg.data = [color_msg]

led_msg.control_type = LEDControl.CTRL_TYPE_ALL

robot.set_leds_from_msg(led_msg)
```

### Display

Display class provides access to the robot's display. It allows you to display text and images on the display.

```python
import cv2
from rae_sdk.robot import Robot

robot = Robot()

img = cv2.imread('image.jpg')
robot.display.display_image(img)
```

### Audio

Audio class provides access to the robot's audio system. It allows you to play audio files and text-to-speech.

```python
from rae_sdk.robot import Robot

robot = Robot()

robot.audio.play_audio_file('file.mp3')
```

### Navigation

Navigation class provides access to the robot's movement & navigation system. It allows you to control the robot's wheels and read
it's position.

```python

from rae_sdk.robot import Robot

robot = Robot()

robot.navigation.move(0.5, 0.5)  # move forward with 0.5 m/s speed and 0.5 rad/s angular speed

position = robot.navigation.get_odom_position()
```

### State

State class provides access to the robot's state. It allows you to read the robot's battery level and charging status.

```python

from rae_sdk.robot import Robot

robot = Robot()

battery_level = robot.state.battery_state.capacity
```

### ROS Interface

ROS Interface is a class that provides access to ROS2 interfaces for communication with peripherals, as well as ROS libraries. It
uses `rclpy` library to spin up its own executor and node for communication with ROS2. It also uses ROS2 launch system to bring up
robot nodes. It is abstracted away from the user, but it is possible to access it via `robot.ros_interface` property. For example,
let's create a publisher that publishes a message to `/test_topic` topic with a frequency of 1 Hz:

```python
from rae_sdk.robot import Robot
from std_msgs.msg import String

robot = Robot()

def timer_callback():
    msg = String()
    msg.data = 'Hello world!'
    robot.ros_interface.publish('/test_topic', msg)

robot.ros_interface.create_publisher('/test_topic', String)
robot.ros_interface.create_timer(1.0, timer_callback)
```

You can also create a subscriber that listens to `/test_topic` topic:

```python
from rae_sdk.robot import Robot
from std_msgs.msg import String

def callback(msg):
    print(msg.data)

robot = Robot()

robot.ros_interface.create_subscription('/test_topic', String, callback)
```

Creating a service client is also simple:

```python
from rae_sdk.robot import Robot
from std_srvs.srv import Trigger

robot = Robot()

robot.ros_interface.create_service_client('/test_service', Trigger)
robot.ros_interface.call_async_srv('/test_service', Trigger.Request())
```

Similarly for action clients, if you want you can override default callbacks for accepting the goals, handling feedback, and
handling results. You can also cancel the goal:

```python

from rae_sdk.robot import Robot
from example_interfaces.action import Fibonacci

def feedback_callback(feedback_msg):
    print('Feedback received:', feedback_msg.feedback.sequence)

def result_callback(future):
    result = future.result().result
    print('Result received:', result.sequence)

robot = Robot()

robot.ros_interface.create_action_client('/test_action', Fibonacci)
robot.ros_interface.call_async_action("/fibonacci", Fibonacci.Goal(order=10), None, self.result_cb, self.feedback_cb)

# cancel the goal robot.ros_interface.cancel_action("/fibonacci")
```

### Resources

We also provide a set of example resources that you can utilize in your applications. You can find them in the `assets` folder of
the SDK. For now those resources include a set of face images for the robot and some example audio files that can be used for
basic interaction.
