Wednesday, May 27, 2015

Garden Robot Update 1

Okay...first update.
Couple mechanical pictures:

I spent quite a long time looking for a valve we had sitting around, and Mom found one in about 5 seconds.  In its former glory, this faded yellow device connected to a hose water spigot, allowing for the fill of water balloons as regulated by the yellow lever on the close side.  I used a 5:1 gear reduction and a single NXT motor to operate the valve (Yes, this is the first time ever I have glued a personal LEGO.) You can't see it in the picture, but the black hose is from a drip irrigation system I got years ago, and is currently connected to a crudely-cut water bottle and sealed with my mediocre hot-gluing skills.  The water bottle acts as the water reservoir and feeds via gravity through the valve.  By opening the valve for different amounts of time, I can adjust how much water is fed to the plant.

 Here is my current test setup.  Three containers of dirt (thankfully "science experiments" are encouraged in my house) and two nails for use as probes.  They are used in a basic "touch sensor" setup, in series with a 2.2kOhm resistor and connected to pins 1 and 2/3 of a sensor port.  More conductivity means more water present, and a lower raw  sensor value read by the NXT.



After a long, multi-day drama (see below), I'm currently at this code:

//Macros for moisture thresholds (raw probe values)
#define HIGH 500
#define MED 300

//Macros for watering times (ms)
#define HIGHWAIT 2000
#define MEDWAIT 1000

//Macros for moisture test wait time (ms)
#define TESTWAIT 5000

int MoistureLevel;

sub MoistureTest()
    {
int raw;
//Apparently the following 2 lines are necessary with updated firmware.
     SetSensorType(S1, SENSOR_TYPE_CUSTOM); //Set the sensor type.
     ResetSensor(S1); //Necessary following SetSensorType
     int data[10]; //Create a data vector with 10 elements
     for(int i=0; i<11 10="" epeat="" i="" p="" times="">             {
             raw=SensorRaw(S1); //Set "raw" variable equal to probe reading
             data[i]=raw; //Use the loop counter as index to save raw in vector
             ClearScreen(); //Don't forget this
             TextOut(0,LCD_LINE1,"Current value = ");
             NumOut(0,LCD_LINE2,raw); //Display current value
             Wait(100); //Wait 1/10 a second
             }
     MoistureLevel=ArrayMean(data,NA,NA); //Reduce noise by averaging vector
     }

sub Water(int WaterLevel)
    {
    if (WaterLevel==0) //Do nothing for an argument 0
       {
       }
    else //Open valve, wait the time given by the argument (>0) and close valve
        {
        RotateMotorEx(OUT_A,100,-470,NA,false,true);
        Wait(WaterLevel);
        RotateMotorEx(OUT_A,100,470,NA,false,true);
        }
    }


task main()
{
     while (true)
{
Wait(TESTWAIT); //Wait for a while before testing moisture level
           MoistureTest();
           PlayTone(262,400); //Play Tone to assert completion of subroutine
           ClearScreen();
           TextOut(0,LCD_LINE1,"Mean value = ");
           NumOut(0,LCD_LINE2,MoistureLevel); //Display this average value
           //This structure displays LOW, MEDIUM or HIGH on screen
           //and passes a watering time argument to the Water subroutine
           if (MoistureLevel <=MED)
       {
       TextOut(0,LCD_LINE3,"LOW");
       Water(0);
       }
           else
          {
               if (MoistureLevel >MED && MoistureLevel<=HIGH)
                  {
                  TextOut (0,LCD_LINE3,"MEDIUM");
                  Water(MEDWAIT);
                  }
               else
                   {
                   TextOut (0,LCD_LINE3,"HIGH");
                   Water(HIGHWAIT);
                   }
               }
           }
}


The NXC Drama:

  1. My first thought:" I should have upgraded to the enhanced NXC/NBC firmware ages ago.  It has support for up to 4D matrices, which is awesome." Unfortunately, it's not that easy.  
  2. Setting up BricxCC was a pain.  I didn't have the MINDSTORMS software already installed on my computer, so I needed the Fantom Drivers from this LEGO page (which they actually still host, much to my shock).
  3. But I got a weird .ini file error when running the autorun.  I found someone else with the same issue, and instead used the drivers from this page (as linked by the second post in the thread).
  4. With the drivers installed, BricxCC was able to connect to my NXT (I had some stock firmware already on it).  For a while I was stuck because an array command I was trying to use wasn't recognized.  I later figured out it was because the compiler will recognize the firmware you are using in your NXT and throw an error if you use commands intended for the enhanced firmware.  So I was off to find the enhanced firmware...
  5. I first tried to flash the firmware linked on this page onto the NXT using BricxCC's Firmware Download feature.  It worked perfectly, but when I ran my program, I kept on getting a "0" raw value back from the sensor, which couldn't be right.  I assumed it was a firmware issue, so I looked elsewhere for a different firmware.
  6. I made the mistake of getting a firmware binary from this page and attempting to use BricxCC's Firmware Download feature to flash it to my NXT...oops.  I had no idea what I was doing, and it totally failed, bringing my brick to "quiet clicking" model.  If I had read more closely, I would have been able to tell that I needed to compile it first, which I didn't.
  7. I then tried to revert back to my earlier firmware using the same feature...it didn't work at all, but BricxCC didn't throw an error.  I was perplexed, because my NXT was reduced to quiet clicking, and even though I downloaded the stock LEGO firmware, it wouldn't respond.
  8. Getting a bit worried, I booted up my old computer and started up NXT-G 1.1  Thankfully, I was able to flash the stock firmware onto my quiet clicking NXT.  After repeating the whole "firmware binary" episode a second time, I read the page and realized my mistake.
  9. This made me realize that my first firmware flash must have been correct, and the problem was in my code.  After some searching through the documentation, I eventually stumbled upon the weird reality that you must first use SetSensorType to define the sensor, and then use ResetSensor, and you can then use SensorRaw to read it as before.
  10. After some more screwing around with the firmware versions (the flash contained two different versions of the enhanced firmware, and only one worked), I settled upon using the "lms_arm_nbcnxc_132.rfw" version.
TL;DR:  Use this Fantom Driver and the "lms_arm_nbcnxc_132.rfw" file from the enhanced firmware linked on this page.  Don't use BricxCC's Firmware Download feature when restoring a clicking NXT, use NXT-G's instead.

Garden Robot

Hello World, it's been a while.
Unfortunately, real life has gotten in the way of my MINDSTORMS pursuits.  That being said, in honor of the fact that it is summer, I have decided to take a far more structured approach to a much larger project.  I won't get into it in depth here, but I essentially want to make a garden robot.  That is a bit broad.  To narrow it down, I have some specifications:

  1. Use LEGO MINDSTORMS NXT for actuation.
  2. Completely autonomous/maintenance-free for extended periods.
  3. Water plants (only, for now).
  4. Relay critical information over the internet (moisture content, PH levels, ambient light, etc.).
  5. Be completely controllable over the internet (all functions accessible).
Numbers 4 and 5, particularly considering specification 1, are apparently quite complicated.  The NXT, unlike the EV3, has no embedded WiFi capability.  Thankfully, with a bit of digging, I was able to chance upon two different projects:

The folks at MonoBrick have created a set of tools to allow for enhanced communication with the NXT and EV3.  Notably, they have developed a "tunnel" Android application that allows you to connect the phone via bluetooth to the NXT and via the internet to a client.  Using their handy C# communication library, you can develop programs to send direct commands to the NXT.  Another huge plus is the capability to stream live video from the phone's camera.  For the time being, this is my method of choice, but there are a couple drawbacks:
  1. Whatever you have running the program on (which for now is my laptop) has to be working...at all times.  Considering I'm a student, this is impractical.  Therefore, whatever code I write on this has to be in addition to the autonomous code that is running on the robot.  This isn't a bad thing, but it will require a bit of creativity to get the two different languages to work with each other seamlessly.
  2. The tunnel app, after upgrading my phone to Android 5.0.2, seems to have lost its menu.  This is an issue if I want to adjust anything, such as which NXT the bluetooth connection pairs with.
  3. I don't really understand this part, but I think that if I switch WiFi networks, I have to reconfigure the client listening port.  Not a big issue, but certainly a limitation due to my restricted programming knowledge.
Secondly, I found another project by SmartLab that does something similar - you place an Android phone on the robot, and it connects via Bluetooth to the robot and via WiFi to the internet.  But this one has a very different type of flexibility - the phone runs its own HTTP server, allowing you to access and control the machine via a webpage.  This is exciting because it removes the need to use a local program to access the robot over the internet.  But for now, this is not my method of choice for two simple reasons:
  1. It's written in Java.  I don't know Java.  At all.
  2. The program they used as an example works by sending direct commands to the NXT.  Considering I have specified that the robot to be autonomous, I will need to figure out how I can write it as a predetermined program on the phone.  I'm sure it's possible, but we are entering the realm of app development here, and I don't know anyone who develops Android apps who might be able to help me with this.
So, for the time being, while I am working out prototypes and proof-of concepts, I have decided to do as follows:
  1. Write a NXC program (this I've dabbled in before) that runs on the NXT to control autonomous function.
  2. Experiment with the MonoBrick library in VisualStudio to work out a communication method between the Windows Form application I'm planning to write (for the GUI) and the robot's data logs.
  3. See if I can work out streaming video (it works in MonoBrick's remote program...I should be able to get it to work on mine too!  Right?)
  4. For all of this, use haphazardly-designed prototypes (Okay, maybe not completely) to make sure I can actually build this thing mechanically.