Mostrando entradas con la etiqueta Workshops. Mostrar todas las entradas
Mostrando entradas con la etiqueta Workshops. Mostrar todas las entradas

miércoles, 8 de enero de 2014

How to start creating and programming robots

 

Introduction


Create robots requires a lot of different skills and, depending on how sophisticated is the behavior or the tasks that must be performed, can be really complex and extremely difficult.

The three pillars of robotics are electronics, mechanics and programming; there are others, but only with these three you can already start experimenting.

In addition to applicable knowledge you also need some others items such as motors (or other actuators), sensors, a small computer to avoid weight and power consumption (typically a SBC or microcontroller ) and a power source (battery to be autonomous) and some parts that sustain and hold together all these elements and their movements.

These elements can be acquired (some even manufactured) separately, or more easily, and probably cheaper as a kit.

.

What do I need to start?


Mainly, you need wish to enjoy creating and learning.

* Acquire a minimum and basic knowledge of:

+ Electronics or electricity (if only to distinguish voltage and current),

+ Mechanics (the minimum would be screwing and unscrewing or connect Lego type pieces)

+ Computer (at least to run a program on a computer)

* Get at least a microcontroller (Arduino, for example), a pair of motors, a distance sensor, a battery, cables, and a structure to support it. The basic set or kit.

A kit, the best option


A clear advantage of starting with a kit is that you start NOW, spending your time on where is your interest (electronic, mechanical or computer) , because the others areas are already solved, but anytime you can get to work in any of them. When you buy the kit with all the necessary set of elements together, the price is also often cheaper.

From the more expensive and complex to the cheapest and easiest

bioloid_bio_img01Bioloid : 18 powerful servo motors, 4 sensors. Ideal for humanoid, quadrupeds, hexapods and even vehicles; software to create them and behave like living beings. Includes programming software RoboPlus Tasks, you can also program in C, and create motion sequences with RoboPlus Motion.  Using other controller, like Raspberry Pi you can use any language and programming tools which generate code to it.

It costs about 1000 euros. Yes, it is somewhat expensive, but if you have enough money and programming skills or willingness to learn, I think it deserves the price.

Mindstorms_EV3Mindstorm EV3: 2 servo motors, 1 motor, 4 sensors. Ideal for mechanisms and vehicles. Very easy to use, but it also allows you to create complex robots. Includes programming software NXT-G, NXT is also possible to program in Java with Far and C / C + + with Osek, not yet available for EV3 or very early versions.

It costs about 300 euros, although it may seem expensive compared to other options, its enormous potential and flexibility in all aspects (construction, programming and electronics) make it tremendously interesting.

Mindstorms EV3 is the latest version, released in August 2013.

[caption id="attachment_2226" align="alignleft" width="240"]Arduino robot Robot Arduino[/caption]

Vehicle based on Arduino: at least 2 servomotors and all the sensors  you want to start. Is easy and cheap, for about 40€/50$ - 70€/97$ you can have the a robot. Ideal for deepening in electronics.

It can be programmed with the friendly Arduino programming environment .

Is the cheapest option and you can go further by buying more components as you go. It not offers as much flexibility and ability to build as Mindstorms vehicles or Bioloid articulated robots, but you can really learn a lot more than it may seem.

.

.

.

And with less money or no money?


For less money, for starters, you can get an Arduino microcontroller or its clones, which cost just over 20 euros/dollars.

Or, completely free of charge, you can start learning to program in C or C + +, which will come very handy to program robots.

Free resources for learning C programming:

C introduction (pdf)

But there are a lot…

C Language Tutorial (html)
How C Programming Works (html)
Several C programming tutorials (html)
... and more from Google


And here you can find free resources for learning C++ programming.

In the next post I will write about a fast comparative between Bioloid, Mindstorms and Arduino based robots and about Arduino programming.

martes, 25 de junio de 2013

Bioloid Workbench Windows C++ examples

This post presents the Windows version of two examples/utilities built, this time, with MS Visual C++ and QT Creator, a great open source IDE and framework.

The first utility has a comand line user interface, being an easy example with only two DLL dependencies to the Visual C++ runtimes.

Screenshot-Terminal

The second example utility has a graphic user interface created with QT Creator.

QTWorkbench

Here you can find the bin executables and the projects with the source code.

This is the main function of the first example, the command line:

[sourcecode language="cpp"]
int _tmain(int argc, _TCHAR* argv[])
{
cout << "AXControl_v2_VS_CPP test v0" << endl;

bool quit=false;
MyBasicSystem::BasicSystem mySystem;
UI ui(mySystem);
do
{
ui.showMenu();
int selected=ui.selectOption();
if (selected==ui.OptionQuit)
quit=true;
ui.executeSelectedOption(selected);
}while (!quit);

mySystem.dynamixelCommunication.close();

return 0;
}
[/sourcecode]

[Update] Yesterday I discovered a subtle but ugly bug. Can you spot it? Send an email to if you can't find it but you want to know the danger bug.

It use two classes, the "BasicSystem" (in the library "VS_CPP_AXControl_lib.lib") and a simple "UI" class that receives the input from the user and use the operations offered by the "BasicSystem" class.

For example:

[sourcecode language="cpp"]
int UI::getPosition()
{
int position=0;

do
{
cout << "Type a value between 0 and 1023 to set the AX-12 in that position" << endl; cin>>position;

}while(!validRange(position, 0, 1023));

cout << "Position:" << position << endl;

return position;
}
...
void UI::doSetPosition()
{
int ax12Id=getId();
int position=getPosition();

mySystem.dynamixelCommunication.sendOrder(ax12Id, MyCommunications::GoalPosition,(short) position);
}
[/sourcecode]

And all the cource code:

[sourcecode language="cpp"]
/*------------------------------------------------------------------------------*\
* This source file is subject to the GPLv3 license that is bundled with this *
* package in the file COPYING. *
* It is also available through the world-wide-web at this URL: *
* http://www.gnu.org/licenses/gpl-3.0.txt *
* If you did not receive a copy of the license and are unable to obtain it *
* through the world-wide-web, please send an email to *
* siempre.aprendiendo@gmail.com so we can send you a copy immediately. *
* *
* @category Robotics *
* @copyright Copyright (c) 2011 Jose Cortes (http://www.siempreaprendiendo.es) *
* @license http://www.gnu.org/licenses/gpl-3.0.txt GNU v3 Licence *
* *
\*------------------------------------------------------------------------------*/

#include "stdafx.h"
#include
#include "BasicSystem.h"
#include "Util.h"

using namespace std;

class UI
{
public:
static const int OptionQuit=8;

UI(MyBasicSystem::BasicSystem& aMySystem) : mySystem(aMySystem) {}

void showMenu();
int selectOption();
bool executeSelectedOption(int selected);
void doBeep();

private:
MyBasicSystem::BasicSystem mySystem;

static const int OptionSetLEDOnOff=1;
static const int OptionQueryAX12=2;
static const int OptionMoveAX12=3;
static const int OptionTorqueAX12=4;
static const int OptionQuerySensor=5;
static const int OptionShowMenu=6;
static const int OptionBeep=7;

static const int MinOption=OptionSetLEDOnOff;
static const int MaxOption=OptionQuit;

bool validRange(int value, int MinValue, int MaxValue);
bool nonValidOption(int option);
int getPosition();
int getId();
int getSensorPort();
void doGetPosition();
void doSetPosition();
void doQuerySensor();
void doSetLEDOnOff();
void doSetTorqueOnOff();

};

void UI::showMenu()
{
cout << "V02" << endl;

cout << OptionSetLEDOnOff << ".- Toggle AX-12 LED" << endl;
cout << OptionQueryAX12 << ".- Query AX-12" << endl;
cout << OptionMoveAX12 << ".- Move AX-12" << endl;
cout << OptionTorqueAX12 << ".- Torque AX-12" << endl;
cout << OptionQuerySensor << ".- Query CM-510 sensor" << endl;
cout << OptionShowMenu << ".- Show menu" << endl;
cout << OptionBeep << ".- Beep" << endl;
cout << OptionQuit << ".- Quit" << endl;
}

bool UI::nonValidOption(int option)
{
return (optionMaxOption);
}

int UI::selectOption()
{
int option=-1;

while (nonValidOption(option))
{
cout << "Select option (" << MinOption << "-" << MaxOption << ")" << endl; cin >> option;
if (nonValidOption(option))
{
cout << endl;
cout << endl;
cout << "(" << option << ") is NOT a valid option" << endl; } } return option; } bool UI::validRange(int value, int MinValue, int MaxValue) { return (value>=MinValue && value<=MaxValue);
}

int UI::getPosition()
{
int position=0;

do
{
cout << "Type a value between 0 and 1023 to set the AX-12 in that position" << endl; cin>>position;

}while(!validRange(position, 0, 1023));

cout << "Position:" << position << endl; return position; } int UI::getId() { int ax12Id=1; do { puts ("Type the ID of the AX-12 to use, a value between 1 and 18, "); cin >> ax12Id;

}while(!validRange(ax12Id, 1, 18));

cout << "AX12 Id:" << ax12Id << endl; return ax12Id; } int UI::getSensorPort() { int sensorPort=1; do { puts ("Type the sensor Port to read, a value between 1 and 6, "); cin >> sensorPort;

}while(!validRange(sensorPort, 1, 6));

cout << "Sensor Port number:" << sensorPort << endl;

return sensorPort;
}

void UI::doBeep()
{
cout << "Beep" << endl;
mySystem.dynamixelCommunication.sendOrder(100, AXS1_Buzzer, (byte) DO, (short) 500);
Sleep (2);
mySystem.dynamixelCommunication.sendOrder(200, MyCommunications::Beep, (byte) 5);
}

void UI::doGetPosition()
{
int ax12Id=getId();

int position = mySystem.dynamixelCommunication.readValue(ax12Id, MyCommunications::PresentPosition);
cout << "the position is: [" << position << "] " << endl << endl << endl;
}

void UI::doSetPosition()
{
int ax12Id=getId();
int position=getPosition();

mySystem.dynamixelCommunication.sendOrder(ax12Id, MyCommunications::GoalPosition,(short) position);
}

void UI::doQuerySensor()
{
int sensorPort=getSensorPort();

int value=mySystem.dynamixelCommunication.readSensorValue (200, ReadCM510SensorRaw, sensorPort);
cout << "the sensor reads: [" << value << "] " << endl << endl << endl;
}

void UI::doSetLEDOnOff()
{
byte lByte=0, hByte=0;
int ledValue;

int ax12Id=getId();

ledValue=mySystem.dynamixelCommunication.readValue(ax12Id, MyCommunications::LED);
Hex::toHexHLConversion(ledValue, hByte, lByte);

bool onOff=false;
if (lByte!=0)
onOff=true;

cout << "The LED is: [" << (onOff?"on":"off") << "], putting it: [" << (onOff?"Off":"on") << "] " << endl << endl << endl;
mySystem.dynamixelCommunication.sendOrder(ax12Id, MyCommunications::LED, byte(onOff?0:1));
}

void UI::doSetTorqueOnOff()
{
byte lByte=0, hByte=0;
int ax12Id=getId();

int torque=mySystem.dynamixelCommunication.readValue(ax12Id, MyCommunications::Torque);
Hex::toHexHLConversion(torque, hByte, lByte);
bool onOff=(lByte!=0?true:false);

cout << "The Torque is: [" << (onOff?"on":"off") << "], putting it: [" << (onOff?"Off":"on") << "] " << endl << endl << endl;

mySystem.dynamixelCommunication.sendOrder(ax12Id, MyCommunications::Torque,(byte) (onOff?0:1));
}

bool UI::executeSelectedOption(int option)
{
bool isOk=true;
cout << endl;
cout << endl;

cout << "Selected option: [" << option << "] " << endl; switch(option) { case OptionSetLEDOnOff: doSetLEDOnOff(); break; case OptionQueryAX12: doGetPosition(); break; case OptionMoveAX12: doSetPosition(); break; case OptionTorqueAX12: doSetTorqueOnOff(); break; case OptionQuerySensor: doQuerySensor(); break; case OptionShowMenu: showMenu(); break; case OptionBeep: doBeep(); break; } return isOk; } [/sourcecode]

The code for the Qt version is more complex, but as an example, the same operation that the example for the command line:

[sourcecode language="cpp"] int MainWindow::getAX12_1_Id() { // Get the value from the edit control for the first AX-12 QString qStr=ui->SB_AX12_1_ID->text();
int id=Util::convertToInt(qStr.toStdString());

return id;
}
...
void MainWindow::on_B_AX12_1_SET_POS_clicked()
{
int id = getAX12_1_Id();

// Get the target position from the UI edit control as string and a convert it to int
short position= ui->SB_AX12_1_POS->text().toInt();

// Send the order to the AX-12 with the "id" to go to "position"
pDynComm->sendOrder(id, MyCommunications::GoalPosition,position);
}
[/sourcecode]

martes, 28 de mayo de 2013

[UPDATED] A simple but pretty complete Linux C++ example for Bioloid

[Jun 12, 2013, Some source code typos fixed and code updated]:

.
.
.
.
.

[sourcecode language="cpp"]
bool nonValidOption(int option)
{
return (optionMaxOption);
}
[/sourcecode]

This is a very simple but pretty complete example, trying to use the least possible dependencies. I have tested in a just installed Ubuntu and you only needed the AXControl library (I created and use it because then there were no Robotis library and because it can use serial port, Dynamixel bus, Zigbee, BT (Robotis or other adaptors)

It use the terminal, no QT, to avoid library dependencies. But you should add the AXControl_v2 lib files to your /usr/lib folder as administrator (sudo). Click here if you want one unique executable for Linux (tested with Linux Mint 14) using these sources files

When executed, it shows the values configured in the HexaWheels.conf file and any problem it founds, like SerialPort2Dynamixel.open(ss)=> [Serial port NOT opened]:


ubuntu@A3820 ~/projects/trunk/bioloid/Herramientas/CommandLine $ ./commandline
init to load configuration(ss)=> [./HexaWheels.conf]
Configuration file=> (ss)=> [./HexaWheels.conf]
Tiempo_Espera_ms(ss)=> [35]
Tiempo_Espera_Sensores_ms(ss)=> [60]
Nombre_Puerto_Serie(ss)=> [/dev/ttyUSB0]
Baudios_Puerto_Serie(ss)=> [1000000]
Motion_File_Name(ss)=> [HexaWheels_2.0.mtn]
UmbralContacto(ss)=> [550]
UmbralDeteccion(ss)=> [200]
loadConfigurationValues: (si)=> [134529476]
getIntValue: (ss)=> [Tiempo_Espera_ms]
getIntValue: (ss)=> [Tiempo_Espera_Sensores_ms]
getIntValue: (ss)=> [Baudios_Puerto_Serie]
getStringValue: (ss)=> [Nombre_Puerto_Serie]


Device /dev/ttyUSB0, Speed B1000000
SerialPort2Dynamixel.open(ss)=> [Serial port NOT opened]
SerialPort2Dynamixel.open, serialPortName(ss)=> [/dev/ttyUSB0]
SerialPort2Dynamixel.open, baudRate(si)=> [4104]
I can't open DynamixelCommunication, name: (ss)=> [/dev/ttyUSB0]
terminate called after throwing an instance of 'std::exception*'
Aborted

If it can connect an there are no problem you should see:


ubuntu@A3820 ~/projects/trunk/bioloid/Herramientas/CommandLine $ ./commandline
init to load configuration(ss)=> [./HexaWheels.conf]
Configuration file=> (ss)=> [./HexaWheels.conf]
Tiempo_Espera_ms(ss)=> [35]
Tiempo_Espera_Sensores_ms(ss)=> [60]
Nombre_Puerto_Serie(ss)=> [/dev/ttyUSB0]
Baudios_Puerto_Serie(ss)=> [1000000]
Motion_File_Name(ss)=> [HexaWheels_2.0.mtn]
UmbralContacto(ss)=> [550]
UmbralDeteccion(ss)=> [200]
loadConfigurationValues: (si)=> [134529476]
getIntValue: (ss)=> [Tiempo_Espera_ms]
getIntValue: (ss)=> [Tiempo_Espera_Sensores_ms]
getIntValue: (ss)=> [Baudios_Puerto_Serie]
getStringValue: (ss)=> [Nombre_Puerto_Serie]


Device /dev/ttyUSB0, Speed B1000000
SerialPort2Dynamixel.open, serialPortName(ss)=> [/dev/ttyUSB0]
SerialPort2Dynamixel.open, baudRate(si)=> [4104]
V01
2.- Toggle AX-12 LED
3.- Query AX-12
4.- Move AX-12
5.- Torque AX-12
6.- Query CM-510 sensor
7.- Show menu
8.- Beep
9.- Quit
Select option (2-9)

[sourcecode language="cpp"]

/*------------------------------------------------------------------------------*\
* This source file is subject to the GPLv3 license that is bundled with this *
* package in the file COPYING. *
* It is also available through the world-wide-web at this URL: *
* http://www.gnu.org/licenses/gpl-3.0.txt *
* If you did not receive a copy of the license and are unable to obtain it *
* through the world-wide-web, please send an email to *
* siempre.aprendiendo@gmail.com so we can send you a copy immediately. *
* *
* @category Robotics *
* @copyright Copyright (c) 2011 Jose Cortes (<a href="https://plus.google.com/105007891378677151287/about">https://plus.google.com/105007891378677151287/about</a>) *
* @license http://www.gnu.org/licenses/gpl-3.0.txt GNU v3 Licence *
* *
\*------------------------------------------------------------------------------*/

#include "stdafx.h"
#include
#include "BasicSystem.h"
#include "Util.h"

using namespace std;

class UI
{
public:
static const int OptionQuit=8;

UI(MyBasicSystem::BasicSystem& aMySystem) : mySystem(aMySystem) {}

void showMenu();
int selectOption();
bool executeSelectedOption(int selected);
void doBeep();

private:
MyBasicSystem::BasicSystem mySystem;

static const int OptionSetLEDOnOff=1;
static const int OptionQueryAX12=2;
static const int OptionMoveAX12=3;
static const int OptionTorqueAX12=4;
static const int OptionQuerySensor=5;
static const int OptionShowMenu=6;
static const int OptionBeep=7;

static const int MinOption=OptionSetLEDOnOff;
static const int MaxOption=OptionQuit;

bool validRange(int value, int MinValue, int MaxValue);
bool nonValidOption(int option);
int getPosition();
int getId();
int getSensorPort();
void doGetPosition();
void doSetPosition();
void doQuerySensor();
void doSetLEDOnOff();
void doSetTorqueOnOff();

};

void UI::showMenu()
{
cout << "V02" << endl;

cout << OptionSetLEDOnOff << ".- Toggle AX-12 LED" << endl;
cout << OptionQueryAX12 << ".- Query AX-12" << endl;
cout << OptionMoveAX12 << ".- Move AX-12" << endl;
cout << OptionTorqueAX12 << ".- Torque AX-12" << endl;
cout << OptionQuerySensor << ".- Query CM-510 sensor" << endl;
cout << OptionShowMenu << ".- Show menu" << endl;
cout << OptionBeep << ".- Beep" << endl;
cout << OptionQuit << ".- Quit" << endl;
}

bool UI::nonValidOption(int option)
{
return (optionMaxOption);
}

int UI::selectOption()
{
int option=-1;

while (nonValidOption(option))
{
cout << "Select option (" << MinOption << "-" << MaxOption << ")" << endl; cin >> option;
if (nonValidOption(option))
{
cout << endl;
cout << endl;
cout << "(" << option << ") is NOT a valid option" << endl; } } return option; } bool UI::validRange(int value, int MinValue, int MaxValue) { return (value>=MinValue && value<=MaxValue);
}

int UI::getPosition()
{
int position=0;

do
{
cout << "Type a value between 0 and 1023 to set the AX-12 in that position" << endl; cin>>position;

}while(!validRange(position, 0, 1023));

cout << "Position:" << position << endl; return position; } int UI::getId() { int ax12Id=1; do { puts ("Type the ID of the AX-12 to use, a value between 1 and 18, "); cin >> ax12Id;

}while(!validRange(ax12Id, 1, 18));

cout << "AX12 Id:" << ax12Id << endl; return ax12Id; } int UI::getSensorPort() { int sensorPort=1; do { puts ("Type the sensor Port to read, a value between 1 and 6, "); cin >> sensorPort;

}while(!validRange(sensorPort, 1, 6));

cout << "Sensor Port number:" << sensorPort << endl;

return sensorPort;
}

void UI::doBeep()
{
cout << "Beep" << endl;
mySystem.dynamixelCommunication.sendOrder(100, AXS1_Buzzer, (byte) DO, (short) 500);
Sleep (2);
mySystem.dynamixelCommunication.sendOrder(200, MyCommunications::Beep, (byte) 5);
}

void UI::doGetPosition()
{
int ax12Id=getId();

int position = mySystem.dynamixelCommunication.readValue(ax12Id, MyCommunications::PresentPosition);
cout << "the position is: [" << position << "] " << endl << endl << endl;
}

void UI::doSetPosition()
{
int ax12Id=getId();
int position=getPosition();

mySystem.dynamixelCommunication.sendOrder(ax12Id, MyCommunications::GoalPosition,(short) position);

}

void UI::doQuerySensor()
{
int sensorPort=getSensorPort();

int value=mySystem.dynamixelCommunication.readSensorValue (200, ReadCM510SensorRaw, sensorPort);
cout << "the sensor reads: [" << value << "] " << endl << endl << endl;
}

void UI::doSetLEDOnOff()
{
byte lByte=0, hByte=0;
int ledValue;

int ax12Id=getId();

ledValue=mySystem.dynamixelCommunication.readValue(ax12Id, MyCommunications::LED);
Hex::toHexHLConversion(ledValue, hByte, lByte);

bool onOff=false;
if (lByte!=0)
onOff=true;

cout << "The LED is: [" << (onOff?"on":"off") << "], putting it: [" << (onOff?"Off":"on") << "] " << endl << endl << endl;
mySystem.dynamixelCommunication.sendOrder(ax12Id, MyCommunications::LED, byte(onOff?0:1));
}

void UI::doSetTorqueOnOff()
{
byte lByte=0, hByte=0;
int ax12Id=getId();

int torque=mySystem.dynamixelCommunication.readValue(ax12Id, MyCommunications::Torque);
Hex::toHexHLConversion(torque, hByte, lByte);
bool onOff=(lByte!=0?true:false);

cout << "The Torque is: [" << (onOff?"on":"off") << "], putting it: [" << (onOff?"Off":"on") << "] " << endl << endl << endl;

mySystem.dynamixelCommunication.sendOrder(ax12Id, MyCommunications::Torque,(byte) (onOff?0:1));
}

bool UI::executeSelectedOption(int option)
{
bool isOk=true;
cout << endl;
cout << endl;

cout << "Selected option: [" << option << "] " << endl;

switch(option)
{
case OptionSetLEDOnOff:
doSetLEDOnOff();
break;
case OptionQueryAX12:
doGetPosition();
break;
case OptionMoveAX12:
doSetPosition();
break;
case OptionTorqueAX12:
doSetTorqueOnOff();
break;
case OptionQuerySensor:
doQuerySensor();
break;
case OptionShowMenu:
showMenu();
break;
case OptionBeep:
doBeep();
break;
}

return isOk;
}

int _tmain(int argc, _TCHAR* argv[])
{
cout << "AXControl_v2_VS_CPP test v0" << endl;

bool quit=false;
MyBasicSystem::BasicSystem mySystem;
UI ui(mySystem);
do
{
ui.showMenu();
int selected=ui.selectOption();
if (selected==ui.OptionQuit)
quit=true;
ui.executeSelectedOption(selected);
}while (!quit);

mySystem.dynamixelCommunication.close();

return 0;
}

[/sourcecode]

lunes, 25 de marzo de 2013

So... let's the Bioloid, C++ and QT games start!

To cretate this workshop I'm using Ubuntu 12.04, GNU g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3 (see Synaptic installer capture),

[caption id="attachment_1635" align="aligncenter" width="300"]Synaptic G++ Synaptic G++[/caption]

QT 5.0.1 and QT creator 2.6.2,

QT creator is a very easy, and good, free IDE with a great design tool for creating user interfaces:

Be careful with this bug: Qt Creator 2.0: UI layout is not updated before launching the application http://qt-project.org/forums/viewthread/292 Is very annoying and time consuming, the solution is in the last comment (setting the UI_DIR in the .pro file)

[caption id="attachment_1637" align="aligncenter" width="600"]QTCreator Bioloid QTWorkshop QTCreator Bioloid QTWorkshop[/caption]

I also will use it with Windows 7.

I also use Boost to get some C++11 features for threading. For example:

pWorkThread = new thread(&Activity::doWork, this, parameter);

std::lock_guard < std::mutex > guard(myMutex);

Don't bother if you don't understand it right now, it's in the guts of the AXControl_v2 library we will use it in a very easy way, as you will see below. Here you will find a lot of resources to learn basic and advanced C++

Example context fot std::lock_guard < std::mutex > guard(myMutex);

[sourcecode language="cpp"]

short DynamixelCommunication::readSensorValue(int id, AX12Address address,
int port) {
std::lock_guard < std::mutex > guard(myMutex);
short value = -1;
try {
int size = getReadSensorWordCommand(buffer, (byte) (id), address,
(byte) (port));
memset(&result, 0, MaxBufferSize);
serialPort.query(buffer, result, size, WaitTimeReadSensor);
value = getQueryResult(result, size);
if (value <= 0)
Debug::show("DynamixelCommunication.readSensorValue", value);

} catch (exception e) {
Debug::show("DynamixelCommunication.readSensorValue", e.what());
}
return value;
}

[/sourcecode]

And context for pWorkThread = new thread(&Activity::doWork, this, parameter);:

[sourcecode language="cpp"]

class Activity {
private:

protected:
std::thread *pWorkThread;

...

}

void Activity::start(int parameter) {
working = true;
pWorkThread = new thread(&Activity::doWork, this, parameter);
Util::sleepMS(10);
}
Let's see how to open the connection
[/sourcecode]

Let's see how to open the connection to the CM-510:

[sourcecode language="cpp"]
void MainWindow::on_B_Open_clicked()
{
//QString output="Open it";
//QMessageBox::information(this, "Output", output, QMessageBox::Ok);

//dynComm.open("/dev/ttyUSB0",57600); //open with these parameters
if (pDynComm->open()) //open getting the parameter from the configuration fiel
{
//Connection opened
setConnectionButtons(true); //User interface update
updateAX12Parameters(ui->SB_AX12_1_ID->text().toInt()); //User interface update
}
else
{
//Show problem opening the connection
string cantOpenPortName="I can't open port: ";
cantOpenPortName+=pConf->getStringValue(DynamixelCommunication::ParameterSerialPortName);

QMessageBox::information(this, "Error", QString::fromStdString(cantOpenPortName), QMessageBox::Ok);
}
}
[/sourcecode]

and get a beep from the Robotis CM-510 (using this alternative firmware):

[sourcecode language="cpp"]
pDynComm->sendOrder(200, MyCommunications::BeepCM510, 0); //200 is the Dynamixel device ID used for the CM-510, 0 because beep doesn't need any additional value
[/sourcecode]

Getting the AX12 position and showing it:

[sourcecode language="cpp"]
void MainWindow::on_B_AX12_1_GET_POS_clicked()
{
QString qStr;

int id = getAX12_1_Id();

int position = pDynComm->readValue(id, MyCommunications::PresentPosition);

ui->SB_AX12_1_POS->setValue(position);
[/sourcecode]

Setting the AX12 position:

[sourcecode language="cpp"]
void MainWindow::on_B_AX12_1_SET_POS_clicked()
{
int id = getAX12_1_Id();

int position= ui->SB_AX12_1_POS->text().toInt();
pDynComm->sendOrder(id, MyCommunications::GoalPosition,position);
}
[/sourcecode]

Putting the selected AX12 LED on and off

[sourcecode language="cpp"]
void MainWindow::on_CH_AX12_1_LED_clicked(bool checked)
{
int id = getAX12_1_Id();

pDynComm->sendOrder(id, MyCommunications::LED, (checked?1:0));// if checked 1, else 0
}
[/sourcecode]

And an auxiliary UI method to get the id from the selected AX-12

[sourcecode language="cpp"]
{
int MainWindow::getAX12_1_Id()
{
QString qStr=ui->SB_AX12_1_ID->text();
int id=Util::convertToInt(qStr.toStdString());

return id;
}
[/sourcecode]

You can download sources and Linux binaries here

A diagram with all the AXControl_v2 lib classes and their methods:

[caption id="attachment_1384" align="aligncenter" width="600"]c++ signatura c++ signatura[/caption]

[Update]

[caption id="attachment_1722" align="aligncenter" width="164"]QT5 Bioloid Workbench QT5 Bioloid Workbench[/caption]

domingo, 17 de marzo de 2013

C. C++, C# robotics programming Workshop/tutorial with the cheapest robotic platform

[caption id="" align="alignleft" width="108"]My Smart Car construction My Smart Car construction[/caption]

[Update March 30, 2013: Added photo gallery]

I will start a C. C++, C# robotics programming Workshop/tutorial with the cheapest robotic platform I have found at dealextreme.com: (Arduino based) plus a Raspberry Pi (like this that use Bioloid as the hardware platform):

Ultrasonic Smart Car Kit

I have not still received the kit, but I will review the kit and start the workshop as soon as I receive it.

miércoles, 13 de marzo de 2013

Playing With Qt 5, C++ and Bioloid

I have been searching the best UI (libraries and UI creating tools) multiplatform framework for several years, and QT 5 is the best option I have found. Its libraries are easy to use, specially the slots (UI widgets connection to code) of QT5.  QT Creator is pretty easy to use and the UI designer is the free best tool I have tested. Really I'm learning to use it as creating these examples.

A very simple example:

[caption id="attachment_1508" align="aligncenter" width="287"]QT Bioloid Workshop QT Bioloid Workshop[/caption]

The code uses two classes from the AXControl_v2 library:

- Configuration, it loads the  parameters from the file HexaWheels.conf (currently in spanish):
Tiempo_Espera_ms=36 // wait time
Tiempo_Espera_Sensores_ms=60 // wait time for sensors
Nombre_Puerto_Serie=/dev/ttyUSB0 // serial port name
Baudios_Puerto_Serie=57600 // baud rate

- DynamixelCommunication, it offers the commands to control Dynamixel items

Connecting to the Dynamixel bus:

[sourcecode language="cpp"]
void MainWindow::on_B_Open_clicked()
{
pDynComm->open(); // open the connection using the parameters from the configuration file
setConnectionButtons(true); // enable and disable conveniently the buttons
}
[/sourcecode]

Getting and setting the AX12 Dynamixel position:

[sourcecode language="cpp"]
void MainWindow::on_B_AX12_1_GET_POS_clicked()
{
QString qStr;

int id=ui->SB_AX12_1_ID->text().toInt();
int position = pDynComm->readValue(id, MyCommunications::PresentPosition);
string str=std::to_string(position);

ui->E_AX12_1_POS->setText(qStr.fromStdString(str));
}

void MainWindow::on_B_AX12_1_SET_POS_clicked()
{
QString qStr=ui->SB_AX12_1_ID->text();
int id=Util::convertToInt(qStr.toStdString());

int position= ui->E_AX12_1_POS->text().toInt();
pDynComm->sendOrder(id, MyCommunications::GoalPosition,position);
}

[/sourcecode]

And this is the (unfinished) main window code:

[sourcecode language="cpp"]
#include

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include "Configuration.h"
#include "DynamixelCommunication.h"
#include "Util.h"

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
pConf=new Configuration ("/home/jose/proyectos_svn_win/trunk/bioloid/Comun/CPP/AXControl_v2/src/HexaWheels.conf");
pDynComm=new DynamixelCommunication (pConf);
}

MainWindow::~MainWindow()
{
delete ui;

pDynComm->close();
delete pDynComm;
delete pConf;
}

void MainWindow::setConnectionButtons(bool onOff)
{
ui->B_Open->setEnabled(!onOff);
ui->B_Beep->setEnabled(onOff);
ui->B_Close->setEnabled(onOff);
}

void MainWindow::on_B_Open_clicked()
{
//QString output="Open it";
//QMessageBox::information(this, "Output", output, QMessageBox::Ok);

//dynComm.open("/dev/ttyUSB0",57600);
pDynComm->open();

setConnectionButtons(true);
}

void MainWindow::on_B_Beep_clicked()
{
pDynComm->sendOrder(200, MyCommunications::BeepCM510, 5);
}

void MainWindow::on_B_Close_clicked()
{
pDynComm->close();
setConnectionButtons(false);
QString output="Port closed!";
QMessageBox::information(this, "Output", output, QMessageBox::Ok);

}

void MainWindow::on_B_AX12_1_GET_POS_clicked()
{
QString qStr;

int id=ui->SB_AX12_1_ID->text().toInt();
int position = pDynComm->readValue(id, MyCommunications::PresentPosition);
string str=std::to_string(position);

ui->E_AX12_1_POS->setText(qStr.fromStdString(str));
}

void MainWindow::on_B_AX12_1_SET_POS_clicked()
{
QString qStr=ui->SB_AX12_1_ID->text();
int id=Util::convertToInt(qStr.toStdString());

int position= ui->E_AX12_1_POS->text().toInt();
pDynComm->sendOrder(id, MyCommunications::GoalPosition,position);
}

[/sourcecode]

But it's "growing":

[caption id="attachment_1546" align="aligncenter" width="285"]QT_Workbench QT_Workbench[/caption]

I have uploaded the source and binary of this work in progress to
https://www.box.com/s/mdsdeoem0gg4o2rapipj/s/mdsdeoem0gg4o2rapipj

viernes, 1 de marzo de 2013

Workshop: USB, serial and remote communications with C#

[Previous post: Workshop: Dynamixel communications with C#]

[caption id="attachment_1117" align="alignright" width="150"]Bioloid SerialPort2Dynamixel C# Bioloid SerialPort2Dynamixel C#[/caption]

SerialPort2Dynamixel


Encapsulating  the SerialPort .Net class offers an easy way to use the serial port and receive Dynamixel Zig messages with the Dynamixel protocol.

.

.

Collaborator classes:


[caption id="attachment_1134" align="alignright" width="150"]Bioloid SerialPort2Dynamixel C# Collaborators Bioloid SerialPort2Dynamixel C# Collaborators[/caption]

- The SerialPort .Net class.

- RCDataReader class, which unpack the Dynamixel Zigbee sequence offering the clean data received.

Operations:


The public interface that others classes will use offers principally these operations:

public void setRemoteControlMode(bool on), which sets on or off the reception of data

[sourcecode language="csharp"]

public void setRemoteControlMode(bool on)
{
if (on)
setReceiveDataMethod(rdDataReader.rawRemoteDataReceived);
else
setReceiveDataMethod(null);
}

[/sourcecode]

public void setReceiveDataMethod(remoteControlDataReceived rcDataReceived), that sets the method that will be called when serial port data is received.

And some basics serial port data operations:

[caption id="attachment_1112" align="alignright" width="131"]Raspberry Pi - USB2Dynamixel - CM510 Raspberry Pi - USB2Dynamixel - CM510[/caption]

public bool open(String com, int speed), to open the serial port which name is in the com parameter. Wireless communications and USB ports, as used by Zig or USB2Dynaniel, are also serial ports  (COM1, COM2, ... or /ttyUSB0, ttyUSB1).

public void close(), it will do nothing if the port is already closed.

public byte[] query(byte[] buffer, int pos, int wait), send (write) a query and gets (read) the result.

public void rawWrite(byte[] buffer, int pos), well... it will write whatever contains the buffer in the first pos positions

public byte[] rawRead() , read and returns the data received.

Notes:


To avoid concurrency problems all the operations that use the Dynamixel bus are protected with a Mutex object that avoids that two or more concurrent objects use SerialPort2Dynamixel simultaneously entering the same operation or using the same resources, like variables, objects or the Dynamixel bus.

[caption id="attachment_1620" align="aligncenter" width="300"]Xevel USB2AX Xevel USB2AX[/caption]

[caption id="attachment_1622" align="aligncenter" width="300"]USB2AX over USB2DYNAMIXEL USB2AX over USB2DYNAMIXEL[/caption]


RCDataReader


[caption id="attachment_1155" align="alignright" width="150"]Bioloid RCDataReader C# Bioloid RCDataReader C#[/caption]

[caption id="attachment_1128" align="alignleft" width="112"]Remote communications RemoteCommunications[/caption]

Its responsability is to receive the Dynamixel Zig packets and extract the data.

Collaborator class:


- The ZigSequence enum, with the Dynamixels protocols data sections

[caption id="attachment_1171" align="aligncenter" width="300"]RC-100 packet RC-100 packet[/caption]

Operations:


[caption id="attachment_1146" align="alignleft" width="105"]Robotis RC-100 remote controller values Robotis RC-100 remote controller values[/caption]

public void rawRemoteDataReceived(byte[] rcData), receives the Zigbee data.

public int getValue(), returns the last value received

miércoles, 27 de febrero de 2013

Workshop: Dynamixel communications with C#

[Next post: Workshop: USB, serial and remote communications with C#]

As I wrote in the previous post, I am not using Robotis Dynamixel SDK USB2Dynamixelbecause it only works with the  USB2Dynamixel, and I need that it also should work with the serial port and with zigbee or bluetooth (really all 4 use the serial connection). Also I want to query sensors connected to the CM-510.

[caption id="attachment_1053" align="alignright" width="150"]Zigbee device Zigbee[/caption]

Using the CM-510 and computer serial port (or USB to serial) connection you are free to use any wired or wireless device. Really there are a lot of possibilities.

We will start connecting to the Dynamixel bus and sending commands and queries. These classes do the work:

- DynamixelCommunication

- SerialPort2Dynamixel

- RCDataReader

But there are other classes that offer to them some additional services, like Configuration, Utils, Hex and several enumeration types.

I will use the Class-Responsability-Collaboration template to present the classes.

DynamixelCommunicationBioloid DynamixelCommunication class C#


The main responsibility of this class is sending commands and queries to any Dynamixel device, including the sensors, sound and other capabilities of the CM-510 controller.

Collaborator classes:


SerialPort2Dynamixel,  that offers operations to use the serial port encapsulating .Net SerialPort class

- Three enums for easy use and avoid errors, using an specific type is safer that using simple integers.

    public enum AXS1_IRSensor { Left, Center, Right, None };
    public enum AXS1_SoundNote { LA, LA_, SI, DO, DO_, RE }; //Only the first six 
    public enum DynamixelFunction, with all the Dynamixel protocols codes and some that I added for the CM-510.

- Configuration class, that reads a file where are stored basic configuration parameters. like:

        private static string ParameterSerialPortName
        private static string ParameterSerialPortBaudRate
        private static string ParameterWaitTime_ms
        private static string ParameterWaitTimeForSensors_ms

Bioloid communications C#



Operations:


The public operations are the interface that other classes will use, like:

- short readValue(int id, DynamixelFunction address), reads the value of any AX-12 parameter (or other Dynamixels)


- bool sendOrder(int id, DynamixelFunction address, int value), send commands, like position, speed or torque.


And the private that do internal work supporting the public interface, like:

static int getReadWordCommand(byte[] buffer, byte id, DynamixelFunction address), create the Dynamixel hexadecimal sequence (FF FF 0F 05 03 1E CB 01 FE)


- static short getQueryResult(byte[] res), once the query or command is sent it gets the result.


Let's see readValue and two other called functions:

[sourcecode language="csharp"]

public short readValue(int id, DynamixelFunction address)
{
mutex.WaitOne();
short position = -1;

try
{
int size = getReadWordCommand(buffer, (byte)id, address);
byte[] res = serialPort.query(buffer, size, WaitTimeReadSensor);

position = getQueryResult(res);
if (position < 0)
Debug.show("DynamixelCommunication.readValue", position);

}
catch (Exception e)
{
Debug.show("DynamixelCommunication.readValue", e.Message);
}

mutex.ReleaseMutex();

return position;
}

private static int getReadWordCommand(byte[] buffer, byte id, DynamixelFunction address)
{
//OXFF 0XFF ID LENGTH INSTRUCTION PARAMETER1 …PARAMETER N CHECK SUM
int pos = 0;

buffer[pos++] = 0xff;
buffer[pos++] = 0xff;
buffer[pos++] = id;

// bodyLength = 4
buffer[pos++] = 4;

//the instruction, read => 2
buffer[pos++] = 2;

// AX12 register
buffer[pos++] = (byte)address;

//bytes to read
buffer[pos++] = 2;

byte checksum = Utils.checkSumatory(buffer, pos);
buffer[pos++] = checksum;

return pos;
}

private static short getQueryResult(byte[] res)
{
short value = -1;

if (res != null)
{
int length = res.Length;
if (res != null && length > 5 && res[4] == 0)
{
byte l = 0;
byte h = res[5];
if (length > 6)
{
l = res[6];
}

value = Hex.fromHexHLConversionToShort(h, l);
}
}
return value;
}

[/sourcecode]

Notes:


To avoid concurrency problems all the operations that use the Dynamixel bus are protected with a Mutex object that avoids that two or more concurrent objects use DynamixelCommunication simultaneously entering the same operation or using the same resources, like variables, objects or the Dynamixel bus.

All the operations use the same buffer, but being protected with the Mutex object I think that is the better option, although in a previous version I used a very different approach where there were AX12 objects with their own buffer.

[Next post: Workshop: USB, serial and remote communications with C#]

martes, 22 de noviembre de 2011

Start programming CM-5/CM-510 in C (AVR microcontrollers)

From time to time I receive questions about how to start programming the CM-5/CM-510 with C.

[This post is also in spanish]

I think it’s necessary to have a working knowledge about:

1. C programming

2. CM-5/CM-510 programming

3. Dynamixel protocol

You can find  a lot of information about CM-510 / CM-700  programming at Robotis support website And here you can learn how to create a simple "Hello World" program for CM-5

1. C programming

I think “C Programming for Microcontrollers is a fast and very practical introduction to C and microcontrolers programming, but I’m a not sure if it an easy way to start learning C.If you a want a more structured and deeper introduction to the C programming language, this is a pretty good and free introduction:


C introduction (pdf)


But there are a lot…


C Language Tutorial (html)
How C Programming Works (html)
Several C programming tutorials (html)


and more from Google


2. CM-5/CM-510 programming

From Robotis support website CM-5/CM-510 programming


3. Dynamixel protocol

From Robotis support website Dynamixel actuator


4. Your first step

If you use a CM-510 you will find here at Robotis support site a lot of information, and if you use the CM-5 you will find in this post some useful information and links


Two others great sources of information are:

Robosavvy Bioloid information wiki


Source code of Stuart&Matt library