2013/11/26

A few scripts to speed up tests and deployment for the Lego Mindstorms EV3

In each script where an IP address appears, you must of course replace it by the IP address displayed in the brick info menu.

Enabling SSH

Useful to copy your files on the brick and run some commands applications remotely. You'll need expect to make it work:
#!/usr/bin/expect

#Replace with your IP address
spawn telnet 192.168.1.71
expect "login:"
send "root\r"

#dropbear enables SSH
send "dropbear\r"
send "exit\r"

interact

Connection over Telnet

Connect to your EV3 without the extra cost of the SSH protocol:
#!/usr/bin/expect

#Replace with your IP address
spawn telnet 192.168.1.71

expect "login:"
send "root\r"

interact

Copy a program

Assuming you want to copy it to /media/card/program/program
#!/bin/bash

#Replace with your IP address
EV3_IP=192.168.1.71

if ! [[ $# -eq 1 ]]
then
    echo "Missing parameter : PROJECT NAME"
else
    PROJECT_NAME=$1
    EV3_PROJECT_DIR="/media/card/$1"

    if ! [[ -d $PROJECT_NAME ]]
    then
        echo "Project doesn't exist."
    else
        #Create the project directory
        ssh root@$EV3_IP "mkdir $EV3_PROJECT_DIR"
        scp $PROJECT_NAME/$PROJECT_NAME root@$EV3_IP:$EV3_PROJECT_DIR/$PROJECT_NAME
    fi
fi

Run a program remotely

Run an application over SSH:
#!/bin/bash

#Replace with your IP address
EV3_IP=192.168.1.71

if ! [[ $# -eq 1 ]]
then
    echo "Missing parameter : PROJECT NAME"
else
    PROJECT_NAME=$1
    EV3_PROJECT_PATH="/media/card/$1/$1"

    if ! [[ -d $PROJECT_NAME ]]
    then
        echo "Project doesn't exist."
    else
        #Environment setup and program launch
        ssh root@$EV3_IP \
        "export QT_QPA_PLATFORM_PLUGIN_PATH=/media/card/lib/platforms && \
         export QT_QPA_FONTDIR=/media/card/lib/fonts && \
         $EV3_PROJECT_PATH -platform ev3linuxfb"
    fi
fi

Copy libraries, fonts and platform plugin

Useless if you have a SD card drive on your computer:
#!/bin/bash

#Replace with your IP address
EV3_IP=192.168.1.71

#Depends on your Qt version
VERSION=5
FULL_VERSION=$VERSION.1.1

#Depends on the '-prefix' configure option you choose to compile Qt
SOURCE_DIR=/home/user/Qt$FULL_VERSION

#Depends on the '-qtlibinfix' configure option you choose to compile Qt
LIB_SUFFIX=_ev3

TARGET_DIR=/media/card/lib
TARGET_PLUGIN_DIR=$TARGET_DIR/plugins/platforms

#Qt libraries
scp $SOURCE_DIR/lib/libQt5Core$LIB_SUFFIX.so.$VERSION root@$EV3_IP:$TARGET_DIR
scp $SOURCE_DIR/lib/libQt5Gui$LIB_SUFFIX.so.$VERSION root@$EV3_IP:$TARGET_DIR
scp $SOURCE_DIR/lib/libQt5Network$LIB_SUFFIX.so.$VERSION root@$EV3_IP:$TARGET_DIR

#Fonts
scp -r $SOURCE_DIR/lib/fonts root@$EV3_IP:$TARGET_DIR

#Create platform plugin directory
ssh root@$EV3_IP mkdir -p $TARGET_PLUGIN_DIR

#Copy platform plugin
scp $SOURCE_DIR/plugins/platforms/libev3linuxfb.so root@$EV3_IP:$TARGET_PLUGIN_DIR/

2013/11/25

Run Qt 5 raster window example on the Lego Mindstorms EV3

In this article, we'll see how to run the Qt raster window example on the EV3 screen.

QPA stands for Qt Platform Abstraction. It has been added to Qt 4.8 as an alternative to QWS and allows to design graphic applications for embedded devices. In Qt 5, QPA has totally replaced QWS.

If you're curious about QPA, take a look at these links:


http://qt-project.org/wiki/Qt-Platform-Abstraction

http://qt-project.org/videos/watch/qpa-the-qt-platform-abstraction

http://qforever.wordpress.com/2012/04/10/qt-platform-abstraction-starter-guide/

To make Qt display text and other things on your device, you must have a fitting platform plugin. Since there is no such plugin for the EV3, we'll have to craft it.

Quotes from QPA main page:
There is currently little documentation for QPA. The best approach for developing a new platform plugin is to look at the other plugins [qt.gitorious.net] and see how they implement the APIs in question.
There are no source or binary compatibility guarantees for the QPA classes, meaning that a platform plugin is only guaranteed to work with the Qt version it was developed against. API changes will however only be made in minor releases. (5.1, 5.2, and so on.)

EV3 display mechanism:


When something appears on the screen of your EV3, data has been written to the /dev/fb0 framebuffer. You can do a simple test by entering this command on your EV3:

cat /dev/urandom > /dev/fb0
Which should give something like this:

/dev/urandom is a random number generator, that's why it displays noise.


EV3's framebuffer is not standard because one pixel on the screen corresponds to 3 bits in the buffer. However the qlinuxfb plugin provided by Qt is a good start to make our plugin.



How to build EV3 platform plugin:

  • First you must have compiled Qt for your beloved brick. See this article for some explanations. Be careful, you must configure without the "-no-gui" option which was present in the first version of the article.
  • Download source code using git:
    git clone https://github.com/broija/ev3linuxfb
  • Copy ev3linuxfb directory to your qt source package directory. For example:
    cp -r ev3linuxfb qt-everywhere-opensource-src-5.1.1/qtbase/src/plugins/platforms/
  • Go to this directory and build the plugin using the qmake created from the Qt compilation dedicated to the EV3 in order to generate the Makefile. For example:
    cd qt-everywhere-opensource-src-5.1.1/qtbase/src/plugins/platforms/
    qmake.ev3
    make


Build the raster window example project:

  • Go to the raster window example directory in Qt source package:
    cd qt-everywhere-opensource-src-5.1.1/qtbase/examples/gui/rasterwindow
  • Edit rasterwindow.cpp with your favorite text editor. We want to change setGeometry parameters in RasterWindow's constructor in order to fit the EV3 screen:
    //    setGeometry(100, 100, 300, 200);
    setGeometry(0, 0, 178, 128);
    RasterWindow inherits QWindow. We've just created a 178x128 window (which is the brick's screen size) with an offset at 0,0.
  • Once again, generate the Makefile and build:
    qmake.ev3
    make


Final preparations:

  • Copy the freshly built 'libev3linuxfb.so' plugin to your EV3 SD card, in /media/card/lib/platforms. The file is located in this directory: qt-everywhere-opensource-src-5.1.1/qtbase/plugins/platforms/
  • Copy all the fonts to your EV3 SD card, in /media/card/lib/fonts. They are located in the Qt installation directory: Qt5.1.1/lib/fonts
  • Set the environment for QPA (Qt Platform Abstraction) by entering these commands on your EV3:
    export QT_QPA_FONTDIR=/media/card/lib/fonts
    export QT_QPA_PLATFORM_PLUGIN_PATH=/media/card/lib/platforms
  • Finally, copy the rasterwindow executable to your EV3. For example in /media/card/rasterwindow/


The fun part:

    Run the application and tell Qt that you want it to use the ev3linuxfb platform plugin to display things on screen:
    /media/card/rasterwindow/rasterwindow -platform ev3linuxfb

Thanks to Xander from the Mindboards forum who gave me the idea to do this.

2013/11/07

Compile Qt 5 (qtbase) for LEGO Mindstorms EV3 on Linux

Requirements:


Tested with:
  • Ubuntu 12.04.
  • EV3 firmware v1.03H.
Devices:
  • a micro SD card to copy all the libraries and binaries
  • a way to access to your EV3 remotely:

Don't do what follows if you don't know what you are doing. I can't be held responsible for any damage caused to your EV3 or your PC.

Cross-compilation toolchain installation 

Download ARM cross-compilation toolchain, Code Sourcery:

wget -c http://www.codesourcery.com/sgpp/lite/arm/portal/package4571/public/arm-none-linux-gnueabi/arm-2009q1-203-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2


Extract the package wherever you want. For example, ~/codesourcery/:


cd
mkdir codesourcery
cd codesourcery
tar -xjvf arm-2009q1-203-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2

Add the toolchain binaries to your PATH, by adding the following line to your ~/.bashrc:

export PATH="~/codesourcery/arm-2009q1/bin:$PATH"


then open a new terminal to continue or enter:
 

source ~/.bashrc

The cross-compilation toolchain is now installed.




Qt compilation

Download Qt source package:

I used Qt 5.1.1, available from this link:

http://download.qt-project.org/official_releases/qt/5.1/5.1.1/single/qt-everywhere-opensource-src-5.1.1.tar.gz

If you want to try with the latest release, go to this page:

https://qt-project.org/downloads

Be careful, you need to download the source package, not an executable binary!

Let's talk about the 'qmake.conf' file. This file is used to compile and link suiting your needs.
Create it and put it where your Qt source package is.

 

qmake.conf:

#
# qmake configuration for building with arm-none-linux-gnueabi-g++
#


MAKEFILE_GENERATOR      = UNIX
CONFIG                 += incremental gdb_dwarf_index
QMAKE_INCREMENTAL_STYLE = sublib

include(../common/linux.conf)
include(../common/gcc-base-unix.conf)
include(../common/g++-unix.conf)

#Compilers, they are in the directory you've just added to PATH

QMAKE_CC                = arm-none-linux-gnueabi-gcc
QMAKE_CXX               = arm-none-linux-gnueabi-g++
QMAKE_LINK              = arm-none-linux-gnueabi-g++
QMAKE_LINK_SHLIB        = arm-none-linux-gnueabi-g++

#Very important! These options tell the compiler that the target processor is an ARM926EJ-S which architecture is ARMV5TE.
QMAKE_CXXFLAGS       += -mcpu=arm926ej-s -march=armv5te
QMAKE_LFLAGS         += -mcpu=arm926ej-s -march=armv5te

#On the EV3, the SD card mounting point is /media/card
#I chose to install all the toolchain binaries and libraries in /media/card/sysroots/arm2009q1

TARGET_SYSROOT=/media/card/sysroots/arm2009q1

#and the Qt libraries in /media/card/lib
TARGET_LIBPATH=/media/card/lib

#Helps the EV3 find where the libraries are.
QMAKE_LFLAGS         += -Wl,-rpath=$$TARGET_SYSROOT/lib:$$TARGET_SYSROOT/usr/lib:$$TARGET_LIBPATH

#Mandatory for dynamic linking on the target
QMAKE_LFLAGS         += -Wl,--dynamic-linker=$$TARGET_SYSROOT/lib/ld-linux.so.3

# modifications to linux.conf
QMAKE_AR                = arm-none-linux-gnueabi-ar cqs
QMAKE_OBJCOPY           = arm-none-linux-gnueabi-objcopy
QMAKE_NM                = arm-none-linux-gnueabi-nm -P
QMAKE_STRIP             = arm-none-linux-gnueabi-strip

load(qt_config)


___________________________________________________

Extract the package:

tar -xzvf qt-everywhere-opensource-src-5.1.1.tar.gz

then copy the qmake.conf file to the directory corresponding to an 'ARM with Linux' Qt build:

cp qmake.conf qt-everywhere-opensource-src-5.1.1/qtbase/mkspecs/linux-arm-gnueabi-g++

This directory already contains a qmake.conf file, but it won't work if you keep it as it is.

Go to the qtbase directory:

cd qt-everywhere-opensource-src-5.1.1/qtbase



and run the configuration and build process:


./configure -v -opensource -confirm-license -release \
  -prefix
~/Qt5.1.1_ev3 \
  -xplatform linux-arm-gnueabi-g++ \

  -qpa linuxfb \
  -qtlibinfix _ev3 \
  -no-c++11 \
  -no-widgets \
  -no-opengl \
  -no-openvg \
  -no-compile-examples \
  -nomake tests \
  -nomake examples \
  -nomake tools \
  && make \
  && make install


If all went well, you must retrieve the fresh-made 'qmake' to compile your projects.
You can create a symlink or make a copy:

sudo cp
~/Qt5.1.1_ev3/bin/qmake /usr/bin/qmake.ev3

Notice that I've called it 'qmake.ev3' to avoid conflicts with other qmake versions.



Compile a "Hello world" application

Create a new directory which will contain your new project:


main.cpp:


#include <QtCore/QCoreApplication>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    qDebug("Hello Qt!");
   
    return a.exec();
}//main

_____________________________________________________

hello_qt.pro:

TEMPLATE = app
TARGET = hello_qt
INCLUDEPATH += .

CONFIG += release

QT -= gui

# Input
SOURCES += main.cpp
 


_____________________________________________________

Now, be sure that you are in your project directory and enter:

qmake.ev3
make


That's it! The program should compile and link.




Installation on the EV3

We need to copy all the libraries and binaries on the SD card. If you can copy all the files directly from your PC to the SD card, do it. If it's not possible, you can find some tutorials to copy files to your EV3 over SSH on the internet.

Copy all the files contained in the source directories to the destination directories on your SD card:

                  SOURCE                            DESTINATION
~/codesourcery/arm-2009q1/arm-none-linux-gnueabi/libc/etc => /media/card/sysroots/arm2009q1/etc
~/codesourcery/arm-2009q1/arm-none-linux-gnueabi/libc/lib => /media/card/sysroots/arm2009q1/lib
~/codesourcery/arm-2009q1/arm-none-linux-gnueabi/libc/sbin => /media/card/sysroots/arm2009q1/sbin
~/codesourcery/arm-2009q1/arm-none-linux-gnueabi/libc/usr/bin => /media/card/sysroots/arm2009q1/usr/bin
~/codesourcery/arm-2009q1/arm-none-linux-gnueabi/libc/usr/sbin => /media/card/sysroots/arm2009q1/usr/sbin
~/codesourcery/arm-2009q1/arm-none-linux-gnueabi/libc/var => /media/card/sysroots/arm2009q1/var


Regarding the /usr/lib directory, just copy the dynamic libs (.so files):


~/codesourcery/arm-2009q1/arm-none-linux-gnueabi/libc/usr/lib/*.so* => /media/card/sysroots/arm2009q1/usr/lib

Copy all the Qt libraries to your SD card:

~/Qt5.1.1_ev3/lib/libQt5*.so.5.1.1 => /media/card/lib

In your Qt SD card directory (/media/card/lib), rename all the Qt libs to *.so.5 :
eg: libQt5Core_ev3.so.5.1.1 -> libQt5Core_ev3.so.5

Copy your project binary to your SD card:

~/hello_qt/hello_qt => /media/card/hello_qt

Finally, connect to your EV3 using telnet and run your program. The IP address is available from the EV3 menu, in "Brick info":

telnet 192.168.1.3
 

login -> root
password -> simply press enter since no password is required.

cd /media/card/
./hello_qt


Hello Qt!