# 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).

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