Integration in user software¶
So far, we documented the usage of o80 via a standalone, i.e. a python method which spaws a process running the (c++) interaction with the driver.
But one may desire to use o80’s frontend API while using their own software architecture.
It is possible to do so by encapsulating an instance of o80::BackEnd to the architecture. This could be done either in python and in c++.
in python¶
backend¶
Similarly than for the FrontEnd and the start_standalone method, the python package wraps the BackEnd class.
import o80_robot
backend = o80_robot.BackEnd(segment_id)
A backend instance provides a single method, pulse, which takes the current observed states of the joints as arguments, and returns the current desired states to apply to the robot (as computed based on the queues of commands sent by an eventual frontend).
A call to BackEnd::pulse performs:
read the queue of commands as generated by an eventual frontend.
compute for each joint its desired states, according to the current queue of commands.
creates an instance of o80::Observation, and writes it to the shared memory (i.e. makes it available to FrontEnd::pulse, FrontEnd::latest, etc)
returns an instance of o80::States, which encapsulate for each joint its desired state.
An instance of BackEnd may be used in the user’s code:
import o80_robot
#
# user initialization code
#
# ...
#
backend = o80_robot.BackEnd(segment_id)
while running:
# user code compute and extract from sensors
# the current joint states
# calling the pulse method of the backend
# (current_states: list of size number of joints)
desired_states = backend.pulse(current_states)
# user code for applying the desired state
# to the robot
time.sleep(0.001)
The pulse function has several overloads. The most complete is:
time_stamp = o80::time_now()
extended_state = MyUserClass()
iteration_update = False
current_iteration = 1000
frontend.pulse(time_stamp,
current_states,
extended_state,
iteration_update,
1000)
time_stamp will be the time stamp encapsulated in the Observation the BackEnd will write in the shared memory.
extended_state is an instance of ExtendedState
iteration_update to False means the BackEnd should not use its internal counter to set the iteration number of the Observation, but rather use the current_iteration argument (iteration_update to False and current_iteration to -1 to use the internal counter)
Other overloads are:
# will use current time as time_stamp, default constructor of ExtendedState, internal iteration counter, and default constructors for desired states.
frontend.pulse()
# same as above, but will use the passed argument for extended state
frontend.pulse(extended_state)
# same as above, but will use the passed argument for desired states
frontend.pulse(desired_states)
bursting mode¶
To use the bursting mode in a user software, you may update the control loop:
import o80_robot
import o80
#
# user initialization code
#
# ...
#
backend = o80_robot.BackEnd(segment_id)
burster = o80.Burster(segment_id)
while running:
# user code compute and extract from sensors
# the current joint states
# calling the pulse method of the backend
# (current_states: list of size number of joints)
desired_states = backend.pulse(current_states)
# user code for applying the desired state
# to the robot
# ! commented, frequency will be managed by
# the burster instead
# time.sleep(0.001)
burster.pulse()
In the above, when its method pulse is called, the loop will hold until a frontend calls its burst function.
in c++¶
An equivalent API is provided in c++.