elbestia-robot/lib/pixy/TPixy.h
2025-02-27 16:55:47 +01:00

273 lines
6.2 KiB
C++

//
// begin license header
//
// This file is part of Pixy CMUcam5 or "Pixy" for short
//
// All Pixy source code is provided under the terms of the
// GNU General Public License v2 (http://www.gnu.org/licenses/gpl-2.0.html).
// Those wishing to use Pixy source code, software and/or
// technologies under different licensing terms should contact us at
// cmucam@cs.cmu.edu. Such licensing terms are available for
// all portions of the Pixy codebase presented here.
//
// end license header
//
// This file is for defining the Block struct and the Pixy template class.
// (TPixy). TPixy takes a communication link as a template parameter so that
// all communication modes (SPI, I2C and UART) can share the same code.
//
#ifndef _TPIXY_H
#define _TPIXY_H
#include "Arduino.h"
// Communication/misc parameters
#define PIXY_INITIAL_ARRAYSIZE 30
#define PIXY_MAXIMUM_ARRAYSIZE 130
#define PIXY_START_WORD 0xaa55
#define PIXY_START_WORD_CC 0xaa56
#define PIXY_START_WORDX 0x55aa
#define PIXY_MAX_SIGNATURE 7
#define PIXY_DEFAULT_ARGVAL 0xffff
// Pixy x-y position values
#define PIXY_MIN_X 0L
#define PIXY_MAX_X 319L
#define PIXY_MIN_Y 0L
#define PIXY_MAX_Y 199L
// RC-servo values
#define PIXY_RCS_MIN_POS 0L
#define PIXY_RCS_MAX_POS 1000L
#define PIXY_RCS_CENTER_POS ((PIXY_RCS_MAX_POS-PIXY_RCS_MIN_POS)/2)
enum BlockType
{
NORMAL_BLOCK,
CC_BLOCK
};
struct Block
{
// print block structure!
void print()
{
int i, j;
char buf[128], sig[6], d;
bool flag;
if (signature>PIXY_MAX_SIGNATURE) // color code! (CC)
{
// convert signature number to an octal string
for (i=12, j=0, flag=false; i>=0; i-=3)
{
d = (signature>>i)&0x07;
if (d>0 && !flag)
flag = true;
if (flag)
sig[j++] = d + '0';
}
sig[j] = '\0';
sprintf(buf, "CC block! sig: %s (%d decimal) x: %d y: %d width: %d height: %d angle %d\n", sig, signature, x, y, width, height, angle);
}
else // regular block. Note, angle is always zero, so no need to print
sprintf(buf, "sig: %d x: %d y: %d width: %d height: %d\n", signature, x, y, width, height);
Serial.print(buf);
}
uint16_t signature;
uint16_t x;
uint16_t y;
uint16_t width;
uint16_t height;
uint16_t angle;
};
template <class LinkType> class TPixy
{
public:
TPixy(uint16_t arg=PIXY_DEFAULT_ARGVAL);
~TPixy();
uint16_t getBlocks(uint16_t maxBlocks=1000);
int8_t setServos(uint16_t s0, uint16_t s1);
int8_t setBrightness(uint8_t brightness);
int8_t setLED(uint8_t r, uint8_t g, uint8_t b);
void init();
Block *blocks;
private:
boolean getStart();
void resize();
LinkType link;
boolean skipStart;
BlockType blockType;
uint16_t blockCount;
uint16_t blockArraySize;
};
template <class LinkType> TPixy<LinkType>::TPixy(uint16_t arg)
{
skipStart = false;
blockCount = 0;
blockArraySize = PIXY_INITIAL_ARRAYSIZE;
blocks = (Block *)malloc(sizeof(Block)*blockArraySize);
link.setArg(arg);
}
template <class LinkType> void TPixy<LinkType>::init()
{
link.init();
}
template <class LinkType> TPixy<LinkType>::~TPixy()
{
free(blocks);
}
template <class LinkType> boolean TPixy<LinkType>::getStart()
{
uint16_t w, lastw;
lastw = 0xffff;
while(true)
{
w = link.getWord();
if (w==0 && lastw==0)
{
delayMicroseconds(10);
return false;
}
else if (w==PIXY_START_WORD && lastw==PIXY_START_WORD)
{
blockType = NORMAL_BLOCK;
return true;
}
else if (w==PIXY_START_WORD_CC && lastw==PIXY_START_WORD)
{
blockType = CC_BLOCK;
return true;
}
else if (w==PIXY_START_WORDX)
{
Serial.println("reorder");
link.getByte(); // resync
}
lastw = w;
}
}
template <class LinkType> void TPixy<LinkType>::resize()
{
blockArraySize += PIXY_INITIAL_ARRAYSIZE;
blocks = (Block *)realloc(blocks, sizeof(Block)*blockArraySize);
}
template <class LinkType> uint16_t TPixy<LinkType>::getBlocks(uint16_t maxBlocks)
{
uint8_t i;
uint16_t w, checksum, sum;
Block *block;
if (!skipStart)
{
if (getStart()==false)
return 0;
}
else
skipStart = false;
for(blockCount=0; blockCount<maxBlocks && blockCount<PIXY_MAXIMUM_ARRAYSIZE;)
{
checksum = link.getWord();
if (checksum==PIXY_START_WORD) // we've reached the beginning of the next frame
{
skipStart = true;
blockType = NORMAL_BLOCK;
//Serial.println("skip");
return blockCount;
}
else if (checksum==PIXY_START_WORD_CC)
{
skipStart = true;
blockType = CC_BLOCK;
return blockCount;
}
else if (checksum==0)
return blockCount;
if (blockCount>blockArraySize)
resize();
block = blocks + blockCount;
for (i=0, sum=0; i<sizeof(Block)/sizeof(uint16_t); i++)
{
if (blockType==NORMAL_BLOCK && i>=5) // skip
{
block->angle = 0;
break;
}
w = link.getWord();
sum += w;
*((uint16_t *)block + i) = w;
}
if (checksum==sum)
blockCount++;
else
Serial.println("cs error");
w = link.getWord();
if (w==PIXY_START_WORD)
blockType = NORMAL_BLOCK;
else if (w==PIXY_START_WORD_CC)
blockType = CC_BLOCK;
else
return blockCount;
}
}
template <class LinkType> int8_t TPixy<LinkType>::setServos(uint16_t s0, uint16_t s1)
{
uint8_t outBuf[6];
outBuf[0] = 0x00;
outBuf[1] = 0xff;
*(uint16_t *)(outBuf + 2) = s0;
*(uint16_t *)(outBuf + 4) = s1;
return link.send(outBuf, 6);
}
template <class LinkType> int8_t TPixy<LinkType>::setBrightness(uint8_t brightness)
{
uint8_t outBuf[3];
outBuf[0] = 0x00;
outBuf[1] = 0xfe;
outBuf[2] = brightness;
return link.send(outBuf, 3);
}
template <class LinkType> int8_t TPixy<LinkType>::setLED(uint8_t r, uint8_t g, uint8_t b)
{
uint8_t outBuf[5];
outBuf[0] = 0x00;
outBuf[1] = 0xfd;
outBuf[2] = r;
outBuf[3] = g;
outBuf[4] = b;
return link.send(outBuf, 5);
}
#endif