View unanswered posts | View active topics It is currently Wed Aug 20, 2014 12:51 am






Reply to topic  [ 8 posts ] 
LEGO color sensor interferes with waitForStart() 
Author Message
Rookie

Joined: Wed Jul 21, 2010 11:23 pm
Posts: 39
Post LEGO color sensor interferes with waitForStart()
To signal which automomous activity is selected my team flashes the LEGO color sensor either red or blue. After adding this task to the program their robot started randomly bypassing the waitForStart() function. The amount of time before randomly starting varies anywhere between 1 and 250 seconds. If we disable the flash_light task the problem goes away. Same thing if we delete the references to the HiTechnic motor controller.

If the HiTechnic motor controller remains configured but is powered down the problem also goes away. It makes no difference if joysticks are connected or not, same thing for Samantha, connected and/or powered makes no difference. In all these cases the robot eventually bypasses waitForStart() if the LEGO color sensor flashes and a HiTechnic motor controller is configured and powered up.

I’ve reduced the program to bare bones – as written it should wait forever and never play the sound, but it appears that there is some type of interaction between the HiTechnic motor controller and the LEGO color sensor whereby the StopPgm flag within the joystick packet gets corrupted. Hopefully someone with a LEGO color sensor can run this code and verify we’re not doing something stupid and that I’m not going crazy.

Code:

#pragma config(Hubs,  S1, HTMotor,  none,     none,     none)
#pragma config(Sensor, S1,     ,                    sensorI2CMuxController)
#pragma config(Sensor, S4,     COLOR,               sensorCOLORFULL)
#pragma config(Motor,  mtr_S1_C1_1,     motorD,        tmotorNormal, openLoop)
#pragma config(Motor,  mtr_S1_C1_2,     motorE,        tmotorNormal, openLoop)
//*!!Code automatically generated by 'ROBOTC' configuration wizard               !!*//

#include "JoystickDriver.c"

task flash_light()
{
  while (true)
  {
    SensorType[COLOR] = sensorCOLORBLUE;
    wait1Msec(500);
    SensorType[COLOR] = sensorCOLORNONE;
    wait1Msec(300);
  }
}


// =======================
// Main program begins
// =========================
task main()
{
  StartTask (flash_light);
  waitForStart();
  PlaySound(soundFastUpwardTones);
  wait1Msec(2000);
}


Wed Nov 23, 2011 4:13 am
Profile
Guru
User avatar

Joined: Sun Nov 15, 2009 5:46 am
Posts: 1347
Post Re: LEGO color sensor interferes with waitForStart()
Don't really know what's wrong with your particular problem but I have found bugs in RobotC in the past that it corrupted memory. I have also read threads somewhere about accessing the joystick in different tasks may cause data corruption. However, in your case, your flash_light task doesn't seem to access the joystick, so I am not sure if it is related to that. Either way, you may want to work around the issue by avoiding task. For example.
Code:
task main()
{
    TSensorTypes lightColor = sensorCOLORNONE;
    long nextTime = nPgmTime;
    long currTime;

    initRobot();
    //
    // The following code is equivalent to waitForStart()
    //
    while (true)
    {
        getJoystickSettings(joystick);
        if (!joystick.StopPgm)
            break;

        currTime = nPgmTime;
        if (currTime >= nextTime)
        {
            SensorType[COLOR] = lightColor;
            if (lightColor == sensorCOLORNONE)
            {
                lightColor = sensorCOLORBLUE;
                nextTime = currTime + 300;
            }
            else
            {
                lightColor = sensorCOLORNONE;
                nextTime = currTime + 500;
            }
        }
    }
    SensorType[COLOR] = sensorCOLORNONE;
    PlaySound(soundFastUpwardTones);
    wait1Msec(2000);
}

Alternatively, you may want to do what we did. We have a library module (http://proj.titanrobotics.net/hg/Ftc/20 ... lib/menu.h) that will display a menu on the NXT LCD screen. You can press the NXT left and right buttons to scroll up and down the menu, then press ENTER to select the autonomous strategy. It will then call waitForStart(). For example:
Code:
#include "menu.h"

#define CHOICE_BLUE_ALLIANCE    0
#define CHOICE_RED_ALLIANCE     1

MENU g_Menu;
int  g_Choice;

task main()
{
    RobotInit();

    MenuInit(g_Menu, "Strategies:");
    MenuAddChoice(g_Menu, "Blue Alliance");
    MenuAddChoice(g_Menu, "Red Alliance");

    g_Choice = MenuGetChoice(g_Menu);
    nxtDisplayCenteredTextLine(4, g_Menu.choices[g_Choice]);

    waitForStart();
    while (true)
    {
        if (g_Choice == CHOICE_BLUE_ALLIANCE)
        {
        }
        else if (g_Choice == CHOICE_RED_ALLIANCE)
        {
        }
    }
}


Last edited by MHTS on Wed Nov 23, 2011 6:30 am, edited 2 times in total.



Wed Nov 23, 2011 5:46 am
Profile
Guru
User avatar

Joined: Sun Nov 15, 2009 5:46 am
Posts: 1347
Post Re: LEGO color sensor interferes with waitForStart()
Here is a stripped down version of the menu.h module.
Code:
#if 0
/// Copyright (c) Titan Robotics Club. All rights reserved.
///
/// <module name="menu.h" />
///
/// <summary>
///     This module contains the library functions for displaying a choice
///     menu on the NXT LCD screen and allowing the user to scroll through
///     the menu and pick a choice.
/// </summary>
///
/// <remarks>
///     Environment: RobotC for Lego Mindstorms NXT.
/// </remarks>
#endif

#ifndef _MENU_H
#define _MENU_H

#pragma systemFile

//
// Constants
//
#define NXTBTN_DEBOUNCE_TIME    20
#ifndef MAX_NUM_CHOICES
    #define MAX_NUM_CHOICES     16
#endif
#define NUM_DISPLAY_LINES       8
#define NUM_PIXELS_PER_LINE     8
#define NUM_LINE_PIXELS         100

#define MENUF_ENABLED           0x0001

#define LinePos(n)              (NUM_DISPLAY_LINES*NUM_PIXELS_PER_LINE - 1 - \
                                 (n)*NUM_PIXELS_PER_LINE)
#define MenuIsEnabled(m)        ((m.menuFlags & MENUF_ENABLED) != 0)
#define MenuGetUserChoice(m)    (m.userChoice)

//
// Type definitions.
//
typedef struct
{
    string   titleText;
    int      menuFlags;
    int      numChoices;
    string   choices[MAX_NUM_CHOICES];
    int      currChoice;
    int      firstChoice;
    int      userChoice;
} MENU;

/**
 *  This function initializes the choice menu.
 *
 *  @param menu Points to the MENU structure to be initialized.
 *  @param titleText Specifies the title text of the menu.
 */
void
MenuInit(
    MENU &menu,
    string titleText
    )
{
    strcpy(menu.titleText, titleText);
    menu.menuFlags = 0;
    menu.numChoices = 0;
    menu.currChoice = 0;
    menu.firstChoice = 0;
    menu.userChoice = -1;
}   //MenuInit

/**
 *  This function adds a choice to the menu.
 *
 *  @param menu Points to the MENU structure to be initialized.
 *  @param choiceText Specifies the choice text.
 *
 *  @return Returns true if the choice is added successful, otherwise the
 *          menu is full.
 */
bool
MenuAddChoice(
    MENU &menu,
    string choiceText
    )
{
    bool fSuccess = false;

    if (menu.numChoices < MAX_NUM_CHOICES)
    {
        strcpy(menu.choices[menu.numChoices], choiceText);
        menu.numChoices++;
        fSuccess = true;
    }

    return fSuccess;
}   //MenuAddChoice

/**
 *  This function invert the menu line.
 *
 *  @param lineNum
 */
void
MenuInvertLine(
    int lineNum
    )
{
    for (int y = LinePos(lineNum + 1) + 1; y <= LinePos(lineNum); y++)
    {
        nxtInvertLine(0, y, NUM_LINE_PIXELS -1, y);
    }
}   //MenuInvertLine

/**
 *  This function is called to refresh the menu display.
 *
 *  @param menu Points to the MENU structure.
 */
void
MenuDisplay(
    MENU &menu
    )
{
    eraseDisplay();
    nxtDisplayTextLine(0, menu.titleText);
    for (int choice = menu.firstChoice;
         choice < menu.firstChoice + NUM_DISPLAY_LINES - 1;
         choice++)
    {
        nxtDisplayTextLine(choice - menu.firstChoice + 1,
                           "%d:%s", choice, menu.choices[choice]);
    }
    MenuInvertLine(menu.currChoice - menu.firstChoice + 1);
}   //MenuDisplay

/**
 *  This function is called to enable or disable the menu.
 *
 *  @param menu Points to the MENU structure.
 *  @param fEnable If true, display and enable the menu, otherwise erase and
 *         disable the menu.
 */
void
MenuSetState(
    MENU &menu,
    bool fEnable
    )
{
    if (fEnable)
    {
        menu.userChoice = -1;
        MenuDisplay(menu);
        menu.menuFlags |= MENUF_ENABLED;
    }
    else
    {
        menu.userChoice = menu.currChoice;
        menu.menuFlags &= ~MENUF_ENABLED;
        eraseDisplay();
    }
}   //MenuSetState

/**
 *  This function set the current choice to next or previous.
 *
 *  @param menu Points to the MENU structure.
 *  @param inc Specifies the increment.
 */
void
MenuIncChoice(
    MENU &menu,
    int inc
    )
{
    menu.currChoice += inc;
    if (menu.currChoice < 0)
    {
        menu.currChoice += menu.numChoices;
    }
    else if (menu.currChoice >= menu.numChoices)
    {
        menu.currChoice -= menu.numChoices;
    }

    int lineNum = menu.currChoice - menu.firstChoice + 1;
    if (lineNum >= NUM_DISPLAY_LINES)
    {
        menu.firstChoice = menu.currChoice - (NUM_DISPLAY_LINES - 2);
    }
    else if (lineNum < 1)
    {
        menu.firstChoice = menu.currChoice;
    }
    MenuDisplay(menu);
}   //MenuIncChoice

/**
 *  This function displays the menu and returns the user choice.
 *  Note that this is a blocking function. It should only be called outside
 *  of the robot loop (e.g. in RobotInit).
 *
 *  @param menu Points to the MENU structure to be initialized.
 *
 *  @return Returns the user choice.
 */
int
MenuGetChoice(
    MENU &menu
    )
{
    TButtons prevNxtBtn = nNxtButtonPressed;
    TButtons currNxtBtn;

    MenuSetState(menu, true);
    while (true)
    {
        currNxtBtn = nNxtButtonPressed;
        if (currNxtBtn != prevNxtBtn)
        {
            if (currNxtBtn == kLeftButton)
            {
                MenuIncChoice(menu, -1);
            }
            else if (currNxtBtn == kRightButton)
            {
                MenuIncChoice(menu, 1);
            }
            else if (currNxtBtn == kEnterButton)
            {
                break;
            }
            prevNxtBtn = currNxtBtn;
            wait1Msec(NXTBTN_DEBOUNCE_TIME);
        }
    }
    MenuSetState(menu, false);

    return menu.userChoice;
}   //MenuGetChoice

#endif  //ifndef _MENU_H


Wed Nov 23, 2011 6:24 am
Profile
Rookie

Joined: Wed Jul 21, 2010 11:23 pm
Posts: 39
Post Re: LEGO color sensor interferes with waitForStart()
MHTS wrote:
Either way, you may want to work around the issue by avoiding task. For example.
Code:
task main()
{
    TSensorTypes lightColor = sensorCOLORNONE;
    long nextTime = nPgmTime;
    long currTime;

    initRobot();
    //
    // The following code is equivalent to waitForStart()
    //
    while (true)
    {
        getJoystickSettings(joystick);
        if (!joystick.StopPgm)
            break;

        currTime = nPgmTime;
        if (currTime >= nextTime)
        {
            SensorType[COLOR] = lightColor;
            if (lightColor == sensorCOLORNONE)
            {
                lightColor = sensorCOLORBLUE;
                nextTime = currTime + 300;
            }
            else
            {
                lightColor = sensorCOLORNONE;
                nextTime = currTime + 500;
            }
        }
    }
    SensorType[COLOR] = sensorCOLORNONE;
    PlaySound(soundFastUpwardTones);
    wait1Msec(2000);
}


Thanks for the response. I've loaded your version that eliminates the flash_light task and (after removing init_robot() and adding pragmas) I get exactly the same results on the NXT. The program will run for up to 30 seconds then it will break out of the StopPgm test and play the sound.

BTW, we do have a strategy selection method that uses the brick screen, the flashing light is intended for fellow team members to confirm from a distance that the driver have made an appropriate automomous selection.

Tested with V3.04/FW 9.04, Samantha disconnected from USB, one HiTechnic motor controller connected and powered up, one LEGO color sensor connected. Anyone care to repeat my test? At this stage it seems to me like a bug in RobotC.


Wed Nov 23, 2011 2:45 pm
Profile
Guru
User avatar

Joined: Sun Nov 15, 2009 5:46 am
Posts: 1347
Post Re: LEGO color sensor interferes with waitForStart()
ronmcrae wrote:
The program will run for up to 30 seconds then it will break out of the StopPgm test and play the sound.

That means somehow somebody cleared StopPgm. Ah, it must be the issue I found in this thread (viewtopic.php?f=52&t=3448&start=30). You need to put the code in joystckDriver.c inside a pair of hogCPU/releaseCPU (i.e. inside a critical section).
ronmcrae wrote:
BTW, we do have a strategy selection method that uses the brick screen, the flashing light is intended for fellow team members to confirm from a distance that the driver have made an appropriate automomous selection.

If you already have a strategy selection method, then you should be able to confirm your selection on the LCD screen without relying on the color light. In my opinion, there isn't a need to let team members from far away to confirm it. But that's just me :)


Wed Nov 23, 2011 4:05 pm
Profile
Rookie

Joined: Wed Jul 21, 2010 11:23 pm
Posts: 39
Post Re: LEGO color sensor interferes with waitForStart()
Early indications are that adding hog/release functions to joystick.c has eliminated the false starts. Seems like the changing of color on the color sensor can interrupt (and corrupt!) the buffer transfers in getjoysticksettings.

Thank you for your assistance.


Wed Nov 23, 2011 4:34 pm
Profile
Guru
User avatar

Joined: Sun Nov 15, 2009 5:46 am
Posts: 1347
Post Re: LEGO color sensor interferes with waitForStart()
RobotC folks,
Please confirm this is indeed a potential issue. We have encountered a few strange start issues during our regional competition that could have been explained by this. If that's true, the impact of this issue is bigger than I originally thought.


Wed Nov 23, 2011 4:43 pm
Profile
Guru
User avatar

Joined: Sun Nov 15, 2009 5:46 am
Posts: 1347
Post Re: LEGO color sensor interferes with waitForStart()
ronmcrae wrote:
Early indications are that adding hog/release functions to joystick.c has eliminated the false starts. Seems like the changing of color on the color sensor can interrupt (and corrupt!) the buffer transfers in getjoysticksettings.

Here is what I susepect that happened:
While the FCS is waiting for the game to start, if communication is lost temporarily (which happened many times in the game), the joystickDriver code would zero out the joystick packet. Unfortunately, one of the fields in the joystick packet is the boolean variable StopPgm. It was set to TRUE before the game starts. The FCS will clear the boolean variable to start the game and unblock the "waitForStart()" function in the robot's Autonomous program. By zeroing it, it would accidentally "start" the robots. But the code did safe-guard this scenario by saving away the state of StopPgm before zeroing the packet and then restoring the StopPgm state back to the packet after zeroing the packet. I suspect there is a race condition where after the code zero'd the packet, there was a task preemption before it had a chance to restore the StopPgm state. So the waitForStart() could accidentally sample the zero in the StopPgm field and unblock itself. The fix is to put the code that save the StopPgm state, zero the joystick packet and restore the StopPgm state all inside a "critical section".


Wed Nov 23, 2011 4:54 pm
Profile
Display posts from previous:  Sort by  
Reply to topic   [ 8 posts ] 

Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  



Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software for PTF.