Pixy for Propeller?

2»

Comments

  • varnonvarnon Posts: 179
    edited August 2014 Vote Up0Vote Down
    I read up on this thread a few weeks ago. Thanks for all the information. I just got my pixy today. I really don't need it right now, but I do have some ideas of how it could be useful. For now, it is kind of a neat little toy. I think it is very reasonably priced for what it does. I do agree that it is very sensitive to lighting conditions.
  • twm47099twm47099 Posts: 664
    edited September 2014 Vote Up0Vote Down
    I've written a function that returns the x position of any signature from Pixy using the UART mode. I made use of it in my ActivtyBot program discussed in post 14 & 15 of this thread:

    http://forums.parallax.com/showthread.php/156970-Bluetooth-App-to-control-ActivityBot?p=1291808#post1291808

    The function can be modified to return any of the Pixy data (x, y, horizontal size, vertical size).

    The code I've posted below has the function and a short main() to demonstrate how it works. In the ActivityBot post, I've removed the printing portion of the code since its not needed.

    I'd like to figure out a way to improve this since there is an issue. Since pixy sends data continuously and the number of blocks per frame depend on the baud as well as the number of objects pixy finds in each signature. The data is sent in signature number order, with the data in each signature group sent in order of size.

    A new frame is started every 20 ms, even if in the middle of a block (giving a bad checksum). If there are a lot of objects (blocks) of the low numbered signatures, the higher signature ones may never be sent. On the other hand if there are only a few blocks in the field of view, lots of zeros will be sent. The code below is my try. Comments welcome.

    Tom
    /*  pixyuart fnctn 3a.c    This works to return a value,  C code used with Pixy - CMUCAM5       Tom Montemarano June 2014,  MIT License.
      
     This program prints out the value of x for a chosen signature and data for all blocks in a frame 
    
     Pixy pin 1 (PP1) (rx)   -- ABot P0 (tx)   -- QS p14  white
                     PP4 (tx)     -- Abot P1 (rx)   -- QS p13  blue
                     PP2 (+5v  )-- Abot (+5v)    --  QS (+5v) 
                     PP6 (gnd)  -- Abot (gnd)     --  QS (gnd)
    
     Run with terminal.  
     Type sig number (1-7) <enter>
     This version only prints out the data
          The order of Pixy words in each block is: 
           43605 (sync), checksum (sum of next 5 words), signature # (1 - 7), x-position of centroid, y-position, width, height.
           Each word is sent LSB first
           2 sync words in succession mean start of new frame.
      
        Now that I got it working I need to:
           1.  Modify to also use colorcodes
      */
    
     #include "simpletools.h"                      // Include simple tools
     #include "fdserial.h"
     #define pybaud 86400    // This baud seems maximum, maybe too fast when getpixyx() is used in some pgms 
                                           // 57600 baud seems safer
     #define pynumblks 14      // max nmbr blocks make large enough to get sig of interest, but too large gets errors
     #define blks 16         // make this pynumblks + 2
                                                   
     fdserial *pixy; 
    
     int abc;
     int signum = 1;       // this is the signature of interest (1 - 7)
     int pyk;
     //int pynumblks = 14;  
     //int blks = pynumblks + 2;
     int pycktot;
     int pyflg;                                // pyflg = 1 when first sync word located
     int pv[blks][7];
     int pyxflg =0;
     int pixyx = -1;
     int pyflg2 =1;
     int pycount = 200;     //  number of tries or return -1  *** calling program sets this just before calling function 
     int rempycount; 
    
     int getpyx(int z, int cntr)           //      z is the signature number 1 - 7, cntr is pycount
     {
     char c1;                     // raw LS byte values from pixy
     int i;
     int j;                                //  number of pixy words
     int k;
                               // fdserial * fdserial_open(int rxpin, int txpin, int mode, int baudrate)
         // in calling program choose one of the 2 statements below. comment out the other one
     //  pixy = fdserial_open(1, 0, 0, pybaud);   // For ActivityBot
     //  pixy = fdserial_open(13, 14, 0, pybaud);    // for quickstart board
      
     pixyx = -1;
     pyflg2 = 1;
     pause(50);
       while(pyflg2)
      {
     cntr--;
         pyflg = 0;
         fdserial_rxFlush(pixy);
         c1 = fdserial_rxChar(pixy);
         if(c1 == 0x55)        // 1st
         {
           pv[0][0] = fdserial_rxChar(pixy);
           if(pv[0][0] == 0xAA)     //  one sync word    2nd
           {
             pyflg =1;
             c1 = fdserial_rxChar(pixy);
             if(c1== 0x55)   // 3rd
             {
               pv[0][0] = fdserial_rxChar(pixy);
               if(pv[0][0] == 0xAA) // 2 sync words = start of frame   4th 
               {
                 pv[0][0] = 0xAA55;
                 pyflg =2; 
                 for(i = 1; i < 7; i++)   
                 {
                   c1  = fdserial_rxChar(pixy);
                   pv[0][i] = (fdserial_rxChar(pixy) << 8) | c1;
                 }
                 k = 1;
                 for(j = 1; j < pynumblks; j++)  //  aa
                 {
                   for(i = 0; i < 7; i++)  //  bb
                   {
                     c1  = fdserial_rxChar(pixy);
                     pv[j][i] = (fdserial_rxChar(pixy) << 8) | c1;
                     if((pv[j][1] != 0xAA55) && (pv[j][2] != 0)) k= j+1;       //  2 sync words or empty block 
                    }   // end bb
                 }  // end aa
                printi(" \n----- new frame -----\n");
                for(i=0; i < k; i++)       //  cc  k = num good blocks
                {
                  pycktot = 0;
                  for(j=2; j<7; j++) pycktot += pv[i][j];      // calc chksum
                 
                  if((pv[i][1] !=0) && pycktot == pv[i][1])      // if cksum is good and chksum<>0  5th
                  {
                     pyk = k;
      
                    printi(" --- new block ---  k = %d  i = %d \n", k, i);
                    printi(" checksum good\n");
                    printi("sync = %d\n", pv[i][0]);      
                    printi("chksum = %d\n", pv[i][1]);
                    printi("sig_num = %d\n", pv[i][2]);
                    printi("x = %d\n", pv[i][3]);
                    printi("y = %d\n", pv[i][4]);
                    printi("width = %d\n", pv[i][5]);
                    printi("height = %d\n", pv[i][6]);
                    printi("area = %d\n", pv[i][5]*pv[i][6]);
                     
                     if((pv[i][2] == z) && (pyxflg == 0))        //  dd
                     {
                       pyxflg = 1;
                       pixyx = pv[i][3];
                       pyflg2 =0;
                       printi("pixyx = %d\n",pixyx);
                     }     // end dd
                  }  // end 5th
                   else printi("*** cksum ng *** = %d\n", pycktot);
                }  //  end cc
                pyxflg = 0;
                rempycount = cntr;       // only if there is need to know value of cntr   ****
                return pixyx;
               }   // end 4th
             } // end 3rd
           }  // end 2nd
         }  // end 1st
         if(cntr<0)
         {
           pyflg2 =0;
           rempycount = cntr;        // only if there is need to know value of cntr   ****
           return pixyx;
         }
      }  // end while
     }  // end function
      
    
     int main()    // calling program must have the statements marked with ****   Those with ^^^ are needed with each call
                       //  calling program should call one additional time if result is -1 due to inconsistent pixy 
     {
       pixy = fdserial_open(1, 0, 0, pybaud);   // For ActivityBot       ****
       pause(50);                  //            **** needed after open
      fdserial_rxFlush(pixy);
       pause(50); 
       while (1)
         {
     int xx = getchar();   // enter sig number
     signum=xx-48;
     if((signum>=1) && (signum<=7))
     {
     printi("\n signum = %d  xx= %c ", signum, xx);
     fdserial_rxFlush(pixy);             //      *** flush before calling
           abc = getpyx(signum, pycount);    // parameters signum, number of tries  *** function call
           printi("signum = %d k = %d pycount = %d  abc = %d\n",signum, pyk, rempycount, abc);
     //      pause(1000);    
     }    
         }
     //pause(1000);
     fdserial_close(pixy);
     }
     
    
     
    
    
    
  • twm47099twm47099 Posts: 664
    edited September 2014 Vote Up0Vote Down
    imbinary wrote: »
    I'm working on a simple robot project with the activity board and pixyCMU5. I modified the arduino code to work with this board via SPI.

    The initial release is here https://github.com/imbinary/parallax-pixy . I run the code in a cog and access the data from the blocks struct. One gotcha I encountered was not having enough light when testing, and not detecting anything so assumed the code was broken :frown:.
    ...
    Hopefully this helps someone else get started. =)

    imbinary

    @imbinary

    I tried the code but i did not get anything printed out. I retried by running the pixyStart() function in the same cog as main, and it did print "pixy init" and "pixy init finish", but nothing else.

    I added a statement in the getWord() function to print w. When I ran that code using Run With Terminal, it did printout the Pixy data block. But it would only print one block per frame. For example, I defined 3 colors (signatures 1,2,3). But the program only captures one block (the largest object of the lowest number signature) each frame. If I removed object 1, it would printout data for object 2, etc.

    The main() function I used is shown below. I have 2 questions.

    1. Any idea why I do not get anything printed from main?
    2. Do you only get block per frame?

    Thanks
    Tom

    void main() { 
    pixyStart();
     //        pixy_cog = cog_run(&pixyStart, 160); 
               while(1)
               {       
                 pause(500); 
                 printi("running \n");
                 if(blockCount){
                   //dprinti(xbee,"pixy: %d\n",blocks[0].x);
                   printi("pixy: count %d x(%d) y(%d)\n",blockCount,blocks[0].x,blocks[0].y);   
                   
                 } 
               }
             }
     
    
    
    
  • twm47099twm47099 Posts: 664
    edited September 2014 Vote Up0Vote Down
    Regarding SPI interfacing with PIXY, I modified the "SPI Asm DEMO.spin" program by deleting all of the temperature sensor code except for the declarations. I set my SPI pins, and used the spi.shiftin() method below in a repeat loop that also just printed the1 byte values.

    pixyval := SPI.SHIFTIN(DQ, CLK, SPI#MSBPRE, 8)  '' read the pixy 
    

    The numbers looked correct, but even with the clock delay value = 1, (I tried different settings) I was only able to get one block per frame. I also had to increase the PST baud to 19200 in order to print the entire block. I'm not sure if I am doing something wrong or if that is the limitation of the prop or of pixy. Pixy is supposed to send data at 1Mbit/second with 20ms between Frames.

    tom
  • twm47099twm47099 Posts: 664
    edited September 2014 Vote Up0Vote Down
    When I thought about the poor results I got with SPIN using the SPI Asm Demo, I realized that I was reading the data with PASM, but printing each read value with Spin. So I changed it by declaring pixyval as a 200 element array, and then filling the array in one repeat loop, then printing the array in a subsequent loop.

    By setting the delay value to 15 (=clock delay of 1u sec) I was able to get more than 6 blocks per frame. (6 objects were detected and the remaining values were zeros until the next frame started indicating that it could have handled more blocks.)

    I tried the same thing with the C program, but was only able to get 2 blocks before the start of a new frame. That could be due to the clock setting, but I don't see anyway to change it.?.

    Tom
  • twm47099twm47099 Posts: 664
    edited September 2014 Vote Up0Vote Down
    I have made a preliminary version of an SPI interface using C and simpleIDE. It uses the pasm from the spi_Asm.spin with some modifications. I intend to make a general spi library, but for now it only supports Pixy.

    Using that code I get over 14 blocks of data per frame, which should be sufficient for using ColorCodes or a large number of color signatures.

    It's at the end of this thread:

    http://forums.parallax.com/showthread.php/157441-Can-SPI-in-Simple-Libraries-be-speeded-up?p=1295677#post1295677

    You still have to write code to transform the raw data as you want.

    Tom
  • robodverobodve Posts: 1
    edited December 2014 Vote Up0Vote Down
    Hi all,

    Inspired by Tom I took his program using Pixy with the analog output signal as a starting point. I expanded it / added things:
    -2nd cog is used to do PING :))))) sensor measurements and if a certain treshold value is reached it stops Abot (this is used to determine if the colored object is reached since analog output mode gives no info about how close you are to the object of interest)
    -I use a PID algorithm to get to the object (for the time being I disabled the Integral part since that can get out of hand easily and is overkill to use on a relative simple task as this one)

    The code is here: Pixy_only.c

    Enjoy! Next step for me is do sort of the same but using the UART mode and the block data coming out of pixy
  • RobertDyerRobertDyer Posts: 23
    edited March 2015 Vote Up0Vote Down
    Hello,

    I'm wondering if anyone is still following this thread since there hasn't been any activity for quite some time? Has this information moved to another Parallax forum thread? There are a few Propeller threads on the Pixy Software Forum, but not too much.

    I've been doing some work with the Pixy, and yes, in UART mode the data stream is filled with $00 between Image Frames. Since the frame rate is 50Hz (every 20mS), the faster the baud rate, the more $00 bytes will be sent between frames because the actual Image Frame data takes less of the 20mS window. If you look in the Pixy Software Forum and search for "UART frame" you will find a special version of Pixy firmware that does not do this. It will just send the data for the Image Frame and stop. However there are a couple data changes: Every Image Frame in the special version starts with $0000, then the sync bytes, then the data, etc. If there are no objects in the frame it only sends the $0000. It's not obvious to me what will happen to this version if a new "standard" version of firmware is released. It would probably be a better idea for me to move to the I2C or SPI interface since as far as I know those protocols don't have this issue.

    Anyway, if you're out there and still interested in Pixy on the Propeller, either let me know where this topic has moved to, or please start posting here again, and I'll join in.

    Robert
  • vanmunchvanmunch Posts: 567
    edited March 2015 Vote Up0Vote Down
    Hey Robert, Yes, I'm following this thread with a lot of interest. I have a Pixy and I've run some of the demos, but I'm working on a couple of other projects right now. Please keep up the good work.

    Dave
    My wife is very, very understanding

    Prospero: Robot Farmer
    http://www.youtube.com/watch?v=ACtihXjq2B0
    www.DorhoutRD.com
  • twm47099twm47099 Posts: 664
    edited March 2015 Vote Up0Vote Down
    Robert,
    After I wrote post 37 above, I got involved writing an SPI library using the C and PASM code for a few of the SPI devices I have. Then I got sidetracked. I also saw that the CMU pixy folks have changed the SPI protocol that pixy uses. Previously, pixy just continuously sent data in 8 bit bytes. The new version of the Pixy firmware requires the controlling Micro to send 16 bits and the pixy responds with 16 bits. (At least that's the way I read their documentation.) That has an advantage in that when it sends it sends a complete MSB first data word. So there is no longer the need to test the received byte to determine if it is the 1st or 2nd byte of a word. But it will slow down the data rates.

    My SPI library should be able to handle that, but the original pixy SPI code I wrote won't work on the new firmware. I haven't updated my pixy firmware yet since there are a lot of questions regarding bugs in the software. I'm not sure if the bugs are just in the arduino libraries or if there are issues in the firmware also. It also seems like there are some unofficial versions of firmware (like the UART code you mentioned), so I'm hesitant to write my SPI code for version "???". I'm also not sure if the slow down will significantly reduce the number of blocks of data per frame.

    One other advantage of the new SPI protocol when used with colorcodes and colorcode mode 2 (colorcodes only) is that all you would have to do is get a 16bit read and look for $aa55, and that would mean the start of a new frame since colorcode blocks start with $aa56. That way I could do away with the code that looks for $aa followed by $55 to determine the start of a word and with the code that looks for 2 instances of $aa55 for the start of a new frame.

    Tom
  • twm47099twm47099 Posts: 664
    edited March 2015 Vote Up0Vote Down
    Deleted double post.
  • RobertDyerRobertDyer Posts: 23
    edited March 2015 Vote Up0Vote Down
    Dave and Tom,

    Glad to hear there is still interest out there. I'll keep you posted on my progress. Thanks!!

    Robert
  • I am also interested in how I can use the Pixy with my ActivityBot
Sign In or Register to comment.