Getting Started

This guide will walk you through setting up the navel SDK and running your first scripts.


On the navel robot, run the following commands:

# Create a venv and activate it
python3 -m venv .venv/
source .venv/bin/activate

# Install the SDK and its dependencies:
pip install navel

Before running any scripts, start bodyd and allow it to finish initializing.


To start getting familiar with programming using the SDK, try running the following script:

 1import navel
 3def main():
 4    with navel.Robot() as robot:
 5        robot.rotate_arms(180,180)
 6        robot.say("Hallo, welt!")
 7        robot.rotate_arms(0,0)
 9if __name__ == "__main__":
10    main()
A few things are happening here:
  • We’re creating an instance of the Robot class (line 4), which handles sending commands to the robot

  • We’re sending commands to move the arms and say a sentence (lines 5-7)

  • Exiting the with block automatically takes care of cleaning up connections for us

When the script is run, Navel should lift its arms, celebrating that everything was set up correctly, and then say “Hello world”. But what if you’d like it to move its arms while speaking? It would seem that’s not possible – indeed, with our current set-up, it isn’t.

In order to support multiple actions at once, the navel python library relies heavily on python’s asyncio lib. We can therefore change the above program to take advantage of this:

1import navel
3async def main(robot: navel.Robot):
4    robot.say("Hallo, welt!")
5    await robot.rotate_arms(180,180)
6    await robot.rotate_arms(0,0)
8if __name__ == "__main__":
You may notice a couple of differences:
  • There’s now an async keyword in front of our main function definition: this is necessary to allow us to take advantage of concurrent programming in the function body.

  • The function now takes an argument of type navel.Robot instead of creating it inside: this allows the navel library to do all the setup for concurrency for us.

  • There’s now an await keyword in front of the arm movements, so that we wait for the movement to be done before continuing.

  • We changed how the function is run, from a simple main() to this takes care of all the boilerplate now that our function has become a coroutine.

This time, Navel should lift its arms while speaking. A similar interface is available for most functions, so that you can either run them directly and do something else while they run, or await them and wait for them to be finished. Go ahead, try putting an await before the robot.say command in line 4 and see what happens. There’s also much more you can do, such as assigning the result of a function to a variable and awaiting it later, cancelling it, or simply checking if it’s done. Under the hood, all async functions in the Robot class return an asyncio Task, so anything you can do with them is supported.

Let’s see an example using slightly more complex logic:

 1import navel
 3async def main(robot: navel.Robot):
 4found_person = False
 5while not found_person:
 6    found_person = await search(robot)
 7    await robot.rotate_base(180)
11async def search(robot: navel.Robot):
12    walk = robot.move_base(2, 0.1)
13    while not walk.done():
14        data = await navel.next_frame()
15        if data.persons:
16            walk.cancel()
17            return True
18    return False
20if __name__ == "__main__":

With this program, navel should move back and forth until it sees a person. When a person is seen, we cancel the motion and say hello. Notice also how walk.done() is used to wait for an action to be done while doing something else (in this case looking for people).

And that’s the basics out of the way. For a full breakdown of everything the SDK has to offer, check out the examples and the API Documentation.