Thursday, March 3, 2011

My Evalbot First Steps: Ethernet Controlled robot

Intro
So I finally received my arm stellaris Evalbot. So I put down the ARM stm32 for a bit and took out my evalbot.  The I got the eval bot with the 125$ discount i saw on http://hackaday.com/ turns out they sold more than they thought and they were put on back order.  I got mine now.

So since I all ready had Keil up and running (still waiting for the non commercial one. If i don't get it soon, I think I will go with a GCC tool chain) I decided to test it with the evalbot. first thing is first I downloaded their stellaris SDK and examples here. Next I downloaded the drivers from TI here. Finally, I stole 4 files from this arm evalbot project.  They are for motor control and the oled screen (oled.h/c motor.h/c).  They work well so why reinvent the wheel.  He also has a neat I2C lib in there.  I don't think I plan on ever writing my own code for that since its nicely done and would be a waste of time.  Now I am ready do create my project.  You can follow the same steps as the ARM STM32 only this time use the device LM3S9B92 by Luminary Micro and the "Stellaris ICDI" instead of "ST-Link" as the debug tool and the utility to flash the program.
 so the first thing I did was load the enet_lwip Example.  That is how I got the robot working online.  This I think is the only example that worked out of the box.  I will base this project all off this example project.  It should also come with a Keil uproj file and you can launch.  Because this code is copyright by TI and not open source, My next step is to build create my own project under the same license and LWIP.  For now we are just exploring so this copyright code is good enough.

Adding to the project
If you look at the main, there is not much.  I would recommend you look around the code and get familiar with it before reading on as I will just jump right into it.

First thing I did since I never got the UART to work, was Display the ip address once I received it.  We will need to add the oled.c file to our project.  I like to have a folder for every function in my project folder.  I created a folder called oled in the project folder and copied oled.h and oled.c in that folder.  Next, you need double click on the 3rdparty folder. I like to add both the .c and the .h file so its easy to open the .h file if I need to view the function names but you just need the .c file.  So click on the newly copied oled.c (and oled.h if you want) file and click add then click close.  Now we need to include the oled.h file.  so scroll to the top and add #include "oled/oled.h". Now that the prep work is done, we will head over to the function called lwIPHostTimerHandler in enet_lwip.c. First we should add our buffer unsigned char screenBuff[17] = {0}; 17 is because the LCD can only display 17 characters and 1 for the \0. There should be an if statement that looks like this:
if(ulIPAddress != g_ulLastIPAddr).  In the if block we will add the display code.  Here is what mine looks like after i striped the uart code:
     if(ulIPAddress != g_ulLastIPAddr)
    {
        g_ulLastIPAddr = ulIPAddress;
        dispClear();
        dispString("Ip obtained:    ",0,0);
        sprintf(screenBuff,"%d.%d.%d.%d",((unsigned char*)&g_ulLastIPAddr)[0],

              ((unsigned char*)&g_ulLastIPAddr)[1],
              ((unsigned char*)&g_ulLastIPAddr)[2],
              ((unsigned char*)&g_ulLastIPAddr)[3]);

        dispString(screenBuff,0,1);
        ulIPAddress = lwIPLocalNetMaskGet();
        ulIPAddress = lwIPLocalGWAddrGet();
    }

If you go a head now and plug a network cable in the evalbot,  wait a little bit for the DHCP to resolve you will get an IP address and a example web page if you http on that address.

Making it move
Now we will add some CGI to the project.  HTTPD that come with the example projects will look for calls to pages that end with the cgi file extension and call the associated function. You can go ahead and repeat the steps we took to add oled to our project but with motor instead (create the motor folder copy over the 2 files and and the .c/h file to the 3rdparty folder). Now we need to include the motor header. #include "motor/motor.h".   We will We will add 2 cgi handler 1 for the LCD and 1 for the motor control.  Lets create a file called cgi.h/.c and add it to our project.  I went a head and created a folder called cgi and saved the 2 files in there.  I also created a group called cgi and added both files to that group.  In our cgi.h file we will need to include #include "httpserver_raw/httpd.h".  we will also need to declare our 2 CGI functions and map them to the page.  Here is what my Header file looks like:
#include "httpserver_raw/httpd.h"
#ifndef CGI_H
#define CGI_H

char* LcdCGIHandler(int iIndex, int iNumParams, char *pcParam[],char *pcValue[]);
char* DriveCGIHandler(int iIndex, int iNumParams, char *pcParam[],char *pcValue[]);

//Map the CGI function to the cgi url
static const tCGI CGI_URI_MAP[] =
{
        { "/LCD.cgi", LcdCGIHandler },{ "/drive.cgi", DriveCGIHandler } /// CGI_INDEX_CONTROL
};
#endif
All we got left to do is define those 2 functions and enable CGI.  Before we do that, I created a .c/.h file called driving.  In there I put 4 function up() down() turnRight() turnLeft().  I will use these function in the example here and I will leave implementation of these functions as an exercise to the reader.  I will give you a head-start by showing you what my turnRight function looks like.  It should be very little work to create the other ones.

int GlobalI;  //this is used to stop the compiler from optimising

void turnRight(void)
{
    GlobalI=0; //set it to 0
    setMotor(MOTOR_L,MOTOR_DIR_F,0x40);  //Rotate the Left Motor toward the front
    setMotor(MOTOR_R,MOTOR_DIR_B,0x40); //Rotate the Right Motor toward the back

    //Wait a little bit taking baby steps
    // 0x44000 was chosen sorta randomly.  
    //I found waiting this long 4 time made it turn about 90 deg
     while(GlobalI<0x44000)
     {
             GlobalI++;
     }
    setMotor(MOTOR_L,MOTOR_DIR_F,0);  // Stop the Left Motor
    setMotor(MOTOR_R,MOTOR_DIR_B,0);  // Stop the Right motor
}

It should be pretty straight forward to add the other 3 missing functions.  No we are going to create our CGI functions.  Lets check out what the parameters do.  we got iIndex, this is the index of the cgi handler in the array. I am not sure where we would use this.  Next there is iNumParams.  This is the number of parameter that were found after the ? in the uri. the we have 2 arrays.  1 for the param name and 1 for their value.
So lest make a cgi that will display on the lcd what ever we pass as an argument in the uri.  This function returns a char* with the URI of the page the user should be redirected to.  We will make a global char* with the uri so that it does not go out or scope after we return.

char* indexName = "/index.htm";
char* LcdCGIHandler(int iIndex, int iNumParams, char *pcParam[],char *pcValue[])
{
    int i=0;
    //clear our LCD
    dispClear();
    //loop threw all the parameters
    for(i=0;i<iNumParams;i++)
    {
        //check if we found the parameter we want
        if(!strcmp(pcParam[i],"name")     )
        {
            //display the value we received
            dispString(pcValue[i],0,0);   
            //exit the loop
            i=iNumParams;
        }
    // return the Index uri to redirect the user
    return indexName;
}
It was pretty straight forward.  Now all we got to do is make the drive handler. I will only show how to make it turn right and it will be up to you to do the rest.  Make sure you include #include "motor/driving.h".

char* DriveCGIHandler(int iIndex, int iNumParams, char *pcParam[],char *pcValue[])
{
    int i=0;

    //loop threw the parameters
    for(i=0;i<iNumParams;i++)
    {

        //did we find the parameter we are looking for?
        if(!strcmp(pcParam[i],"dir")     )
        {

           // lest compare the directions
            if(!strcmp(pcValue[i],"up")     )
            {
                       
            }
            else if(!strcmp(pcValue[i],"dn")     )
            {
                       
            }
            else if(!strcmp(pcValue[i],"rt")     )
            {
                turnRight();       
            }
            else if(!strcmp(pcValue[i],"lt")     )
            {
                      
            }   
        }

    }

    // return the user to /index.htm
    return indexName;
}

All we got left to do in enable our CGI.  By default, the CGI is not compiled so we will need to add a define to tell httpd to compile it so lets add the define INCLUDE_HTTPD_CGI in the options.  Hit Alt+F7 to open the option dialog.  head over to the C/C++ tab and in the define section add INCLUDE_HTTPD_CGI.
Now head back to your main.  Right under the variable decelerations, you can call init_display(); and init_motorPWM(); I actually added it right after the ROM_SysCtlClockSet call.

Now right on top of httpd_init(); we will add our  CGI map like this
http_set_cgi_handlers(CGI_URI_MAP, 2);  //the 2 is the number of CGI handlers we have defined.  Don't forget to #include "cgi/cgi.h".

Now if you go to your browser and navigate to http://evalbotIP/LCD.cgi?name=Hello
it should display hello on the LCD. if you head over to http://evalbotIP/drive.cgi?dir=rt
the evalbot robot should turn right.

My Next post in the next couple days will be hosting the web page from a USB key.
Neat little ARM based robot.

6 comments:

  1. Let me know if you get into any difficulties So I can update my posts and add give credit. Or if you want my source code. I don't have a place to host it at the moment so I can email it if you like.

    ReplyDelete
  2. I'd like the source, if possible. Trying to implement this in CCS/Eclipse, but having difficulty following this guide. :-/

    ReplyDelete
  3. sure send me an email to my google adress jeanmarc.leblanc.

    where are you having problems?

    ReplyDelete
  4. I've encountered a few problems concerning unresolved symbols and function declared implicitly from the stellaris SDK.
    Apparently the "#define TARGET_IS_TEMPEST_RB1" should be located in the project configuration to prevent such problems.

    ReplyDelete
  5. Hi,
    Luminary server is now down and I can't get the evalbot example anymore, even on TI web site. Unfortunately , Stellarisware doesn't contains evalbot example for ethernet. Coud you please send me the initial example or your program.
    Thank you !

    ReplyDelete