Carl Has Multiple Personality Disorder

I should have expected Carl to be confused when I started telling him “Marvin Be Quiet”, and “Marvin You Can Talk Now”. (The Nyumaya hotword engine only recognizes “Marvin”, “Sheila”, “Firefox”, or “Alexa” so I chose “Marvin” until the “Hey Carl” model arrives.)

Turns out Carl has full fledged Multiple Personality Disorder.

First came the issue of backing onto the dock with the drive_cm() method not returning. Several times I found Carl on his dock, but he was totally unresponsive. It turned out I needed a drive_cm() with a timeout. I created a custom my_easygopigo3.drive_cm(distance, timeout=60) that would always return even if the last encoder tic of backing onto the doc was blocked.

Carl’s life would have been fine if I had not wanted to add an Inertial Measurement Unit to him. For that I had to create a thread safe my_safe_inertial_measurement_unit.py and my_inertial_management_unit.py package.

And since the IMU maintains state I also needed to create a “no initialization” feature so that a second process could read the IMU without re-initializing it out from under the first process’s configuration.

Next came wanting to leave the battery and docking management process running 24/7, but be able to run other processes during Carl’s playtime. Well Carl likes his speed to be a constant 150 degrees per second where his 180 degree turns are most accurate, but when a second process initializes its EasyGoPiGo3 object, the speed gets reset back to 300 DPS, even if that process only plans to check the battery voltage and quit.

The answer was to create a special noinit_easygopigo3.py and noinit_gopigo3.py with the option noinit=True in the EasyGoPiGo3 and GoPiGo3 class initializations, just like I had done for the IMU.

And finally while testing my Braitenberg Vehicles with the EasyPiCamSensor class I created, I discovered that the easygopigo3.EasyGoPiGo3().steer(left_percent, right_percent) had a defect, so I created another easygopigo3.py with only that change.

Today when I was working on my voice command program and wanted to change the eyes color to indicate that Carl was waiting for the “Marvin” hotword (light blue), or waiting for a voice command (bright blue), or didn’t understand the command (light red), or actually did understand (light green), I needed to choose one of the four easygopigo3 versions:

  1. Dexter/ModRobotics official easygopigo3
  2. my_easygopigo3 - with drive_cm timeout
  3. noinit_easygopigo3 - with noinit=True feature
  4. Projects/EasyPiCamSensor/easygopigo3 - with fixed steer function
     

The best choice was noinit_easygopigo3 so the voice commander would not reset Carl’s docking speed setting, and that is how I coded it.

Of course, after I got it recognizing the “Marvin” hotword, recognizing some voice commands, and showing the pretty colors, I wanted to make the voice commands actually do some Carl functions. Oops, the “easygopigo3” init_servo() method is objecting with “TypeError: Us a GoPiGo3 object for the gpg parameter” in easysensors.py

Carl is confused. I’m confused. This was supposed to be “Easy(GoPiGo3)”.

And Carl needs a therapist for his multiple personality disorder!

3 Likes

Wow - quite the project.

2 Likes

Cognitive therapy.

Have you considered making one special class and instantiating it into the special versions you need?  Or even overloading the gopigo or easygopigo classes with the changes you need so there’s NO special classes at all?

Or, am I missing something?

1 Like

If I actually knew Python coding styles, I might have more “tools” to manage complexity.

All of my programs and even my “common modules” are the product of a hundred separate investigations of GoPiGo functionality. When I try to combine two of these, the common module changes breaking one or both. Then I add a third user, and change the common module, and break the first two again. Just imagine what ModRobotics has to do for “I just changed one line”, and there I am. I have two years of singletons that I need to combine to make “a whole robot”.

Who would have thought I would need a regression test suite for a personal robot?

2 Likes

And this is just the start. Once I get all the robot functions available at the same time, Ihave to find a dialog engine and a knowledge base and a knowledge query engine and, and, and…

2 Likes

“Ahh feel yer pain!”

All I wanted to do was factor out a lot of common code from the various modules I’m writing and testing for my remote control robot project. . .

And as soon as I did that, everything fell apart into a quivering lump of GAGH!

Sigh. . . .

1 Like

Did you ever look at the “Run My Robot” code? It is a group of people that unleash their robot for other “members” to remote control their robot. - video, rocket launchers, interesting stuff.

2 Likes

It is interesting, but I’m not sure I’m ready for Charlie to go public just yet.

1 Like

Understand. I’m not ready to invite the public into Carl, as well.

1 Like

 
. . . . and let some blithering idiot drive him into a tree!  :grimacing:   :cold_sweat:

No thank you!  Next contestant please!

1 Like

I totally understand that and I have run into the same issues where I have a dozen or so different things that do different things and every time I do something I end up re-inventing the wheel.

Maybe this is a hint that it’s time to set the experiments aside and begin refactoring the code you already have?  It’ll be a pain at first, but then you have everything packaged up nice and tidy into something that’s more easily debugged because you have only one of them.

Note:
I’ve begun doing the same thing with my experimental code because I end up using the same set of functions and constants in all my code slices that I create to experiment with a particular characteristic - and they all end up out-of-sync because I tweak something here and forget to migrate it there.  Then I go crazy scratching my head because THIS instance of a particular test behaves differently than THAT instance of a similar test.

This seems to be the perfect opportunity for a class or two that create generalized abstractions for the functionality you need.

  • You need this specific functionality.

  • You need this specific functionality that’s thread safe.

  • You need this specific functionality that’s guaranteed to return with a variable timeout.

  • You need this specific functionality that’s both thread safe AND is guaranteed to return.

  • And so on.
     

Maybe I’m wrong, but this seems to be begging for a class that can be instantiated and, if necessary, overloaded.

Then again, I’m not you, nor am I Carl, and I’m not exactly the expert on classes and when to use them.