Shop OBEX P1 Docs P2 Docs Learn Events
My ActivityBot — Parallax Forums

My ActivityBot

RsadeikaRsadeika Posts: 3,837
edited 2013-11-08 13:05 in Learn with BlocklyProp
I just recently received an ActivityBot, nice little kit. Also, "Good job" for the Learn Team. I put the kit together to the basic build point, no extras like the whiskers were added. I followed the Learn setup guide to calibrate the servos and such, plus I looked into their explanation for preliminary navigation, very good job. So far everything is working as expected.

Some general random thoughts, probably the next addition to the ActivityBot will probably be the XBee module. The cord puts some limits on functionality for the bot, but then you would need some kind of interactive program, with some scripting capability. Since I am temporarily using the included battery pack, that will probably to be changed to the Li-ion pack, but the problem with that is you have no way of knowing when your pack needs to be re-charged. I keep bringing that point up every time I get chance.

Below are a couple of very basic programs, for maybe a beginner, to do some basic turns. Try running them and see what the difference is, if any.

Ray

/*
  turns1.c
 
*/
#include "simpletools.h"
#include "abdrive.h"

int main()
{

  // Left turn 90 deg
  //          LW RW
  drive_goto(-26,25);
  pause(1000);
  // Home position
  drive_goto(51,0);
  pause(1000);
  // Right turn 90 deg
  drive_goto(26,-25);
  pause(1000);
  // Home position
  drive_goto(-51,0);

}
/*
  turns2.c
 
*/
#include "simpletools.h" 
#include "abdrive.h"

int main()
{

  // Left turn 90 deg
  //          LW RW
  drive_goto(-26,25);
  pause(1000);
  // Home position
  drive_goto(26,-25);
  pause(1000);
  // Right turn 90 deg
  drive_goto(26,-25);
  pause(1000);
  // Home position
  drive_goto(-26,25);
 
}

«13

Comments

  • RsadeikaRsadeika Posts: 3,837
    edited 2013-09-09 07:05
    I have been thinking about how to best 'cut the cord' with the ActivityBot, and now I am thinking about using an IR Remote set up. The ActivityBot kit comes with some IR detectors, and I have a Parallax Remote control, with Sony capability. This might be a more reasonable approach at this time, rather then adding the XBee setup, that could be added at a later date. There are a couple of items that I could not find on the Learn site, or any of the example folders that are associated with SimpleIDE, and that is, the C driver(s) needed to access the IR detector and IR remote.

    I just tried to do a spin2cpp conversion of the Tom Doyle IR_RemoteTest.spin program with no success. Going this route will probably take some time because it will need a complete rewrite in Spin, and then a functional conversion using spin2cpp. Maybe the Learn team has that C code already, so I am bringing it up here.

    My thoughts on the IR remote set up is, probably a lot of the beginners have access to a remote control, and they could probably write a fairly simple program to use that setup. At least this way they can drive the ActivityBot around the room, or wherever they are located after they do the initial setup of the bot. Since the Activity board has a uSD, maybe an improvement to the program could be a way of loading some coded bot programs from the SD card, and have that run when selected via the remote control. Going this route you would probably have to create a bare minimum ActivityBot Programming Language (ABPL).

    Ray
  • Ken GraceyKen Gracey Posts: 7,389
    edited 2013-09-09 10:24
    Ray,

    Maybe consider how you could use Phil's wireless XBee programming example with an ActivityBot, as the Activity Board design should support the necessary wiring. Using it with a Spin/ASM file is probably quite straight forward, but we will need to do some tool work to support it with the C compiler. I'll be sure that this improvement is on our internal planning agenda for the near future.

    Andy has used the Simple IDE debug window with an XBee VCP on USB. This allows debug data to come back to the PC and should also be able to be used for wireless control through the debug window.

    Ken Gracey
  • jazzedjazzed Posts: 11,803
    edited 2013-09-09 11:40
    I suppose anything can be made easier. I have a bot with XBee and a WiFi CAM. My grandson and I drive it around the house for fun.

    Some of you may remember Turtle graphics. That should be an easy control concept for a bot with no obstacles. Automatically overcoming obstacles would be interesting.
  • RsadeikaRsadeika Posts: 3,837
    edited 2013-09-09 14:09
    I did a spin2cpp conversion of the Tom Doyle IR_RemoteTest.spin program, after rewriting the original slightly, and it seems to be working, at least it is responding to a key press on the remote control. The problem that I am having is a jerky and sluggish response to the 'ch+' key.
      else if (Lcode == Chup) 
      {
        drive_goto(3,3);
      }
    
    I like the idea of holding the key down and having the bot move, but it needs some improvement in the speed area. I was going to try using the 'ch+' key to start the servos up, and they keep turning until I hit a key too stop them, but I did not see any commands in the abdrive lib for doing that. Will that be added, or is there something else that is in the works?

    After looking at the spin2cpp conversion code, it looks like it could be quite a task to rewrite it to something that I think that I would need for an expanded functional program for manipulating the ActivityBot. Since the program starts up at least two cogs, that I know of, it will be difficult to figure out how to start up other cogs when necessary. But I guess it is better than nothing.

    Ray

    Ray
  • RsadeikaRsadeika Posts: 3,837
    edited 2013-09-11 05:09
    Below I started a base program for the control and operation of my ActivityBot. The question is about the print() command, below in the cog function(s)
      print("IR remote\n");
      print("XB remote\n");
    
    are not appearing on the terminal screen at start up. What would be the proper way of having this appear on the terminal screen?

    Ray

    /*
     * abpl.c
     *
     * The ActivityBot program.
     * 
    */
    #include "simpletools.h"
    #include "abdrive.h"
    
    
    unsigned int IRstack[(160 + (50 * 4)) / 4];
    unsigned int XBstack[(160 + (50 * 4)) / 4];
    
    // Function prototype
    void IR_remote(void *par);
    void XB_remote(void *par);
    
    volatile unsigned int pin;
    
    int main()
    {
      // Add startup code here.
    
      pause(300);
      print("The ActivityBot\r");
    
      int cog = cogstart(&IR_remote, NULL, IRstack, sizeof(IRstack));
      pause(500);
      int cog1 = cogstart(&XB_remote, NULL, XBstack, sizeof(XBstack));
      pause(500);
     
      while(1)
      {
        pause(400);    
      }  
    }
    
    /* IR remote control */
    void IR_remote(void *par)
    {
      pause(1000);
      print("IR remote\n");
    
      while(1)
      {
        high(26);
        pause(300);
        low(26);
        pause(300);
      
      }
    }
    
    /* XB remote control */
    void XB_remote(void *par)
    {
      pause(1000);
      print("XB remote\n");
    
      while(1)
      {
        high(27);
        pause(500);
        low(27);
        pause(500);
      }
    }
    
    
  • tdlivingstdlivings Posts: 437
    edited 2013-09-11 09:02
    Ray
    Each Cog has it's own data direction registers DIRA so the serial code print is using was set up in
    Cog0 the main cog. My guess is print cannot control the tx pin in different Cogs.
    Why not have each new Cog set a flag var indicating it is running and print that fact in the main line code


    tom
  • RsadeikaRsadeika Posts: 3,837
    edited 2013-09-11 10:07
    I started out trying to make sure that the cogs were running, hence the use of print(). When I was not getting anything on the screen, I went with the blinking LED solution. IIRC, from previous experiments that I have done, each cog other than cog0, will have to have its own serial (Rx/Tx) init routine. This approach seems like it will have a lot of extra repetitive code in the program. As I start to add some of the IR_remote code that was converted with spin2cpp, I want to use the local terminal as a debug screen, while I work out the bugs with the program. As the program gets broader in scope, and I add the XBee component, then part of that session will have to contain some IR feed back.

    Ray
  • jazzedjazzed Posts: 11,803
    edited 2013-09-11 11:03
    Hi.

    For printing between cogs it will be necessary to lock the stream. For N ports, a lock would not be necessary, and would limit number of ports ability if it was added to libserial by default. The libfdserial code might benefit from a lock. I'm not sure if the standard printf provided by GCC locks the port or not.

    If people look at libsimpletext.c (the test code for the library), they will find the different ways to use the simpletext library.

    https://code.google.com/p/propsideworkspace/source/browse/Learn/Simple Libraries/Text Devices/libsimpletext/libsimpletext.c

    The code at about line 110 shows how to close and reopen the simpletext console device.
    {
      serial *text; // new serial port text pointer.
      char buffer[80]; // arbitray size that should never be exceeded.
    
      /* Close default console. Not necessary for a new port. */
      simpleterm_close();
    
      /* restart device */
      text = serial_open(31,30,0,115200);
      writeStr(text, "SimpleSerial Started.\n");
    
      /* traditional hello message using buffer printf. */
      sprint(buffer, "Hello, world! Again!\n");
      writeStr(text, buffer);
    }
    
    


    The same idea can be applied to opening a new serial port or N ports on other pins.Currently fdserial can only open a port per COG, so it is limited to about 7 ports. The simple serial port can have as many ports as there are pin pairs (without locking).
  • RsadeikaRsadeika Posts: 3,837
    edited 2013-09-11 13:02
    I had mentioned that I did a spin2cpp conversion of the IR_Remote program. In the zip file below is the project, I do not know if the Project zip command got fixed for the latest version of SimpleIDE.

    The program works kind of weird, it looks like it is buffering the keypress of the remote control, I think. I looked at the code and cannot find the commands that need to be corrected. I am using the old Parallax black remote control, I have the IR on p2. The IR driver code is in the IR_Remote.c, if somebody wants to look at it to see if they can spot the problem, it would be a big help.

    Ray
  • jazzedjazzed Posts: 11,803
    edited 2013-09-11 14:35
    Rsadeika wrote: »
    In the zip file below is the project, I do not know if the Project zip command got fixed for the latest version of SimpleIDE.

    It works for most of us. Can we do a hangout so you can demo to me? Maybe on the weekend?
  • RsadeikaRsadeika Posts: 3,837
    edited 2013-09-12 03:56
    In this latest program I missed the 'Auto repeat' code that was in the IR_Remote driver:
    //  DIRA &= ~(1<<Pin);
    //  Index = 0;
    //  do {
    //    if (((INA >> Pin) & 0x1) == 1) {
    //      (Index++);
    //    } else {
    //      Index = 0;
    //    }
    //  } while (Index < Gapmin);
    
    After removing that section of code, the program still does not run as to be expected. It seems like the signal from the remote is not being translated correctly. In the Spin version of this program, it ran as expected, but in this spin2cpp converted version, something is definitely not working correctly. Not sure where the problem is occurring in the converted code.

    Ray
  • RsadeikaRsadeika Posts: 3,837
    edited 2013-09-13 05:48
    I temporarily gave up on the IR_Remote program, need a lot of time and patience to figure out how spin2cpp changed the code. For the C experts it probably is no problem, but for me ...

    I moved on to adding the ping))), again the Learn tutorial is very helpful for doing this. I did find a problem with the instructions in the Learn 'Try this - roaming with ping)))'. In the program example it is missing:
    int turn;
    
    and drive_setRampSte p(10) should be:
    drive_RampStep(10);
    

    Ray
  • Steph LindsaySteph Lindsay Posts: 767
    edited 2013-09-13 08:25
    Rsadeika wrote: »
    I temporarily gave up on the IR_Remote program, need a lot of time and patience to figure out how spin2cpp changed the code. For the C experts it probably is no problem, but for me ...

    I moved on to adding the ping))), again the Learn tutorial is very helpful for doing this. I did find a problem with the instructions in the Learn 'Try this - roaming with ping)))'. In the program example it is missing:
    int turn;
    
    and drive_setRampSte p(10) should be:
    drive_RampStep(10);
    

    Ray


    Ah, I see the extra-spaces typo in the screencapture, thanks Ray, I'll fix it now. The screencap only shows the modified main (we usually don't give away the whole solution to the "Try This" sections, just show the changed area) but in this case I'll also add the int turn line.
  • RsadeikaRsadeika Posts: 3,837
    edited 2013-09-13 14:33
    After testing out some of the different devices like the ping))), I decided to replace the battery pack with the Boe-bot Li-ion pack, I had forgotten what a PIA that is to get the thing in. I ended up just slipping the pack in without the spacers or the screws and nuts. This pack definitely needs a re-design, there has to be a much easier way to get the pack in, and have it secured. Hopefully the pack will stay in place, and will not get shorted out.

    Ray
  • dgatelydgately Posts: 1,630
    edited 2013-09-13 14:53
    Rsadeika wrote: »
    After testing out some of the different devices like the ping))), I decided to replace the battery pack with the Boe-bot Li-ion pack, I had forgotten what a PIA that is to get the thing in. I ended up just slipping the pack in without the spacers or the screws and nuts. This pack definitely needs a re-design, there has to be a much easier way to get the pack in, and have it secured. Hopefully the pack will stay in place, and will not get shorted out.

    Ray

    It's definitely a tight squeeze, but I got the Li-on pack to fit and use the same screws and spacers as my PropBOE Bot. Just needs a little space where the corners of the battery circuit board touches the server mounts. A little wedging took place and one corner of the circuit board just started to bend a little as I tightened the screw. I made sure not to tighten the screw too much to avoid breaking the board.

    photo.JPG


    dgately
    640 x 480 - 144K
  • edited 2013-09-14 21:03
    Hi Ray,

    Here's an ActivityBot SONY remote app.

    http://forums.parallax.com/showthread.php/150260-ActivityBot-with-SONY-Remote

    Hopefully it'll be a little less cumbersome to work with than the ported Spin object. The library is still preliminary. Please let me know if there's anything I can do to improve it, make it more useful, etc.

    Thanks, Andy
  • edited 2013-09-15 10:13
    Hi again Ray,

    Making one process the clearinghouse for other cog variable tends to make the coding a lot simpler because you can avoid stopping and restarting the serial terminal process in every cog. Here is an example where main is displaying shared variable activity within two other processes.

    Andy
    /* 
      Info from two cogs.c 
    */
    
    #include "simpletools.h"                      // Include simpletools
    
    void process_a(void *par);                    // Forward declarations
    void process_b(void *par);
    
    int stackA[40 + 36];                          // Cog stacks
    int stackB[40 + 36];
    
    volatile int sharedA, sharedB;                // Shared variables
    
    int main()                                    // Main function
    {
    
      // Launch processes into cogs
      int cogA = cogstart(&process_a, NULL, stackA, sizeof(stackA));
      int cogB = cogstart(&process_b, NULL, stackB, sizeof(stackB));
     
      while(1)                                    // Monitor sharedA, sharedB
      {
        pause(2000);
        print("process_a sharedA = %d\n", sharedA);
        print("process_b sahredB = %d\n\n", sharedB);    
      }  
    }
    
    void process_a(void *par)                     // Process A
    {
      low(26);     
      while(1)
      {
        toggle(26);                               // Blink P26
        pause(300);
        sharedA++;                                // Increment sharedA
      }
    }
    
    void process_b(void *par)                     // Process B
    {
      low(27);     
      while(1)
      {
        toggle(27);                               // Blink P27
        pause(200);
        sharedB -= 2;                             // Subtract 2 from sharedB
      }
    }
    
  • RsadeikaRsadeika Posts: 3,837
    edited 2013-09-15 11:03
    Thanks Andy, great stuff.

    Below is a small test program, trying to get a good idea as to what is going on with the different libs. In the program when I press the CH_UP button, sometimes the wheels start turning real slow, and when I press the same button again, it seems to pick up some speed, not sure why, or how, that is occurring. After hitting the CH_UP button, then I started to hit the CH_DN button, instead of going backwards, it kept moving forward, but at a slower rate, at which time it eventually started to go backwards. So, using the same behavior, I decided to try to make the turns in an incremental way, not sure if that is working the way I expected.

    Making the drive go faster and slower by pressing a button is a good idea, but it seems like it needs a transition point for changing direction and not speed. Not sure if you can achieve that level of control while using an IR remote, not conveniently anyway.

    Next what I will do with the program below is have a new cog for IR control and a new cog for the abdrive stuff. Since I will be implementing an XBee cog which will have drive control commands, I figure multiple use of a particular function should be appropriate.

    Ray

    /*
      Blank Simple Project.c
    
    */
    #include "simpletools.h"
    #include "abdrive.h"
    #include "sonyremote.h"
    
    //static volatile 
    int IRpin = 9;
    //static volatile 
    int key;
    
    int main()
    {
      // Add startup code here.
      drive_setRampStep(10);
      ir_tLimit(50);
    
      while(1)
      {
        key = ir_key(IRpin);                             
        if(key == CH_UP) // CH_UP -> Forward
          drive_rampStep(128,128);
        if(key == CH_DN)  // CH_DN -> Backward
          drive_rampStep(-128,-128);
        if(key == VOL_UP)  // VOL_UP -> Right
          drive_rampStep(128,0);
        if(key == VOL_DN)  // VOL_DN -> Left
          drive_rampStep(0,128);
        if(key == PWR)              // PWR -> Stop drive
          drive_goto(0, 0);
      }  
    }
    
  • edited 2013-09-15 16:30
    Thanks Ray,

    With your code, pressing and holding a button will ramp it toward a particular speed. If you let go of a button, it will hold that speed instead of slowing down. That's because there's no code that responds to when the ir_key function returns -1 after a timeout. The -1 indicates that it didn't get any messages (because you aren't holding down a key any more). You could press and hold the button for the opposite direction, but you will need to hold it long enough for it to complete the change; otherwise, it might just slow down some, like you observed.

    If you want it to instead put on the breaks when you release a button, you can add the condition:

    if(key == -1) drive_speed(0, 0);

    The timeout for the ir_key is set to 50 ms with ir_tLimit(50). After the timeout (because you're not holding a button), it returns -1, the if(key == -1) drive_speed(0,0) statement would cause the loop to step the speed back down toward a speed of 0, 0.

    Another way you could make it stop would be to treat the PWR button as a way of putting on the breaks. Instead of using drive_goto, use drive_rampStep.

    if(key == PWR) drive_rampStep(0, 0).

    If you use that instead of if(key == -1) drive_rampStep(0, 0), the ActivityBot will keep going at whatever speed you ramped it too, and you can press and hold the PWR key to put on the breaks. You can also press and hold a key in the opposite direction to slow it down. Keep holding, and it'stop briefly, and then reverse direction and start to speed up in that opposite direction.

    The drive_rampStep function has turned out to be the best tool for sensor loops because it gets the wheels to a certain speed, but not to abruptly like drive_speed does. In contrast, drive_goto is just designed for fun with dead reckoning when getting started. It's not all that useful beyond that because it cannot be interrupted. I'm working on a drive_distance version that will run in another cog and monitor for if the calling function changed its mind about the distance.

    That said, there is one really cool potential application for drive_goto with the TV remote. The application would wait for the remote handler to key in a list of distances, and the press a key to initiate the sequence. Then, it would go through all the maneuvers that were just keyed in.

    Hope that helps, Andy

    P.S. If you leave the bot position 1 when the wheels are supposed to be turning and then switch to 2, weird things can happen. Reason being, the control system thinks the wheels are supposed to be a long way away from where they are, and they go crazy trying to catch up. So, if you have been testing in position 1 and you want to switch to position 2, press and release the RST button to restart the program right after you switch to position 2. That'll put both its measured and actual distance back to zero.
  • edited 2013-09-15 16:43
    One other idea: I think you could also use drive_ramp(0, 0) if you wanted to just completely stop with just a short press/release of PWR. Here are the three examples:

    1) Set and forget speed, breaks applied by pressing and holding power. Press and hold a different key for a second or so to fully change direction.
    #include "simpletools.h"
    #include "abdrive.h"
    #include "sonyremote.h"
    
    int IRpin = 10;
    int key;
    
    int main()
    {
      drive_setRampStep(10);
      ir_tLimit(50);
    
      while(1)
      {
        key = ir_key(IRpin);                             
        if(key == CH_UP) // CH_UP -> Forward
          drive_rampStep(128,128);
        if(key == CH_DN)  // CH_DN -> Backward
          drive_rampStep(-128,-128);
        if(key == VOL_UP)  // VOL_UP -> Right
          drive_rampStep(128,0);
        if(key == VOL_DN)  // VOL_DN -> Left
          drive_rampStep(0,128);
        if(key == PWR)              // PWR -> speed to zero
          drive_rampStep(0, 0);
      }  
    }
    


    2) Apply breaks applied by letting go of a button for a while:
        ...
        if(key == PWR)              // PWR -> speed to zero
          drive_rampStep(0, 0);
      }  
    }
    


    3) Full stop by just one press/release of PWR (not tested):
        ...
        if(key == PWR)              // PWR -> speed to zero
          drive_ramp(0, 0);
      }  
    }
    
  • RsadeikaRsadeika Posts: 3,837
    edited 2013-09-16 03:26
    That said, there is one really cool potential application for drive_goto with the TV remote. The application would wait for the remote handler to key in a list of distances, and the press a key to initiate the sequence. Then, it would go through all the maneuvers that were just keyed in.
    My thoughts were along the lines of a Learn Mode, the remote handler could drive the bot and have the Learn Mode record and store the data. The recorded data then could be looked at and modified if necessary. Or the recorded data could be a starting point for an expanded bot exploration process. Now that the ActivityBot has a functional encoder process, and the drive is more accurate, you could potentially add minor program offshoots and then have the bot return to the same point of the offshoot and continue with the recorded program. For the time being the Learn Mode would be using just the encoder data, but accuracy and potential could be increased when devices like a compass, and some more pings))) are added. Basically the Learn Mode would simplify the programming process, instead of manually plotting every position, some this could simplified by using a Learn Mode.

    Ray
  • NWCCTVNWCCTV Posts: 3,629
    edited 2013-09-16 11:28
    Thanks for the Sony remote code. This is exactly what I need for my Wild Thumper project. I plan to use Ping sensors also but I want to be able to use a remote for manual over ride just in case. I had everything I needed in C except for this so I should be OK now.
  • RsadeikaRsadeika Posts: 3,837
    edited 2013-09-17 05:09
    The program below seems to be working as expected in its own cog. The actual IR_remote cog code still is lacking something, but can not put my finger on it. The actual commands need to be refined some more. I slowed the start speed, but the next key press looks like it doubles the value and goes twice as fast, it seems like it is not doing the drive_setRampStep(10) setting. Also when you do the right and left turns it goes at the speed that is now set for forward, this is usually to fast to go into a remote controlled turn.

    I tried working with drive_speed() to see if I could get more control, but I was running into problems when I tried too implement backward, left, and right control. I was trying to use a separate key for speed increase/decrease, maybe the lib itself should contain more drive command(s) control.

    Ray
    /*
      Blank Simple Project.c
    
    */
    #include "simpletools.h"
    #include "abdrive.h"
    #include "sonyremote.h"
    
    //static volatile 
    int IRpin = 9;
    //static volatile 
    int key;
    
    unsigned int IRstack[(160 + (50 * 4)) / 4];
    
    // Function prototype
    void IR_remote(void *par);
    
    
    int main()
    {
      int cog = cogstart(&IR_remote, NULL, IRstack, sizeof(IRstack));
      pause(500);
    
      // Add startup code here.
      while(1)
      {
        pause(50);
      }
    
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    /* IR remote control */
    void IR_remote(void *par)
    {
      drive_setRampStep(10);
      ir_tLimit(50);
    
      while(1)
      {
        key = ir_key(IRpin);                             
        if(key == CH_UP) // CH_UP -> Forward
          drive_rampStep(64,64);
        if(key == CH_DN)  // CH_DN -> Backward
          drive_rampStep(-64,-64);
        if(key == VOL_UP)  // VOL_UP -> Right
          drive_rampStep(64,0);
        if(key == VOL_DN)  // VOL_DN -> Left
          drive_rampStep(0,64);
        if(key == PWR)              // PWR -> Stop drive
          drive_ramp(0, 0);      
      }  
    }
    
  • RsadeikaRsadeika Posts: 3,837
    edited 2013-09-18 04:51
    Below I added an XBee component to the program, and it is running into a problem with drive the commands. The IR_remote part does not respond to a key press anymore, and the xbee part only does a gofore command, or only one command before it seems like it has locked the drive routine. So, it seems like the abdrive lib is only functional for one cog at a time, seems like this could could become a very complex program if you have to manipulate the abdrive component, or the cog access to the abdrive component. But, maybe it is just an error in my program that I am not seeing at the moment.

    Ray

    /*
      Blank Simple Project.c
    
    */
    #include "simpletools.h"
    #include "abdrive.h"
    #include "sonyremote.h"
    #include "fdserial.h"
    
    
    //static volatile 
    int IRpin = 9;
    //static volatile 
    int key;
    
    //static volatile 
    int ldrive = 0, rdrive = 0;
    //static volatile 
    int ldrive_goto = 0, rdrive_goto = 0;
    //static volatile 
    int ldrive_RStep = 0, rdrive_RStep = 0;
    //static volatile 
    int setRampS = 0;
    
    
    unsigned int IRstack[(160 + (50 * 4)) / 4];
    unsigned int XBstack[(160 + (50 * 4)) / 4];
    unsigned int Drivestack[(160 + (50 * 4)) / 4];
    
    serial *xbee;
    
    // Function prototype
    void IR_remote(void *par);
    void XB_remote(void *par);
    void Drive_control(void *par);
    
    int main()
    {
      int cog = cogstart(&IR_remote, NULL, IRstack, sizeof(IRstack));
      pause(500);
      int cog1 = cogstart(&XB_remote, NULL, XBstack, sizeof(XBstack));
      pause(500);
      int cog2 = cogstart(&Drive_control, NULL, Drivestack, sizeof(Drivestack));
      pause(500);
    
      // Add startup code here.
      while(1)
      {
        pause(50);
      }
    
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    /* IR remote control */
    void IR_remote(void *par)
    {
      drive_setRampStep(10);
      ir_tLimit(50);
    
      while(1)
      {
        key = ir_key(IRpin);                             
        if(key == CH_UP) // CH_UP -> Forward
          drive_rampStep(64,64);
        if(key == CH_DN)  // CH_DN -> Backward
          drive_rampStep(-64,-64);
        if(key == VOL_UP)  // VOL_UP -> Right
          drive_rampStep(64,0);
        if(key == VOL_DN)  // VOL_DN -> Left
          drive_rampStep(0,64);
        if(key == PWR)              // PWR -> Stop drive
          drive_ramp(0, 0);      
      }  
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    /* XB remote control */
    void XB_remote(void *par)
    {
      char inBuff[40];
    
    /*                     Rx  Tx mode BAUD */
      xbee = fdserial_open(11, 10, 0, 9600);
      pause(500);
      writeStr(xbee,"XBremote started.\n");
    
      while(1)
      {
        writeStr(xbee,"> ");
        readStr(xbee, inBuff, 40);
        if(!strcmp(inBuff,"onled"))
        {
          high(26);
        }
        else if(!strcmp(inBuff,"offled"))
        {
          low(26);
        }
        else if(!strcmp(inBuff,"gostop"))
        {
          //drive_speed(0, 0);
          ldrive = 0, rdrive = 0;
        }
        else if(!strcmp(inBuff,"gofore"))
        {
          //drive_speed(64,64);
          ldrive = 64, rdrive = 64;
        }
        else if(!strcmp(inBuff,"goback"))
        {
          //drive_speed(-64,-64);
          ldrive = -64, rdrive = -64;
        }
        else if(!strcmp(inBuff,"goto"))
        {
          writeStr(xbee,"To be determined");
        }
        else
        {
          writeLine(xbee,"Invalid Command!");
        }    
    
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    void Drive_control(void *par)
    {
      while(1)
      {
        drive_speed(ldrive,rdrive);
        drive_goto(ldrive_goto,rdrive_goto);
        drive_setRampStep(setRampS);
        drive_rampStep(ldrive_RStep,rdrive_RStep);
    //    pause(30);
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    
    
    
  • edited 2013-09-18 12:08
    Hi Ray,

    This reminds me of a problem I see when we take more than one TV remote controlled bot to a youth event. Two kids get remotes from different tables and take them to the same table. Then, they use them to control the same bot. One presses and holds the forward button. The other presses and holds the back up button. The bot understandably looks like it's having a seizure.

    In the case of your code, we have two inputs, and allowing them to exert control over the bot at the same time can result in similar behavior. Several ways to handle this come to mind. First, if both inputs are coming in at the same time, the code could give one priority over the other. Another way to handle it would be to take the average of the two for robot control. A third way to handle it would be to lock out whatever input tries to interrupt the first input stream until that input stream is obviously done.

    But, before we start on any of that, I'd like to make sure both our subsystems are good. We have working and tested TV remote code earlier in this thread. Could you please post some working and tested XBee control code (that controls through just the XBee?).

    After we get those two pieces, let's talk about how we want to mediate control. On my end, I'll add locks to abdrive to prevent any timing issues, but locks still cannot prevent the spasmodic motions that result when two or more conflicting incoming commands are repeating themselves. That's where the mediation approach comes in: One could always have priority over the other, they could be averaged, or they could lock until the input data stops.

    Andy
  • edited 2013-09-18 12:47
    Just as a side note, here is an example that uses locks to make each cog wait for the other to be done with its maneuver before taking control and calling abdrive functions.
    #include "simpletools.h" 
    #include "abdrive.h"
    
    void speed_steps(void *par);
    
    unsigned int stack[40 + 24];
    
    static volatile int id, lockstate;
    
    int main()
    {
      if(!(id = locknew()))
      {
        print("No locks available."); 
        while(1);
      }
      else print("Lock ID = %d", id);
    
      while(lockset(id));
      drive_speed(-16, -16);
      cogstart(&speed_steps, NULL, 
               stack, sizeof(stack));
    
      // Other cog has to wait until this cog clears the lock
      pause(2000);
      lockclr(id);
      pause(100);
    
      // This cog has to wait for the other to clear the lock
      while(lockset(id));        
      drive_speed(0, 0);
      lockclr(id);
    }
    
    void speed_steps(void *par)
    {
      while(lockset(id));
      for(int i = 1; i <= 6; i++)
      {
        drive_speed(16 * i, 16 * i);
        pause(1000);
      }  
      lockclr(id);
      while(1);
    }
    
  • RsadeikaRsadeika Posts: 3,837
    edited 2013-09-18 13:42
    Program has a working XBee cog, the commands that I have, seem to be working as expected. I left the other cogs in, just to make sure I was not running out of cogs to work with for future expansion. The Drive_control cog will probably have to go, that idea is not working as expected. It will be kind of interesting to see if the use of locks will work.

    Ray
    ///////////////////////////////////////////////////////////////////////////////
    /*
     * abpl.c
     *
     * The ActivityBot program.
     * 
    */
    #include "simpletools.h"
    #include "abdrive.h"
    #include "simpletext.h"
    #include "ping.h"
    #include "fdserial.h"
    #include "sonyremote.h"
    
    //static volatile 
    //int ldrive = 0, rdrive = 0;
    //static volatile 
    //int ldrive_goto = 0, rdrive_goto = 0;
    //static volatile 
    //int ldrive_RStep = 0, rdrive_RStep = 0;
    //static volatile 
    //int setRampS = 0;
    
    volatile unsigned int IRpin = 9;
    
    serial *xbee;
    
    
    unsigned int IRstack[(160 + (50 * 4)) / 4];
    unsigned int XBstack[(160 + (50 * 4)) / 4];
    unsigned int Drivestack[(160 + (50 * 4)) / 4];
    
    // Function prototype
    void IR_remote(void *par);
    void XB_remote(void *par);
    void Drive_control(void *par);
    
    
    ///////////////////////////////////////////////////////////////////////////////
    int main()
    {
      // Add startup code here.
      char inBuff[40];
      int getBuff;
    
      pause(300);
      print("The ActivityBot\r");
    
      int cog = cogstart(&IR_remote, NULL, IRstack, sizeof(IRstack));
      pause(500);
      int cog1 = cogstart(&XB_remote, NULL, XBstack, sizeof(XBstack));
      pause(500);
      int cog2 = cogstart(&Drive_control, NULL, Drivestack, sizeof(Drivestack));
      pause(500);
     
      while(1)
      {
        putChar('#');
        getBuff = getStr(inBuff,40);
        if(!strcmp(getBuff,"quit")) break;
        else
        {
          putLine("Invalid Command!");
        }
        
    //    pause(400);    
      }
      putLine("Program Stopped!");  
    }
    ///////////////////////////////////////////////////////////////////////////////
    /* IR remote control */
    void IR_remote(void *par)
    {
    
      while(1)
      {  
        pause(50);  
      }
    }
    ///////////////////////////////////////////////////////////////////////////////
    /* XB remote control */
    void XB_remote(void *par)
    {
    
      char inBuff[40];
    
    
    /*                     Rx  Tx mode BAUD */
      xbee = fdserial_open(11, 10, 0, 9600);
      pause(500);
      writeStr(xbee,"XBremote started.\n");
    
      while(1)
      {
        writeStr(xbee,"> ");
        readStr(xbee, inBuff, 40);
        if(!strcmp(inBuff,"onled"))
        {
          high(26);
        }
        else if(!strcmp(inBuff,"offled"))
        {
          low(26);
        }
        else if(!strcmp(inBuff,"gostop"))
        {
    //      ldrive = 0, rdrive = 0;
          drive_speed(0,0);
        }
        else if(!strcmp(inBuff,"gofore"))
        {
    //      ldrive = 32, rdrive = 32;
          drive_speed(32,32);
        }
        else if(!strcmp(inBuff,"goback"))
        {
    //      ldrive = -32, rdrive = -32;
          drive_speed(-32,-32);
        }
        else if(!strcmp(inBuff,"goto"))
        {
          // To be added.
        }
        else
        {
          writeLine(xbee,"Invalid Command!");
        }    
    //    high(27);
    //    pause(500);
    //    low(27);
    //    pause(500);
      }
    }
    ///////////////////////////////////////////////////////////////////////////////
    void Drive_control(void *par)
    {
      while(1)
      {
    //    drive_speed(ldrive,rdrive);
    //    drive_goto(ldrive_goto,rdrive_goto);
    //    drive_setRampStep(setRampS);
    //    drive_rampStep(ldrive_RStep,rdrive_RStep);
        pause(30);
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    
    
  • edited 2013-09-18 22:44
    Hi Ray,

    Here is the xbee control modified slightly. I'm hoping that if you also put the TV remote code into this format, we'll have an easier time merging the two and adding the arbitration code. In other words, modify your TV remote code so that it sets speedLeft and speedRight variables and lets the ab_nav function take care of calling the abdrive functions.

    Andy
    #include "simpletools.h"
    #include "abdrive.h"
    #include "fdserial.h"
    
    void xb_remote(void *par);
    static int xbStack[40 + 50];
    serial *xbee;
    static volatile char xbInBuf[40];
    static volatile int xbCog;
    
    void ab_nav(void *par);
    static int abStack[40 + 50];
    static volatile int abCog;
    static volatile int speedLeft, speedRight;
    
    int main()
    {
      int xbCog = cogstart(&xb_remote, NULL, xbStack, sizeof(xbStack));  
      int abCog = cogstart(&ab_nav, NULL, abStack, sizeof(abStack));  
      while(1); 
    }
    
    
    void ab_nav(void *par)
    {
      int speedLeftOld  = speedLeft;
      int speedRightOld = speedRight;
      while(1)
      {
        if(speedLeftOld != speedLeft || speedRightOld != speedRight)
        {
          drive_speed(speedLeft, speedRight);
          speedLeftOld = speedLeft;
          speedRightOld = speedRight;
        } 
        pause(20);
      }
    }
    
    
    /* XB remote control */
    void xb_remote(void *par)
    {
      char inBuff[40];
                        // Rx  Tx  mode BAUD
      xbee = fdserial_open(11, 10, 0,   9600);
      pause(500);
      writeStr(xbee,"XBremote started.\n");
    
      while(1)
      {
        writeStr(xbee,"> ");
        readStr(xbee, inBuff, 40);
        if(!strcmp(inBuff,"onled"))
        {
          high(26);
        }
        else if(!strcmp(inBuff,"offled"))
        {
          low(26);
        }
        else if(!strcmp(inBuff,"gostop"))
        {
          speedLeft = 0;
          speedRight = 0;
        }
        else if(!strcmp(inBuff,"gofore"))
        {
          speedLeft = 32;
          speedRight = 32;
        }
        else if(!strcmp(inBuff,"goback"))
        {
          speedLeft = -32;
          speedRight = -32;
        }
        else if(!strcmp(inBuff,"goto"))
        {
          // To be added.
        }
        else
        {
          writeLine(xbee,"Invalid Command!");
        }    
      }
    }
    
  • RsadeikaRsadeika Posts: 3,837
    edited 2013-09-19 04:46
    Adding in the suggestions from Andy, below is a program that is working as expected. Just contains some very basic commands, just to make sure both IR_remote, and XB_remote are working.

    The one thing that I have noticed is, SimpleIDE reports: "Code Size 15,528 bytes (20,476 total)", and this is in CMM mode. Barely getting started and the available memory is starting to dwindle, fast. One option is using XMM, but this would be a major redesign of the existing program, not even sure if you could implement abdrive and still have IR_remote and XB_remote function as expected.

    Ray
    ///////////////////////////////////////////////////////////////////////////////
    /*
     * abpl.c
     *
     * The ActivityBot program.
     * 
    */
    #include "simpletools.h"
    #include "abdrive.h"
    #include "simpletext.h"
    #include "ping.h"
    #include "fdserial.h"
    #include "sonyremote.h"
    
    
    
    volatile unsigned int IRpin = 9;
    
    static volatile char xbInBuf[40];
    static volatile int xbCog;
    static volatile int speedLeft, speedRight;
    
    serial *xbee;
    
    
    unsigned int IRstack[40 + 50];
    unsigned int XBstack[40 + 50];
    unsigned int abstack[40 + 50];
    
    // Function prototype
    void IR_remote(void *par);
    void XB_remote(void *par);
    void ab_nav(void *par);
    
    
    ///////////////////////////////////////////////////////////////////////////////
    int main()
    {
      // Add startup code here.
      char inBuff[40];
      int getBuff;
    
      pause(300);
      print("The ActivityBot\r");
    
      int ircog = cogstart(&IR_remote, NULL, IRstack, sizeof(IRstack));
      pause(500);
      int xbcog = cogstart(&XB_remote, NULL, XBstack, sizeof(XBstack));
      pause(500);
      int abcog = cogstart(&ab_nav, NULL, abstack, sizeof(abstack));
      pause(500);
     
      while(1)
      {
        putChar('#');
        getBuff = getStr(inBuff,40);
        if(!strcmp(getBuff,"quit")) break;
        else
        {
          putLine("Invalid Command!");
        }
        
    //    pause(400);    
      }
      putLine("Program Stopped!");  
    }
    ///////////////////////////////////////////////////////////////////////////////
    /* IR remote control */
    void IR_remote(void *par)
    {
      int key;
      ir_tLimit(50);
    
      while(1)
      {
        key = ir_key(IRpin);
        if(key == PWR)
        {
          speedLeft = 0;
          speedRight = 0;
        }
        if(key == CH_UP)  // CH_UP -> Forward
        {
          speedLeft = 32;
          speedRight = 32;
        }
        if(key == CH_DN)  // CH_DN -> Backward
        {
          speedLeft = -32;
          speedRight = -32;
        }
        if(key == VOL_UP)  // VOL_UP -> Right
        {
          speedLeft = 16;
          speedRight = 0;
        }
        if(key == VOL_DN)  // VOL_DN -> Left
        {
          speedLeft = 0;
          speedRight = 16;
        } 
    //    pause(50);  
      }
    }
    ///////////////////////////////////////////////////////////////////////////////
    /* XB remote control */
    void XB_remote(void *par)
    {
    
      char inBuff[40];
    
    
    /*                     Rx  Tx mode BAUD */
      xbee = fdserial_open(11, 10, 0, 9600);
      pause(500);
      writeStr(xbee,"XBremote started.\n");
    
      while(1)
      {
        writeStr(xbee,"> ");
        readStr(xbee, inBuff, 40);
        if(!strcmp(inBuff,"onled"))
        {
          high(26);
        }
        else if(!strcmp(inBuff,"offled"))
        {
          low(26);
        }
        else if(!strcmp(inBuff,"gostop"))
        {
          speedLeft = 0;
          speedRight = 0;
        }
        else if(!strcmp(inBuff,"gofore"))
        {
          speedLeft = 32;
          speedRight = 32;
        }
        else if(!strcmp(inBuff,"goback"))
        {
          speedLeft = -32;
          speedRight = -32;
        }
        else if(!strcmp(inBuff,"goto"))
        {
          // To be added.
        }
        else
        {
          writeLine(xbee,"Invalid Command!");
        }    
      }
    }
    ///////////////////////////////////////////////////////////////////////////////
    void ab_nav(void *par)
    {
      int speedLeftOld  = speedLeft;
      int speedRightOld = speedRight;
      while(1)
      {
        if(speedLeftOld != speedLeft || speedRightOld != speedRight)
        {
          drive_speed(speedLeft, speedRight);
          speedLeftOld = speedLeft;
          speedRightOld = speedRight;
        } 
        pause(20);
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    
    
  • edited 2013-09-19 11:21
    Yeah, abdrive is an ongoing project that still takes a lot of space. After adding a few more features, I'll start paring it down.

    Also, I've noticed that it's possible to add a lot more code now that we've got the smaller footprint libraries for text messages, EEPROM, and other things. Support for terminal, text messages and etc. are already in the app, so it should only grow by small increments with each function. That's with the possible exception of SD, but if you stick with fread and fwrite, it will keep the increase in code size reasonable.
Sign In or Register to comment.