Table of Contents
Robotino Rectangle Tutorial
This tutorial is part of the Robotino Operation series.
Purpose: to explain how to write a basic robotino program using robotino api2, compile and run it. The program written in this tutorial will take in user specified rectangle and drive around it's perimeter.
Downloads
The completed project ready to upload via ftp: rect.zip
Videos
If you are not interested in learning about the code you can jump straight to the compile video
The finished program running:
Writing the code
boiler plate:
Below is a basic boiler plate for your robotino program. It includes some basic c libraries. More importantly, it includes the api2 library.
- boilerplate.cpp
#define _USE_MATH_DEFINES #include <cmath> #include <iostream> #include <stdlib.h> #include "rec/robotino/api2/all.h" // include the api2 library using namespace rec::robotino::api2; // we are going to be operating in the api2 namespace for this tutorial float _rect[2]= {0,0}; // this is going to be the size of the rectangle our robotino will drive in. bool _run = true;
Overriding the com class
The API2 com class allows us to communicate with the robotino's microcontroller. It has several virtual functions that we will need to overwrite in order to use it.
- MyCom.h
class MyCom : public Com { public: MyCom() : Com( "rect" ) // name our com after our program { } /* ** below we deal with the virtual functions. for our purposes a simple cout will suffice */ void errorEvent( const char* errorString ) { std::cerr << "Error: " << errorString << std::endl; // remember we are using namespace::api2 so we need to type std:: to access cout and cerr } void connectedEvent() { std::cout << "Connected." << std::endl; } void connectionClosedEvent() { std::cout << "Connection closed." << std::endl; } void logEvent( const char* message, int level ) { std::cout << message << std::endl; } void pingEvent( float timeMs ) { std::cout << "Ping: " << timeMs << "ms" << std::endl; } };
Setting up our bumper
Once again we need to override a built in API2 class. We want to tell the robotino to stop when the bumper has contact with something.
- MyBumper.h
class MyBumper : public Bumper { public: MyBumper() : bumped( false ) { } void bumperEvent( bool hasContact ) { bumped |= hasContact; std::cout << "Bumper has " << ( hasContact ? "contact" : "no contact") << std::endl; } bool bumped; };
Declare instances of our classes:
Now declare instances of the classes you created and an instance of OmniDrive.
MyCom com; OmniDrive omniDrive; MyBumper bumper;
init() function:
The init function will be used to set up our robotino when the user launches our executable.
- init.cpp
void init( const std::string& hostname ) { // Initialize the actors // Connect std::cout << "Connecting... "; com.setAddress( hostname.c_str() ); com.connectToServer( true ); if( false == com.isConnected() ) { std::cout << std::endl << "Could not connect to " << com.address() << std::endl; rec::robotino::api2::shutdown(); exit( 1 ); } else { // if everything goes alright we say success and ask the user the size of the rectangle to trace std::cout << "success" << std::endl; std::cout << "enter rectange x in mm:" << std::endl; std::cin >> _rect[0]; // just use std:cin to take in the size of the rectangle. std::cout << "enter rectange y in mm:" << std::endl; std::cin >> _rect[1]; } }
Driving the robotino
The drive() function will be used to move the robotino around using the omniDrive class
- drive.cpp
void drive() { float vel[2] = {0.1, 0.0}; // create an array to store our velocity float pos[2] = {0,0}; // create an array to store our position float lastTime=com.msecsElapsed(); // remember last time to measure change in time to calculate position while( com.isConnected() && false == bumper.value() && _run ) { pos[0]=vel[0]*(com.msecsElapsed()-lastTime)+pos[0]; // update the position pos[1]=vel[1]*(com.msecsElapsed()-lastTime)+pos[1]; std::cout << "Pos:" << pos[0] << "," << pos[1] <<std::endl; // print out the position.\ omniDrive.setVelocity( vel[0], vel[1], 0 ); // set the x and y velocity to our velocity setting set rotational velocity to 0 if(pos[0]>=_rect[0] && pos[1] <= 0){ // this if statement changes the velocity when we reach the first corner of our rectange vel[0]=0; vel[1]=.1; } if(pos[0]>=_rect[0] && pos[1] >= _rect[1]){ // second corner vel[0]=-0.1; vel[1]=0; } if(pos[0]<=0 && pos[1] >= _rect[1]){ // third corner vel[0]=0; vel[1]=-0.1; } if(pos[0]<=0 && pos[1] <= 0){ // back to start location vel[0]=0.1; vel[1]=0; } lastTime=com.msecsElapsed(); // reset the last time variable com.processEvents(); // sincronizes the com class and the onboard computer rec::robotino::api2::msleep( 100 ); // wait 100 ms } }
Destroy:
when we are ready to quit we want to run destroy
void destroy() { com.disconnectFromServer(); // simply disconnect the com }
main program
Now we just need to write our main function to call the functions written above in the proper order.
- main.cpp
int main( int argc, char **argv ) { std::string hostname = "172.26.1.1"; // set our local hostname of our microcontroller if( argc > 1 ) // boiler plate stuff { hostname = argv[1]; } try // try to run our functions { init( hostname ); // these functions explained above drive(); destroy(); } // below we catch any errors that cropped up catch( const rec::robotino::api2::RobotinoException& e ) { std::cerr << "Com Error: " << e.what() << std::endl; } catch( const std::exception& e ) { std::cerr << "Error: " << e.what() << std::endl; } catch( ... ) { std::cerr << "Unknow Error" << std::endl; } rec::robotino::api2::shutdown(); // shut down API2 }
Compiling
In order to compile your program on your robotino you will need a CMakeLists.txt file. I have included it above for download. rect.zip
Create a folder on your robotino.
mkdir ~/dasl_tutorials/rect
switch to that directory
cd ~/dasl_tutorials/rect
On your pc put main.cpp document and your CMakeLists.txt file into a folder called src. Upload your src file to ~/dasl_tutorials/rect using your favorite ftp. My personal favorite is Transmit by Panic.
FTP username: robotino FTP password: robotino
Now you are all set to follow the video tutorial!
The finished program running: