views:

365

answers:

4

I've written a program to get a string input from a user and parse it into tokens and move a robot according to the input. My problem is trying to issue more than one command. The code looks like:

void Navigator::manualDrive()
{

    const int bufSize = 42;
    char uinput[bufSize];
    char delim[] = " ";
    char *token;
    while(true)
    {

        Navigator::parseInstruction(uinput);
    }
}  
/* parseInstruction(char *c) -- parses cstring instructions received
* and moves robot accordingly
*/


void Navigator::parseInstruction(char * c)
{

    const int bufSize = 42;
    char uinput[bufSize];
    char delim[] = " ";
    char *token;


    cout << "Enter your directions below: \n";
    cin.ignore();
     cin.getline (uinput, bufSize);


    token=strtok(uinput, delim);
    if(strcmp("forward", token) == 0)
    {
        int inches;
        token = strtok(NULL, delim);
        inches = atoi (token);
        Navigator::travel(inches);
    }
    if(strcmp("back",token) == 0)
    {
        int inches;
        token = strtok(NULL, delim);
        inches = atoi (token);
        double value = fabs(0.0735 * fabs(inches) - 0.0550);
        myRobot.backward(1/*speed*/, value/*time*/);
    }
    if(strcmp("turn",token) == 0)
    {
        int degrees;
        token = strtok(NULL, delim);
        if(strcmp("left",token) == 0)
        {
            token = strtok(uinput, delim);
            degrees = atoi (token);
            double value = fabs(0.0041 * degrees - 0.0523);
            myRobot.turnLeft(1/*speed*/, value/*time*/);
        }
    }
    if(strcmp("turn",token) == 0)
    {
        int degrees;
        token = strtok(NULL, delim);
        if(strcmp("right",token) == 0)
        {
            token = strtok(uinput, delim);
            degrees = atoi (token);
            double value = fabs(0.0041 * degrees - 0.0523);
            myRobot.turnRight(1/*speed*/, value/*time*/);
        }
    }
    if(strcmp("stop",token) == 0)
    {
        myRobot.motors(0,0);
    }
}

In the function manualDrive I have a while loop calling the function parseInstruction infinitely. The program outputs "Enter your directions below: " When I give the program instructions it executes them, and then it outputs "enter your directions below: " again and when I input my directions again it does not execute them and outputs "Enter your directions below: " instead. I'm sure this is a very simple fix I'm just very new to c++. So if you could please help me out and tell me why the program only takes the first set of directions. thanks

+1  A: 

This sounds like the common issue that occurs when your cin command reads in the new line character from the previous input. I see that you have cin.ignore(), which is usually the fix for that problem, but it's still happening anyway.

Try moving your ignore to after the getline() command

brydgesk
I moved the ignore() after getline() and the robot didn't move and I got segmentation fault.
Van
+1  A: 

You shouldn't need the cin.ignore() line here. cin.getline should already extract and discard the delimiter. I suspect it was throwing away the first character of your command. You can check this by changing your if statements to else-ifs and adding an else block at the end:

if(strcmp("forward", token) == 0)
else if(strcmp("back",token) == 0)
else if(strcmp("turn",token) == 0)
else if(strcmp("turn",token) == 0)
else if(strcmp("stop",token) == 0)
else
{
    std::cerr << "Unknown command '" << token << "'\n";
}
Tim
We use bluetooth devices for sending signals to and from the robot(there seem to be lag issues). When the robot sends information back to the device to let us know it has connected, the program puts the info into the cin.getline() and ends the program(which shouldn't happen now that the function is in a while loop). I used cin.ignore() to negate this action. However, your suggestion certainly seems worthwhile, and I will try it out when I'm back in the lab tomorrow around 5pm EST.
Van
This is a good suggestion though; when your program seems to be misinterpreting the input, the first thing to check is if the program is seeing the input the way you think it should be!
dash-tom-bang
You were correct the cin.ignore() was throwing away the first letter of input. Without cin.ignore() the program wouldn't run so what I ended up doing was moving it to my driver program just after it connects to the robot and just before my manual drive function is called.
Van
A: 

I believe your multiple if statements are part of the cause along with misreading the commands. I would also use the endl instead of using the /n char. Doing so means you don't need ignore.

void Navigator::manualDrive()
{

    const int bufSize = 42;
    char uinput[bufSize];
    char delim[] = " ";
    char *token;
    while(true)
    {

        Navigator::parseInstruction(uinput);
    }
}  
/* parseInstruction(char *c) -- parses cstring instructions received
* and moves robot accordingly
*/


void Navigator::parseInstruction(char * c)
{

    const int bufSize = 42;
    char uinput[bufSize];
    char delim[] = " ";
    char *token;


    cout << "Enter your directions below: " << endl;
    cin.getline (uinput, bufSize);


    token=strtok(uinput, delim);
    switch(token[3])//the command's fourth letter
    //needed letter because strings don't work with switch
    {
        case 'w': //forward
            int inches;
            token = strtok(NULL, delim);
            inches = atoi (token);
            Navigator::travel(inches);
            break;//this signifies the end of the case

        case 'k': //back
            int inches;
            token = strtok(NULL, delim);
            inches = atoi (token);
            double value = fabs(0.0735 * fabs(inches) - 0.0550);
            myRobot.backward(1/*speed*/, value/*time*/);
            break;

        case 'n': //turn
            int degrees;
            token = strtok(NULL, delim);
            if(strcmp("left",token) == 0)
            {
                token = strtok(uinput, delim);
                degrees = atoi (token);
                double value = fabs(0.0041 * degrees - 0.0523);
                myRobot.turnLeft(1/*speed*/, value/*time*/);
            }
            else if(strcmp("right",token) == 0)
            {
                token = strtok(uinput, delim);
                degrees = atoi (token);
                double value = fabs(0.0041 * degrees - 0.0523);
                myRobot.turnRight(1/*speed*/, value/*time*/);
            }
            break;

        case 'p': //stop
            myRobot.motors(0,0);
            break;

        default: //the default case
            cout << "Command Unknown" << endl;
            break;
    }
}
datdo
I like using switch case much better than if statements for some reason so I'll probably give it a shot. Do I need to define each cases' letter? EX: char w[]= "forward";
Van
I think you misunderstood how switch case works. The parameter of switch is compared to each case so you don't need to declare any variables for each case.
datdo
Never mind I just realized what switch(token[3]) was doing for some reason. It finds the fourth letter and if its w(forward's 3th letter) then it executes case 'w'. Sorry I'm a major n00b, it's definitely going to be a while before I'm the one helping out on this website.
Van
I didn't use switch case, but you did help me realise why my robot wouldn't turn right. I combined my two turn statements into one as you did above and it worked like a charm. Thanks
Van
A: 
gnometorule