Class Library for Hokuyo URG-04LX Range Finder (using SCIP1 communication specification)

Dependents:   mbed_Hokuyo_Example

This library interfaces the mbed to the Hokuyo 2D scanning laser range finder. The interface assumes the user has properly level shifted the serial communication lines to TTL (3.3 volt or 5 volt) levels from the Hokuyo URG-04LX RS-232 level UART. It should also be noted that the device requires about an amp of current on startup, then drops to a little less then a half amp when running. A sufficient 5 volt switching supply is my recommended power source. I am currently working on a function to auto detect the baud rate on initialization and change it to 750000. The heart of the library is a serial read function with timeout, which allows for capturing large data strings (non-ASCII or otherwise) of maximum length by using a state machine without having to alter the MODSERIAL library internal buffer sizes.

hokuyo.cpp

Committer:
jebradshaw
Date:
2016-03-04
Revision:
0:a325ad337940

File content as of revision 0:a325ad337940:

// J Bradshaw 20160304

#include "hokuyo.h"

Hokuyo::Hokuyo(PinName tx, PinName rx) : _hokuyo(tx, rx) {
    _hokuyo.baud(19200);
}

int Hokuyo::lidar_read(char *str, int numchars, float timeoutDelay){        
    Timer t_Frame;
    int i=0;        
    int timeoutState=0;
    float timeout;
    
    t_Frame.start();
    
    while(timeoutState != 3  && (i < numchars)){
        switch(timeoutState){
            case 0:
                while(_hokuyo.readable()){ //if characters are in buffer, read them
                    str[i++] = _hokuyo.getc();
                    if(i == numchars){
                        timeoutState = 3;
                        break;   
                    }
                }
                //if no characters in buffer, initiate timeout
                timeoutState = 1;
                break;
            case 1:
                timeout = t_Frame.read() + timeoutDelay;    //current time plus timeout time
                timeoutState = 2;
//                                              pc.printf("Timeout initiated %f\r\n", timeout);
                break;
            case 2:
                if(_hokuyo.readable()){ //check buffer while timeout is running
                    str[i++] = _hokuyo.getc();
                    if(i == numchars){
                        timeoutState = 3;
                    }
                    else{
                        timeoutState = 0;
                    }
                    break;
                }
                if(t_Frame.read() >= timeout) //if timeout has elapsed, exit the while loop with state 3
                    timeoutState = 3;
                break;
            default:
                timeoutState = 0;
        }//switch timeoutState                             
    }//while timeoutState != 2
    return i;   //return number of bytes read
}

int Hokuyo::Init(void)
{
    char sent[20];
    
    _hokuyo.printf("L1\n");        //turn laser on
    wait(.1);
    //printf("Received %s", sent);
    _hokuyo.scanf("%s",&sent);
    
    if(!strcmp(sent, "L1")){  //if "L1\n" returned, successful
        sent[0] = '\0';
        _hokuyo.scanf("%s",&sent);
        
        if(!strcmp(sent, "0")){   // if "0\n" returned, successful
            //printf("Hokuyo Init SUCCESS\r\n");
            return 0;
        }        
        else{
            return -1;
        }
    }
    else{        
        //printf("ERROR - L1 not returned on initialization, received %s\r\n", sent); 
        return -2;
    }
}

//Uses the SCIP 1.0 : C-42-3320A protocol for scanner commands
int Hokuyo::Read_Scan(float scan_deg, int clust_size)
{
    char sent[MAXBUFSIZE];
    int N_read, i, j, k;
    int range_val, range_l, range_h;
    float minstep, maxstep;
    char temp[68];
    char *tok;
    int cluster;
    float angle_read;
    int stepnum;
    Timer t_delay;

    stepnum = 0;
    angle_read = -scan_deg/2.0;

    for(i=0;i<MAXBUFSIZE;i++)
        sent[i] = 0;

    while(this->_hokuyo.readable())     //clear the read buffer
        char c = this->_hokuyo.getc();
        
    minstep = 384 - (scan_deg/2.0)/.351;
    maxstep = 384 + (scan_deg/2.0)/.351;

    if(minstep < 0.0)            //-135 deg
        minstep = 0.0;
    if(maxstep > 768)            //+135 deg
        maxstep= 768;
    //int totalsteps = (int)(maxstep - minstep);
    cluster = clust_size;    //totalsteps/(int)scan_deg;
        
    strcpy(sent, "G");
    sprintf(temp, "%03d", (int)minstep);
    strcat(sent, temp);
    sprintf(temp, "%03d", (int)maxstep);
    strcat(sent, temp);
    sprintf(temp, "%02d", cluster);
    strcat(sent, temp);
    strcpy(temp, sent);

    this->_hokuyo.printf("%s\n",temp);   //fire laser
//   serBputs("G12863214\n");   //fire laser

    t_delay.start();
    while(!this->_hokuyo.readable()){
        if(t_delay.read() > .13){
            printf("Timeout before receiving data packet\r\n");
            wait(2);
            return -1;      //timeout before receiving data packet
        }
    }
    t_delay.stop();
//    wait(.13);

   N_read = this->lidar_read(sent, MAXBUFSIZE, .005);
    //pc.printf("number of bytes read = %d\r\n", N_read);

   tok = strtok(sent, "\n");        //extract first string
//   pc.printf("%s was received back = should be the sent command!\r\n", tok);
   
   if(!strcmp(temp, tok))           //if sent command was received back
   {
       tok = strtok(NULL, "\n");    //extract error message
      if(atoi(tok) == 0)            //if error was 0
      {
                //bytes read - command returned\n and error\n
            for(k=N_read-12;k>0;k-=65)  //64 data bytes plus '\n'
         {
              tok = strtok(NULL, "\n");  //get data string
              strcpy(temp, tok);
              j=strlen(temp);

              for(i=0;i<j;i++)
              {
                range_h = ((temp[i] - 0x30) << 6);
                i++;
                range_l = (temp[i] - 0x30);
                range_val = range_h + range_l;
                this->dist_mm[stepnum] = range_val;
                //printf("%3d %7.2f   %5d\r\n", stepnum++,angle_read, range_val);                    
                
                angle_read += (float)cluster * .351;
                this->angle[stepnum] = angle_read;
                stepnum++;
              }
         }  //read 64 bytes or remaining bytes at a time from returned data string
//         printf("\r\n\r\n");
            this->numPts = stepnum;
            return 0;        //returns 0 on success
      } //no error
      else
      {
          printf("Error Taking Scan! Error returned.\r\n");
          return -2;
      }
   }    //command was received back
   else
   {
      printf("Error Taking Scan. No command returned!\r\n");
      return -1;
   }
}

/*
//Working on function for auto baud detect and change to 750000 baud
int Init_Hokuyo(int baudrate)
{
    char sent[20];
    char temp[20];
    
    lidar.baud(19200);
    lidar.printf("L1\n");        //turn laser on
    wait(.1);
    lidar_read(sent, 3, .5);
    //lidar.scanf("%s",&sent);
    pc.printf("Received %s", sent);
    
    if(!strcmp(sent, "L1")){  //if "L1\n" returned, successful
        sent[0] = '\0';
        lidar.scanf("%s",&sent);
        
        if(!strcmp(sent, "0")){   // if "0\n" returned, successful
            pc.printf("Hokuyo Init SUCCESS\r\n");
            sprintf(temp, "S%06dFFFFFFF\n", baudrate);
            lidar.printf("%s", temp);
            
            lidar.scanf("%s\n",&sent);
            pc.printf("Received %s", sent);
            
            if(!strncmp(temp, sent, 14)){
                pc.printf("Changing baud rate to %06d\r\n", baudrate);
                lidar.baud(baudrate);        
            }
            
            return 0;
        }        
        else{
            return -1;
        }
    }
    else{
        lidar.baud(750000);
        lidar.printf("L1\n");        //turn laser on
        wait(.1);
        lidar_read(sent, 3, .5);
        pc.printf("Received %s", sent);
        
        if(!strcmp(sent, "L1")){  //if "L1\n" returned, successful
            sent[0] = '\0';
            lidar.scanf("%s",&sent);
            
            if(!strcmp(sent, "0")){   // if "0\n" returned, successful
                pc.printf("Hokuyo Init SUCCESS\r\n");
                sprintf(temp, "S%06dFFFFFFF\n", baudrate);
                lidar.printf("%s", temp);
                
                lidar.scanf("%s\n",&sent);
                pc.printf("Received %s", sent);
                
                if(!strncmp(temp, sent, 14)){
                    pc.printf("Changing baud rate to %06d\r\n", baudrate);
                    lidar.baud(baudrate);        
                }
                return 0;
            }        
            else{
                return -1;
            }
        }        
        pc.printf("ERROR - L1 not returned on initialization, received %s\r\n", sent); 
        return -2;
    }
}
*/