Super Droid Bot "Anna" - w/ Learning AI

Cost

Thanks.  It cost probably around $700 if I had to buy all the parts new, not counting the Android Phone.  It’s going to be a lot more once i fit out the head with all the sensors.  Hoping to get a Thermal Array (thermal vision) onto it in the next month or so.  An XBee radios will be going on too with the antenna out the back.

i remember VFH algorithm but

i remember VFH algorithm but never know how to implement it… are you making it for military?it is looking awesome … it will be very nice if you tell how you did all this…

 

Re: VFH algorithm

Thanks for the feedback.  Having a lot of fun building it, not for military…personal fun!

I’ll give you the high level ideas to how I did it, there are many ways to do it.

By experimentation, I discovered that sonar signals bounce off walls at relatively small angles to the perpendicular of an oncoming wall.  I settled on having sonars every 30 degrees around 3 sides of the bot…4 sides would be better for force field but time to cycle through all sonars slows down with more sensors.  Even at 30 degrees, the bot can still run into objects at particular angles and shapes that bounce sound away from bot (like wedges).  Still, nothing is perfect, and 30 degrees would still fit on my bot using cheap SRF04’s for about $5 a piece.  I originally wanted to use Maxbotix sensors at $55 but since I didn’t know if the whole idea was going to work well, I decided to try it on the cheap sensors first.

Next, I started with the NewPing library.  There is a 15 sensor version that allows you to run a bunch of sonars without delays…crucial for this situation.  To use this lib, you supply code for the oneSensorCycle function.  Basically, I cycle through the readings and hand the values over to my force service, then call the force service to do some processing, then the obstacle service.

void oneSensorCycle() 

    for (int i = 0; i < SONAR_NUM; i++) 

    {     

        UpdateForceDistance(i+1, distance[i]);

    }   

    ForceService();  

    ObstacleService();

    if(_SonarArrayOutputSwitch)

    {

      for (int i = 0; i < SONAR_NUM; i++) 

      {     

        Serial.print(i+1);

        Serial.print("=");

        Serial.print(distance[i]);

        Serial.print("in ");

      }

      Serial.println();

    }  

}

Next the Force Service.  This service is called one time for every cycle of the sonars.  Kind of dangerous if you are driving in close proximity at any significant speed.  Each vector is configured in the SetupForce function.   In my case, one attractive force (the goal of where I want to go), and 9 repulsive forces, one for each sonar.  I kept the force code separate from the sonar code intentionally so I could add behaviors later like “move towards light”, “move towards other bots”, “move towards high ground”.  The idea being, I might want to add attractive or repulsive forces in the future that were not sonar related.  I also setup the ability to modify the direction of a force.  This is because as the robot moves around, the direction of its goal will change rapidly relative to the bot.  Some code somewhere will need to update this heading regularly.  Here’s the code…yes I realize I could rewrite this with one struct array and I plan to…I only just got this working a week ago…this if proof of concept stuff.

// On Off Switch for Service

boolean _ForceServiceSwitch = false;

 

//Output Switch for Service

boolean _ForceOutputSwitch = false;

 

//Constants

const int NUM_FORCES = 10;  //Number of forces in array

const int DISTANCE_THRESHOLD = 3;  //Only readings above this value will be considered, all readings below will be ignored.

const int DISTANCE_FLOOR = 5;  //All readings < this value will be set to this value

const int DISTANCE_CEILING = 36;  //All readings above this amount will be considered to be same as DISTANCE_MAX and exert zero force.

const int DISTANCE_MAX = 255;  //Do not change this value;

const long DEFAULT_ATTRACTIVE_FORCE_MAG = 100000;

const long DEFAULT_REPULSIVE_FORCE_MAG = -100000;

const long DEFAULT_REPULSIVE_FORCE_MAG2 = -50000;

const long DEFAULT_ATTRACTIVE_FORCE_DISTANCE = 14;

 

//Force Distance

int _ForceDistance[NUM_FORCES];

 

//Force Angles in Radians

int _ForceAngleDegrees[NUM_FORCES];

double _ForceAngleRadians[NUM_FORCES];

 

//Force X and Y Adjustment Factors

double _ForceAdjX[NUM_FORCES];

double _ForceAdjY[NUM_FORCES];

 

//Force Factors

int _Force[NUM_FORCES];

 

//Force Factor X and Y Components

int _ForceX[NUM_FORCES];

int _ForceY[NUM_FORCES];

 

//Force Switches - To Turn Each Force On or Off

boolean _ForceSwitch[NUM_FORCES];

 

int _ForceXSum = 0;

int _ForceYSum = 0;

 

//Force Magnitude, Positive for Attractive, Negative for Repulsive

long _ForceMagnitude[NUM_FORCES];

 

double _NetForceRadians;

int _NetForceDegrees;

int _NetForceMagnitude;

 

void SetupForce(boolean pIsServiceOn, boolean pShowOutput) 

{   

    _ForceServiceSwitch =  pIsServiceOn;

    _ForceOutputSwitch = pShowOutput;

 

    //Configure Attractive Forces - Angle will be updated later by compass or drive module in main loop

    ConfigureForce(0, ON, 0, DEFAULT_ATTRACTIVE_FORCE_MAG, DEFAULT_ATTRACTIVE_FORCE_DISTANCE);

 

    //Configure Repulsive Forces - Distances will be updated later by sonar module in main loop

    ConfigureForce(1, ON, 0, DEFAULT_REPULSIVE_FORCE_MAG, DISTANCE_MAX);

    ConfigureForce(2, ON, -30, DEFAULT_REPULSIVE_FORCE_MAG, DISTANCE_MAX);

    ConfigureForce(3, ON, 30, DEFAULT_REPULSIVE_FORCE_MAG, DISTANCE_MAX);

    ConfigureForce(4, ON, -60, DEFAULT_REPULSIVE_FORCE_MAG2, DISTANCE_MAX);

    ConfigureForce(5, ON, 60, DEFAULT_REPULSIVE_FORCE_MAG2, DISTANCE_MAX);

    ConfigureForce(6, ON, -90, DEFAULT_REPULSIVE_FORCE_MAG2, DISTANCE_MAX);

    ConfigureForce(7, ON, 90, DEFAULT_REPULSIVE_FORCE_MAG2, DISTANCE_MAX); 

    ConfigureForce(8, ON, -120, DEFAULT_REPULSIVE_FORCE_MAG2, DISTANCE_MAX); 

    ConfigureForce(9, ON, 120, DEFAULT_REPULSIVE_FORCE_MAG2, DISTANCE_MAX); 

 

}

 

void ForceService()

{

    if(_ForceServiceSwitch)

    {       

        CalculateNetForce(); 

 

        if(_ForceOutputSwitch)

        {

            ShowForceOutput();

        }

    }

    else

    {

        setForceHeading(-1);

    }

}

 

 

void SwitchForce(int pForceNumber, boolean pOnOffSwitch)

{

    _ForceSwitch[pForceNumber] = pOnOffSwitch;

}

 

void ConfigureForce(int pForceNumber, boolean pOnOffSwitch, signed int pForceAngle, signed long pForceMagnitude, int pDistance)

{

    _ForceSwitch[pForceNumber] = pOnOffSwitch;

    _ForceAngleDegrees[pForceNumber] = pForceAngle;

    _ForceAngleRadians[pForceNumber] = getRadiansFromDegrees(pForceAngle);

    _ForceAdjX[pForceNumber] = sin(_ForceAngleRadians[pForceNumber]);

    _ForceAdjY[pForceNumber] = cos(_ForceAngleRadians[pForceNumber]);   

    _ForceMagnitude[pForceNumber] = pForceMagnitude;

    UpdateForceDistance(pForceNumber, pDistance);

}

 

void UpdateForceDistance(int pForceNumber, int pForceDistance)

{

    //Serial.println(“Force Updated.”);

 

    //Only Look at readings that are over threshold

    if(pForceDistance > DISTANCE_THRESHOLD)

    {

        if(pForceDistance < DISTANCE_FLOOR)

        {

            _ForceDistance[pForceNumber] = DISTANCE_FLOOR;

        } 

        else if(pForceDistance > DISTANCE_CEILING)

        {

            _ForceDistance[pForceNumber] = DISTANCE_MAX;

        } 

        else

        {

            _ForceDistance[pForceNumber] = pForceDistance;

        }

 

        //Calculate Force

        _Force[pForceNumber] = _ForceMagnitude[pForceNumber] / (pow(_ForceDistance[pForceNumber], 2));

 

        //Calculate X and Y components of force 

        _ForceX[pForceNumber] = (int)(_Force[pForceNumber] * _ForceAdjX[pForceNumber]);

        _ForceY[pForceNumber] = (int)(_Force[pForceNumber] * _ForceAdjY[pForceNumber]);

 

    }

}

 

void UpdateForceAngle(int pForceNumber, int pForceAngle)

{

    _ForceAngleDegrees[pForceNumber] = pForceAngle;

    _ForceAngleRadians[pForceNumber] = getRadiansFromDegrees(pForceAngle);

    _ForceAdjX[pForceNumber] = sin(_ForceAngleRadians[pForceNumber]);

    _ForceAdjY[pForceNumber] = cos(_ForceAngleRadians[pForceNumber]);  

 

    if(_ForceOutputSwitch)

    {

        Serial.print("ForceNum: “);

        Serial.print((int)pForceNumber);

        Serial.print(” Updated Angle: ");

        Serial.println((int)_ForceAngleDegrees[pForceNumber]);

    } 

}

 

double getRadiansFromDegrees(int pDegrees)

{

    return (double)(pDegrees * 0.0174532925);

}

 

int getDegreesFromRadians(float pRadians)

{

    return (int)(pRadians * 57.2957795);

}

 

int getNetForceDiff()

{

    return _NetForceDegrees;

}

 

void CalculateNetForce()

{

    _ForceXSum = 0;

    _ForceYSum = 0;

 

    for(int MyForceNum = 0; MyForceNum < NUM_FORCES; MyForceNum++)

    {

        if(_ForceSwitch[MyForceNum])

        {

            _ForceXSum = _ForceXSum + _ForceX[MyForceNum];

            _ForceYSum = _ForceYSum + _ForceY[MyForceNum];

        }

    }

 

    _NetForceRadians = atan2(_ForceXSum, _ForceYSum);    

    _NetForceDegrees = getDegreesFromRadians(_NetForceRadians);

    _NetForceMagnitude = sqrt(pow(_ForceXSum,2) + pow(_ForceYSum,2));

 

    //Update Force Heading with Heading Service

    setForceHeading(getNewHeading(getHeading(), _NetForceDegrees));       

 

}

 

The next service is key to make this work…the ObstacleService.  The problem is, sonar readings are unreliable.  You get crazy readings that are small, or crazy large when an object is actually close.  You need filters.  What I did was count the number of times in a row that a value in each vector (each sonar) was below 3 different ranges.  If it ever got to 3, I considered the ruing to be broken.  Imagine the bot has 3 rings of defense around it, lets say at 18in, 12in, and 6in.  Although for me, they are ovals and not circular, I am more concerned with obstacles in front than to the sides.  I didn’t include source for the obstacle service but I might when I feel a little better about it.  But below is the basic ideas.

The idea is:

1.  If no rings are broken, drive to where you want to drive.

2.  Start making steering adjustments according to the ForceService if the first ring is broken, and start slowing down to buy more time for sonar cycles.

3.  Slow down further if 2nd ring is broken, allow for sharper steering adjustments.

4.  Stop if the innermost ring is broken and take some evasive action, back up, run a contingency mission, whatever.

My ObstacleService tells my ThrottleService what the MaxSpeed should be and what the heading should be, and the ThrottleService takes care of how much juice to send to each motor based on the difference between actual heading and desired heading.

Hope this helps.  

nice job …keep

nice job …keep proceeding…

Awesome!

Your robot looks ready for a quest for world domination, but it still needs the laser cannon. :smiley:

Awesome!

Your robot looks ready for a quest for world domination, but it still needs the laser cannon. :smiley:

Laser Cannon coming…but first its gotta See something!

Thanks.  Funny you should mention laser cannon…I found a site that makes cheap lasers that put out particular patterns with the lasers…circle, crosshairs, etc.  Thinking about picking one up.  I’m planning on having a set of sensors accross the top, and a couple of rails on the sides of the head (think ears) to which interchangable modules can be attached that need pan/tilt.

Before that can be useful though, vision is needed.  I spent the evening getting BlobTracking going with OpenCV4Android, which I’m only just learning.  I have a proto of the OpenCV part working for finding the blobs, their location, size, bounding rect, etc.  Next I need to integrate the proto into my existing bot code to get the servos tracking against the most promising blobs.

I did some experiments using a laser and open cv on the droid phone…it can see and track a laser point in the same room…not sure if that is useful since the bot can simply center a blob of interest in its field of view…unless I wanted to use a laser to tell the bot what objects/colors to take an interest in…hmmmm…sounds like world domination.   Ha ha ha ha ha!

Very cool. That black is

Very cool.  That black is highly menacing.  Concur with person who says it needs a laser cannon.

I imagine a lot of work getting all the pieces to work so happily together.  Keep it coming! 

Regards,

Bill

Very cool. That black is

Very cool.  That black is highly menacing.  Concur with person who says it needs a laser cannon.

I imagine a lot of work getting all the pieces to work so happily together.  Keep it coming! 

Regards,

Bill

Re: Laser Cannon

Hey Bill,

Thanks for the input and ideas.  I added the laser cannon you suggested!  Had to get OpenCV going first so she could find something to aim at.  Lately I’ve been working on getting a moving face, eyes, mouth, pupils, lids, lately.  I think its cool stuff.  You are right, the integration was hell for a while, especially when you are scanning video frames where the location of a target in the frame is kicking off servo adjustments in near real time.  Small time delays in OpenCV or the USB bus can cause a whole lotta issues.  Servos don’t move instantly, so I have to slow down the adjustment rate when the servos are moving a lot.  That’s why she’s a little jumpy at very close range where the servo movements are larger. Anyway, probably way more info than anyone cares to hear!

Regards,

Martin

Woo hoo!

Martin,

I am going to be giggling like a school girl for weeks!  This thing is awesome. I love the expressions and how it responds to movement.  But the laser cannon just brings me joy.

 I think your screen idea is a great way to interact with people.  I was thinking of doing something similar with a Raspberry Pi.  Great work on this!

Regards,

 

Bill

Re: Woo hoo!

Thanks, this is largely a solitary joy…so I appreciate someone getting a kick outta it!

If you liked that one, I just uploaded one that is 3 times better!

I’ve been working for a day and a half straight to get the thing to assemble and prioritize an entire list of targets, right now prioritized by area, but I have it stubbed out for left-to-right, right-to-left, etc.

It just started working an hour ago, the aim is not perfected (still some challenges with aiming from a single image frame rather than converging and tracking as I do in single shot mode)

Anna is getting a bit frightening to set loose when she’s in full-auto mode.

Anyway, hope you enjoy!

very well impressive, clean,

very well impressive, clean, smart, monumental, intelligent work

you are my master robot conceptor, I am your little jedi until I can show my robot like you do your.

 

In french:  tres joli.

Thanks, but not so fast…

Thanks for the comments, sincerely.  I’m really more of a software guy, new to the construction side, finding my way.  Because of that, I used a lot of off the shelf components from LynxMotion and Radio Shack, built the sonar housings myself though.  I like the chassis you are working on for your patrol bot, wish I thought I was ready to scratch build a chassis.  I started out with the same mission in mind…patrolling a route by GPS and taking pictures of animals.  Not really sure what I want the mission to be anymore.  Working on indoor localization lately, hoping to add thermal vision next.  I’ve been doing a lot of thinking lately on how to build a personality simulator and how this might make building richer autonomous behavior easier.  Still in envisioning stage on that though.  I have high hopes.  Good luck on yours!

Thanks again.  

Regards,  Martin.

man you should put this on kickstarter. SERIOUSLY.

SERIOUSLY

Thanks for the Kickstarter Suggestion

Thanks for the Kickstarter Suggestion.  I wasn’t familiar with them, not really looking for funding.  For me, these projects are funded with time, not money.  I’ll give it some thought.  Here are a couple of ideas I was toying with.

The first is to open up the server (the language, logic, learned knowledge, and web services) to interested individuals in the hobby community to use as a web service using API keys.  I would open source the android and arduino code to kickstart it.  The idea would be motivated by my desire to increase the use of Android phone / microcontroller combo robots with learning abilities.  I’d like to see more hobbyists able to spend more time on higher level behaviors, and I’d get help making the brains smarter over time.

Second, I see a need and benefit for average people to have an AI like this running on their personal devices.  My wife wants it already…basically it would be a Siri but with a more in depth memory of you and the people in your life, and trainable to learn whatever topics you are into.  Could also be an app for people with alzheimer’s…“What are my grandkids names again?”  I am looking for a name, I have been calling the concept “Personalized AI”.

Sadly, I fear google is going to leave all our little projects in the dust shortly.  It will be great for humanity, but it will mean my hobby won’t feel so cool anymore when I can buy something from amazon for a few hundred that is way better and smarter than I can create.

Thanks again.  Regards, Martin

I am very curious to know

I am very curious to know how everything work together, can you publish a basic plan of your system, also what brand and model devices did you use ? ?

Sorry I left that out

Sorry I left that out, I had all of it in a powerpoint preso and my licence expired on me!  I hate when that happens.  I’ll try to post something when I draw up a replacement.

Anna as J.A.R.V.I.S. ?

Home automation enthusiasts would be very pleased with a disembodied Anna controlling the lights and sprinkler system.

Anna as a chatbot/personal assistant is worth releasing on her own. Brilliant work.

I have been thinking about that

Thanks.  have been thinking about home automation recently, want to get a new hub for home, but can’t decide which one will have the most open APIs, my TV will take IP commands, so I thought I might start with that…“Turn on the game Anna.”…eerily similar to “Open the pod bay doors Hal”.

Its kinda funny, it was an interest in home automation that got me to go the local Radio Shack a little over a year ago, whereby I saw these things called “Arduinos”  that I had never heard of and “Microcontrollers”, which I had heard of but never used.  I made an impulse buy and my life has been different ever since.