Example: HelloWorld module (DEPRECATED)¶
The whole example is available here: helloworld.zip
Module creation¶
This module is defined in the two following files:
Header¶
The first one is a header file, defining the HelloWorld class. Note that it is inheriting from the ALModule class.
/**
* Copyright (c) 2011 Aldebaran Robotics
*/
#ifndef HELLOWORLD_H
#define HELLOWORLD_H
#include <boost/shared_ptr.hpp>
#include <alcommon/almodule.h>
namespace AL
{
// This is a forward declaration of AL:ALBroker which
// avoids including <alcommon/albroker.h> in this header
class ALBroker;
}
/**
* A simple example module that says "Hello world" using
* text to speech, or prints to the log if we can't find TTS
*
* This class inherits AL::ALModule. This allows it to bind methods
* and be run as a remote executable or as a plugin within NAOqi
*/
class HelloWorld : public AL::ALModule
{
public:
HelloWorld(boost::shared_ptr<AL::ALBroker> pBroker, const std::string& pName);
virtual ~HelloWorld();
/** Overloading ALModule::init().
* This is called right after the module has been loaded
*/
virtual void init();
/**
* Make Nao say "Hello world" or just print a message to
* the console if not connected to a robot.
*/
void sayHello();
/**
* Make Nao say a sentence given in argument.
*/
void sayText(const std::string& toSay);
/**
* Make Nao say a sentence and return its length.
*/
int sayTextAndReturnLength(const std::string &toSay);
};
#endif // HELLOWORLD_H
Source file¶
The second one contains the implementation. Note the binding of the functions in the constructor. This binding is imperative: else, the methods won’t be available from outside the module.
/**
* Copyright (c) 2011 Aldebaran Robotics
*/
#include "helloworld.h"
#include <iostream>
#include <alcommon/albroker.h>
#include <qi/log.hpp>
#include <alproxies/altexttospeechproxy.h>
using namespace AL;
HelloWorld::HelloWorld(boost::shared_ptr<ALBroker> broker, const std::string& name):
ALModule(broker, name)
{
/** Describe the module here. This will appear on the webpage*/
setModuleDescription("A hello world module.");
/** Define callable methods with their descriptions:
* This makes the method available to other cpp modules
* and to python.
* The name given will be the one visible from outside the module.
* This method has no parameters or return value to describe
*/
functionName("sayHello", getName(), "Say hello to the world");
BIND_METHOD(HelloWorld::sayHello);
functionName("sayText", getName(), "Say a given sentence.");
/**
* This enables to document the parameters of the method.
* It is not compulsory to write this line.
*/
addParam("toSay", "The sentence to be said.");
BIND_METHOD(HelloWorld::sayText);
functionName("sayTextAndReturnLength", getName(),
"Say a given sentence, and return its length");
addParam("toSay", "The sentence to be said.");
/**
* This enables to document the return of the method.
* It is not compulsory to write this line.
*/
setReturn("sentenceLength", "Length of the said sentence.");
BIND_METHOD(HelloWorld::sayTextAndReturnLength);
// If you had other methods, you could bind them here...
/** Bound methods can only take const ref arguments of basic types,
* or AL::ALValue or return basic types or an AL::ALValue.
*/
}
HelloWorld::~HelloWorld() {}
void HelloWorld::init()
{
/** Init is called just after construction.
*
* Here we call sayHello, so that the module does something
* without us having to explicitly call sayHello from somewhere else.
*/
sayHello();
}
void HelloWorld::sayHello()
{
const std::string phraseToSay("Hello world");
std::cout << "Saying hello to the console ..." << std::endl;
std::cout << phraseToSay << std::endl;
std::cout << "Calling say method of ALTextToSpeech module ..." << std::endl;
try
{
/** Create a proxy to TTS.*/
ALTextToSpeechProxy tts(getParentBroker());
/** Call the say method. */
tts.say(phraseToSay);
/** Note: on the desktop you won't hear anything, but you should see
* some logs on the naoqi you are connected to.
*/
}
catch(const AL::ALError&) // no object name given to avoid warning
{
qiLogError("module.example") << "Could not get proxy to ALTextToSpeech" << std::endl;
}
qiLogInfo("module.example") << "Done !" << std::endl;
}
void HelloWorld::sayText(const std::string &toSay) {
std::cout << "Saying the phrase in the console..." << std::endl;
std::cout << toSay << std::endl;
try
{
/** Create a proxy to TTS.*/
ALTextToSpeechProxy tts(getParentBroker());
/** Call the say method. */
tts.say(toSay);
/** Note: on the desktop you won't hear anything, but you should see
* some logs on the naoqi you are connected to. */
}
catch(const AL::ALError&)
{
qiLogError("module.example") << "Could not get proxy to ALTextToSpeech" << std::endl;
}
}
int HelloWorld::sayTextAndReturnLength(const std::string &toSay) {
/** Say the sentence.*/
sayText(toSay);
/** Return its length.*/
return toSay.length();
}
Main¶
The main.cpp contains lots of boilertemplate code. You should not worrying about this file. Just do not modify it unless you know what you are doing.
/**
* Copyright (c) 2010 Aldebaran Robotics
*/
#ifndef _WIN32
# include <signal.h>
#endif
#include <alcommon/albroker.h>
#include <alcommon/albrokermanager.h>
#include <alcommon/altoolsmain.h>
#include "helloworld.h"
#ifdef HELLOWORLD_IS_REMOTE
# define ALCALL
#else
// when not remote, we're in a dll, so export the entry point
# ifdef _WIN32
# define ALCALL __declspec(dllexport)
# else
# define ALCALL
# endif
#endif
extern "C"
{
ALCALL int _createModule(boost::shared_ptr<AL::ALBroker> pBroker)
{
// init broker with the main broker instance
// from the parent executable
AL::ALBrokerManager::setInstance(pBroker->fBrokerManager.lock());
AL::ALBrokerManager::getInstance()->addBroker(pBroker);
// create module instances
AL::ALModule::createModule<HelloWorld>(pBroker, "HelloWorld");
return 0;
}
ALCALL int _closeModule( )
{
return 0;
}
} // extern "C"
#ifdef HELLOWORLD_IS_REMOTE
int main(int argc, char *argv[])
{
// pointer to createModule
TMainType sig;
sig = &_createModule;
// call main
return ALTools::mainFunction("HelloWorld", argc, argv, sig);
}
#endif
Note: if you want to understand what this main.cpp
does or want to change it, you can
read about it in the Creating a custom main section.
CMakeLists.txt¶
The CMakeLists.txt file can generate a .sln file or a Makefile project for you. Do not change it unless you know what you are doing.
# Copyright (C) 2011 Aldebaran Robotics
cmake_minimum_required(VERSION 2.6.4 FATAL_ERROR)
# Define the name of the project
project(helloworld)
# This include enable you to use qibuild framework
find_package(qibuild)
# Create an option to make is possible compiling the module
# as a remote executable, or as a local shared library
option(HELLOWORLD_IS_REMOTE
"module is compiled as a remote module (ON or OFF)"
ON)
# Create a list of source files
set(_srcs
helloworld.cpp
helloworld.h
main.cpp
)
if(HELLOWORLD_IS_REMOTE)
# Add a compile flag because code changes a little bit
# when we are compiling an executable
# This will let you use #ifdef HELLOWORLD_IS_REMOTE
# in the C++ code
add_definitions( " -DHELLOWORLD_IS_REMOTE ")
# Create an executable
qi_create_bin(helloworld ${_srcs})
else()
# Create a plugin, that is a shared library, and make
# sure it is built in lib/naoqi, so that the naoqi executable
# can find it later
qi_create_lib(helloworld SHARED ${_srcs} SUBFOLDER naoqi)
endif()
# Tell CMake that sayhelloworld depends on ALCOMMON and
# ALPROXIES.
# This will set the libraries to link sayhelloworld with,
# the include paths, and so on
qi_use_lib(helloworld ALCOMMON ALPROXIES)
# Also create a simple executable capable of creating
# a proxy to the helloworld module
qi_create_bin(testhelloworld testhelloworld.cpp)
qi_use_lib(testhelloworld ALCOMMON ALPROXIES)
Module access¶
Here is an example on how to access or “HelloWorld” module from the outside.
/**
* Copyright (c) 2011 Aldebaran Robotics. All Rights Reserved
*
* \file testhelloworld.cpp
* \brief Test how to call a module from the outside.
*
* An example on how to call the example "HelloWorld" module from the outside.
*
*/
#include <iostream>
#include <alerror/alerror.h>
#include <alcommon/alproxy.h>
#include <alcommon/albroker.h>
int main(int argc, char* argv[]) {
if(argc != 2)
{
std::cerr << "Wrong number of arguments!" << std::endl;
std::cerr << "Usage: testhelloworld NAO_IP" << std::endl;
exit(2);
}
const std::string robotIP = argv[1];
int port = 9559;
try {
/** Create a generic proxy to "HelloWorld" module.
* Arguments for the constructor are
* - name of the module
* - string containing the IP adress of the robot
* - port (default is 9559)
*/
boost::shared_ptr<AL::ALBroker> broker =
AL::ALBroker::createBroker("MyBroker", "", 0, robotIP, port);
boost::shared_ptr<AL::ALProxy> testProxy
= boost::shared_ptr<AL::ALProxy>(new AL::ALProxy(broker, "HelloWorld"));
/** Call the sayHello method from the module using its bound name.
* Since it returns nothing, use the callVoid method.
*/
testProxy->callVoid("sayHello");
/** Call the sayText method from the module using its bound name and giving
* the right argument. Since it returns nothing, use the callVoid method.
*/
testProxy->callVoid("sayText", std::string("This is a test."));
/** Call the sayTextAndReturnLength method from the module using its bound
* name and giving the right argument.
* Since the method returns something, use the call method templated with
* the right return type.
*/
int sentenceLength = testProxy->call<int>("sayTextAndReturnLength",
std::string("This is another test"));
std::cout << "Sentence length is " << sentenceLength << std::endl;
}
catch (const AL::ALError& e) {
std::cerr << e.what() << std::endl;
}
}