====== Robotino Rectangle Tutorial ====== **This tutorial is part of the [[robotino_operation|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: {{dylanw:rect.zip}} ===== Videos ===== If you are not interested in learning about the code you can jump straight to the compile video {{youtube>wy88DKn-6x4?large}} The finished program running: {{youtube>sw0jyGtzqhg?large}} ===== 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. #define _USE_MATH_DEFINES #include #include #include #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. 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. 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. 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 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] <=_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. 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. [[:File: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 [[http://panic.com/transmit/|Transmit]] by Panic. FTP username: robotino FTP password: robotino Now you are all set to follow the video tutorial! {{youtube>wy88DKn-6x4?large}} The finished program running: {{youtube>sw0jyGtzqhg?large}}