|Note: This tutorial assumes that you have completed the previous tutorials: rosserial design notes.|
|Please ask about problems and questions regarding this tutorial on answers.ros.org. Don't forget to include in your question the link to this page, the versions of your OS & ROS, and also add appropriate tags.|
rosserial_embeddedlinux Advanced TechniquesDescription: This tutorial describes several advanced techniques for debugging problems or running or building the package different ways
Tutorial Level: ADVANCED
rosserial_embeddedlinux Design Notes
rosserial_python is designed to be a TCP/IP server, when invoked with the tcp argument. It uses the unix idiom of waiting for a socket connection, then fork/exec-ing the server process to do the requested work while the process parent goes back to waiting for more connection requests. Python multiprocessing is used as the fork technique, but it may not have all the typical unix semantics such as the controlling tty. The program does not exec an external binary - the child handles completing the connection to the ephemeral port and handling messages to/from the client.
Debugging rosserial_python with print statements
Sometimes you need to find out what the python code is doing. A breakpoint can be inserted and the program put into single-step mode by inserting this code at the desired breakpoint location:
import pdb; pdb.set_trace()
It's often difficult to inject breakpoints and have the system stay running in a sane manner - there are timers that will cause the system to retrigger topic exchanges, time, etc. Injecting print statements can be a better approach to understanding what the code is doing.
A consequence of the fork-exec idiom described in the design notes is that the output of print statements is not visible. rosserial_python addresses this by providing a mode of running where it doesn't fork-exec the process. This is controlled by the boolean parameter fork_server, which defaults to True.
To get print statement output to print to your terminal, start rosserial_python with fork_server equal to False by setting the /rosserial_embeddedlinux/fork_server parameter as follows:
rosparam set /rosserial_embeddedlinux/fork_server False rosrun rosserial_python serial_node.py tcp
A consequence of starting this way is that only one embedded linux client at a time will be able to connect to the rosserial_python proxy.
When you're done debugging, remember to delete the parameter:
rosparam delete /rosserial_embeddedlinux/fork_server
Building rosserial_embeddedlinux as a library
You may want to build the rosserial_embeddedlinux module as a library you can link applications against (statically or dynamically). The Makefile below builds it as a static library using the VEXPro toolset. It may be out of date - be forewarned. It is presented as a guide to creating a library. Adjust for your toolchain.
# source files. CPPSRC = time.cpp duration.cpp SRC = embedded_linux_comms.c CPPOBJ = $(CPPSRC:.cpp=.o) OBJ = $(SRC:.c=.o) OUT = librosembeddedlinux.a # include directories INCLUDES = -I/usr/local/terkos/arm/arm-oe-linux-uclibcgnueabi/include \ -I/usr/local/terkos/arm/arm-oe-linux-uclibcgnueabi/usr/include \ -I/usr/local/terkos/arm/arm-oe-linux-uclibcgnueabi/include/terk \ -I. -I.. # C++ compiler flags (-g -O2 -Wall) CCFLAGS = -O0 -g3 -Wall -c -fmessage-length=0 -DBUILD_LIBROSEMBEDDEDLINUX # compiler CCC = /usr/local/terkos/arm/arm-oe-linux-uclibcgnueabi/bin/g++ CC = /usr/local/terkos/arm/arm-oe-linux-uclibcgnueabi/bin/gcc # library paths LIBS = -L../ -L/usr/local/lib -lm # compile flags LDFLAGS = -g .SUFFIXES: .cpp .c default: $(OUT) .c.o: $(CC) $(INCLUDES) $(CCFLAGS) -c $< -o $@ .cpp.o: $(CCC) $(INCLUDES) $(CCFLAGS) -c $< -o $@ $(OUT): $(CPPOBJ) $(OBJ) ar rcs $(OUT) $(OBJ) $(CPPOBJ) clean: rm -f $(OBJ) $(CPPOBJ) $(OUT) Makefile.bak