An article describing how to write plug-ins is available here.
(ssh to your target device if needed)
git clone --depth=1 https://github.com/bob-linuxtoys/eedd.git
cd eedd; make
sudo make install
# Start the empty daemon (background but not a daemon)
export PATH=$PATH:/usr/local/bin
eddaemon -ef &
# Load the "hello, world" demo plug-in
edloadso hellodemo.so
# Subscribe to the message service of hellodemo
edcat hello_demo message # "hello, world" once a second
# Open a second terminal window, and subscribe again
export PATH=$PATH:/usr/local/bin
edcat hello_demo message # "hello, world" once a second
# Open a third terminal window
# Change the print period to 2 seconds
export PATH=$PATH:/usr/local/bin
edset hello_demo period 2
# Change the printed string to good-bye
edset hello_demo messagetext good-bye
# Display info about the system and about hellodemo
edlist
edlist hello_demo
The above shows how to start the empty daemon, how to load a plug-in,
how to subscribe to a data stream, and how to change parameters while
the program is running.
edloadso <plug-in.so>
edget <name|ID#> <resource_name>
edset <name|ID#> <resource_name> <value>
edcat <name|ID#> <resource_name>
edlist [name]
Each of the above has an equivalent bash command that behind the scenes opens a TCP connection and sends the command. (You can use telnet to connect directly to the empty daemon if you wish.) You'll find that having Bash commands to get or change plug-in parameters makes it easy to use a script file to drive your project or to help automate its testing.
The edloadso command starts everything by loading a shared object plug-in. Plug-ins are user-space device drivers that interface to the underlying hardware or software service. EEDD provide sample drivers that include interfaces to a game controller, to IRC (for robot team communication), and to a GPS receiver.
Each time a plug-in is loaded it is given a slot ID. Slots are numbered sequentially starting from zero. It is possible to load a plug-in twice. Since the two instances have the same name you'll want to use the slot ID to differentiate them in the get, set, and cat commands.
If you have a USB game controller you can test it by plugging it
into your computer and starting the daemon as described above. Load
the game controller plug-in with:
edloadso gamepad.so
Resources are ASCII printable values stored in an instance of a plug-in. Resources can be read-only, read-write, or broadcast. You can view a readable resource's value with the edget command and set a read-write value with the edset command. Callbacks in the plug-in are invoked when you get or set a resource, or start a stream.
Although resources are presented as a static values, callbacks for writing or reading a resource can be used as a command to the system. For example, setting robot's motor mode to BRAKE would trigger sending the underlying commands to stop the motor.
For example, the game controller has a resource that tells the system
where in /dev to find the device for the game controller. Tell EEDD where
your game controller is located with a command like:
edset gamepad device /dev/input/js0
The edcat command starts a stream of data. The TCP connection becomes dedicated to just that stream of data. As you write applications you'll find that you have a TCP connection for each sensor stream, and one more connection for get and set commands.
You can start a stream of game controller state information with the
command:
edcat gamepad state
The command edlist gives a list of the plug-ins that are loaded. It also shows the resources associated with each plug-in.
The edlist command doubles as the help system. If you give the edlist command followed by the name of a plug-in you'll get the help text for that plug-in. This makes writing applications easier since the meaning and syntax of a plug-in's resources are easy to see.
You can list the plug-ins in your system and get help for the game
controller with the commands
edlist
edlist gamepad
Each of the get, set, list, and loadso commands return a backslash to indicate that the command has completed. If the command fails for any reason an error message is given. The error message is followed by a backslash to indicate that the command has completed.
Be sure your application reads the backslash from the command connection or the socket's receive buffer will fill and all communication over the socket will fail.
Let's say you want to use the game controller described above to control a small two wheeled robot. You're using an FPGA based robot controller that offers an EEDD plug-in that let's you set the mode and PWM pulse width for two H-bridges motor controllers.
The motor_cntrl plug-in has a mode resource that indicates the H-bridge configuration. Mode is given as two space separated character in 'frbc' (forward, reverse, brake, and coast). The PWM widths are two floating point numbers in the range of 0.0 to 100.0. Spinning in place at a high speed could be accomplished with:edset motor_cntrl mode f r edset motor_cntrl pwm 100 100
The 'filter' resource in the gamepad plug-in let's you remove specific
fields from the state data stream. After reading 'edlist gamepad' you've
decided to us a filter of edffff so an edcat of the gamepad state resource
gives a stream of data in the form:
The full Python program to implement gamepad control of the robot is given below:
#!/usr/bin/env python
import socket
import sys
''' This program opens two sockets to the eddaemon, one
to listen for gamepad events and one to update the
motors. This code uses a blocking read but a select()
implementation would work too.
'''
# Send a set command to the fpga and wait for the response prompt
def set_cmd(sock, set_str):
sock.send(set_str)
while True:
retval = sock.recv(1)
if retval == '\\':
break
try:
sock_cmd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock_cmd.connect(('localhost', 8870))
sock_gamepad = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock_gamepad.connect(('localhost', 8870))
set_cmd(sock_gamepad, 'edset gamepad filter edffff\n')
sock_gamepad.send('edcat gamepad state\n')
# loop forever getting gamepad joystick positions
while True:
gamepad_state= sock_gamepad.recv(1024).split()
# Gamepad analog output a value between -32767 and +32767.
if (int(gamepad_state[1]) > 20)
left_pwm = {0:.2f}".format(int(gamepad_state[1]) / 327.6)
left_mode = "f"
else if (int(gamepad_state[1]) < -20)
left_pwm = {0:.2f}".format(-int(gamepad_state[1]) / 327.6)
left_mode = "r"
else
left_pwm = "0.0"
left_mode = "b"
if (int(gamepad_state[2]) > 20)
right_pwm = {0:.2f}".format(int(gamepad_state[2]) / 327.6)
right_mode = "f"
else if (int(gamepad_state[2]) < -20)
right_pwm = {0:.2f}".format(-int(gamepad_state[2]) / 327.6)
right_mode = "r"
else
right_pwm = "0.0"
right_mode = "b"
# Set the mode and speeds
set_cmd(sock_cmd, 'edset motor_cntrl mode c c\n')
set_cmd(sock_cmd, 'edset motor_cntrl pwm '+left_pwm+' '+right_pwm+'\n')
set_cmd(sock_cmd, 'edset motor_cntrl mode '+left_mode+' '+right_mode+'\n')
except KeyboardInterrupt:
# exit on Ctrl^C
sock_cmd.close()
sock_gamepad.close()
sys.exit()
except socket.error:
print "Couldn't connect to eddaemon"
sys.exit()
Each of the EEDD protocol commands has a corresponding shell equivalent.
You may find initial debugging is easier using shell scripts to exercise
the hardware. For example, the following shell script lacks reverse but
is otherwise equivalent to the above Python program.
#!/bin/bash
edset gamepad filter edffff
unbuffer edcat gamepad state |
while read tm l r
do
modl="c"
if (( $l >= 20 ))
then
motl=$(( $l / 328 ))
modl="f"
fi
modr="c"
if (( $r >= 20 ))
then
motl=$(( $r / 328 ))
modr="f"
fi
edset ed_motor mode $modl $modr
edset motor_cntrl pwm $motl $motr
echo $l $r $motl $motr
done
|
|
|
|
 - EEDD is released under the GPLv2 and github is the official
source code repository. If you would like to participate
let me know and I'll give you commit access to the repository.
The repository is here:
https://github.com/bob-linuxtoys/eedd.
- Although the empty daemon is written in C the plug-ins can be written in any language that can produce a shared object file.
- Plug-ins do not need to be released under the GPL. If you have driver code you would like to keep proprietary you can place it in a plug-in without any issues.
- When you build EEDD you can give the commands a prefix other than 'ed'. Just change CPREFIX in the EEDD top level Makefile.
- EEDD provides comes with three plug-ins that might be of use
to robot builders. Each plug-in has a readme file that tells you how
to use the plug-in and how to install any required hardware or software.
The plug-in readme files are available here:
- Game Controller
- Team Communications using IRC
- Text-to-Speech
- VL53L0X Time-of-flight distance sensor
- EEDD has two permanent branches. One is for the Home Brew Automation FPGA based robot. The other is for the Demand Peripherals FPGA based robot. Their respective git branch names are "hba" and "dpi".