Skip navigation
2015

In this post we will face some image processing technique, like blob analysys.

I will use the cvBlob library to detect blobs in the image capture by the raspicam

 

Step1: cvBlob installation

1.       Download cvBlob library from this link

               https://github.com/Steelskin/cvblob              

          and save it to

          /home/pi/cvblob

2.       Because I downloaded the zip file, I need to unzip it

               tar xvf cvblob-0.10.4-src.zip

3.       We need to make some bug fixing. So move to the source code directory

cd cvblob

cv cvBlob

and make the following  changes to

               a.       cvblob.h: at line 84 replace

const char cvChainCodeMoves[8][2] = { {0, -1},

with

const signed char cvChainCodeMoves[8][2] = { {0, -1},

               b.      cvlabel.cpp: at line 34 replace

const char movesSE[4][3][4] = <line continues...>

with

const signed char movesSE[4][3][4] = <line continues...>

               c.       cvlabel.cpp: at line 40 replace

const char movesI[4][3][4] = <line continues...>

with

const signed char movesI[4][3][4] = <line continues...>

4.       build cvBlob library

                    cd ..    

          cmake .    

          make

5.       and finally let's install the cvBlob library

               make install


Step2: develop an application that can detect blobs in images

  1. I firstly created some utility functions to capture images from RaspiCam. You can find such functions in raspistill.h and raspistill.c (everything is under development, so some code clean up may be required..). Thanks to raspistill functions, the main application is very easy to implement:
 raspistill_initialize(&state);     
raspistill_shot(&state, camera_callback);     
raspistill_terminate(&state);               


The raspistill_shot take a photo and invoke the camera_callback function. The only      parameter used by this function is an IplImage object that contains the captured image

2.       Next step is to implement functions for detecting blobs in the image. Such functions are implemented in the blobs.c and blobs.h functions. There are two functions currently implemented

detectBlobs(IplImage* image, struct ImageParams* imageParams)           


                  and        

detectBlobsWithImage(IplImage* image, struct ImageParams* imageParams)               


The second one shows the results of the image processing in a set of windows. So I'm going to use the latter for this demo because it's more impressive than some text output on a console. This function basically gets the images captured by the RaspiCam and creates an image (named segmentated) where the pixel whose color is inside the given RGB color range are white and the other pixels are black

IplImage* segmentated;
cvInRangeS(image, CV_RGB(155, 0, 0), CV_RGB(255, 130, 130), segmentated);







With the segmentated image, we can detect blobsIplImage* labelImg;CvBlobs blobs;

labelImg = cvCreateImage(cvGetSize(image), IPL_DEPTH_LABEL, 1);
 
result = cvLabel(segmentated, labelImg, blobs);

3.       Let's bring everything together and make  loop that periodically invoke the raspistill_shot function so that we can experiment with the camera and it's behavior in different light conditions

4.       Let's build application with the usual sequence of commands

                    cd build    

          cmake ..    

          make

Previously:

Sci Fi Your Pi - Prince Dakkar's patent log taking chart compass

Sci Fi Your Pi - Prince Dakkar's patent log taking chart compass - Functional Design

Sci Fi Your Pi - Prince Dakkar's patent log taking chart compass - Route selection and indication

Sci Fi Your Pi - Prince Dakkar's patent log taking chart compass - Direction of Travel Indicator 1

Sci Fi your Pi - Prince Dakkar's patent log taking chart compass - Current Position

Sci Fi your Pi - Prince Dakkar's patent log taking chart compass - GPS Test

Sci Fi your Pi - Prince Dakkar's patent log taking chart compass - Direction of Travel Indicator 2

Sci Fi Your Pi - Prince Dakkar's patent log taking chart compass - The end.......for now

 

So the winner has been announced this week - Sci Fi Your Pi: Winner Announced! and it was a well deserved win by the Meditech! by balearicdynamics. Even if i had more time I am not sure I would have been able to compete with this project or the other finalists there were some really amazing entries.


Seeing the announcement reminded me I said I would continue with the project despite the deadline having passed so here it is.. I have been working on this a little and have managed to get full direction of travel arrow circuit working.The system now takes the current position and lights an appropriate arrow(s) based on the direction to be traveled to the destination. in this below the arrows showing are South and East as I am North-West of the destination

 

013d10941f052df49733d4c3a0fe95d8531af64637.jpg

 

Currently the destination is fixed so the next stage is to work on adding the destination selection circuits to make this possible. I have added a test circuit to the breadboards to test the idea and added the map travel LEDs as well so i can test that functionality too.

 

010fc5bd9bc3161e5130d6a7f4bfb5ca1d7d79eb7d.jpg

01f89ec39ef4dd045935e5518b56ff94fcf921b5a2.jpg

So far I have set up the circuit and it uses a pair of jumper wires rather than the planned wheels to select the destination and start locations. The LEDs that represent the correct rout light up indicating the route to be taken. The next step is to also use this input to set the destination for the direction of travel arrow.

 

I may have made a little more progress but it was my birthday so I was a little distracted by a new arrival - a Raspberry PI touchscreen (and flotilla case from Pimoroni.

 

0133938f25be8675ec084e512ff3153469baf4309e.jpg

 

I was also a little distracted by my Abobo robot project a little while back I added a seven segment display mouth and decided it used too many pins. i spent a while soldering in a shift register but hadn't got around to getting it running again. This week AgoBo got his smile back .

 

01ddbbf9c36097fc697e4098da0d5a8df12dd0e06a.jpg

Previous posts for this project:

http://www.element14.com/community/community/design-challenges/sci-fi-your-pi/blog/authors/screamingtiger?ICID=BLOG-SciFiPi-challengers

 

I have been updating my code for the QuadCop in the GitHub.  I am new to Git Hub and many of my changes were not being committed.

 

https://github.com/screamingtiger/QuadCOP

 

So for anyone looking at the code it may make more sense now.  The ControlSwitch_32 was very outdated and missing the head control logic.

 

On Another note, I have some parts ordered!  I need a new camera and going with the Pi NoirPi Noir.

 

Im busy this week but next week its back on the project! Going to make a video of the sensor array in action, something I didn't get to before the challenge ended.

 

The head code is here.  It basically moves the head left and right, at a random point, at random times.  It only updates every few seconds.  It needs to be a bit more complex but I plan to use a 360 degree servo.

 

Keep in mind this code for the the ChipKit PiChipKit Pi

 

//A function that randomly moves the head around

void MoveHead()
{
  
    
 //SoftPWMServoServoWrite

        if(millis() - headLastUpdate > headDelay)      
 {
  
    if(headDirection == 0)
   headCurrentPWM -= headSpeedFactor;
  else
   headCurrentPWM += headSpeedFactor;

  if(random(1,10000) < 30)
                {
                  headDirection++;
                  headDirection %= 2;
                  headDelay=random(1,3) * 1000;
                  headSpeedFactor = random(1,6);
                  headSpeedFactor =10;
                }
                else  
                  headDelay = 10;
                  
                if(headCurrentPWM >= MAXPWM || headCurrentPWM <= MINPWM)
  {
                    
   if(headDirection == 0)
                        {
                            headDirection = 1;
                            headCurrentPWM = MINPWM + 10;
                        }
                        else
                        {
                            headDirection = 0;
                            headCurrentPWM = MAXPWM - 10;
                        }
                        
   headSpeedFactor = random(1,3) * 10;
;
                        
                        //headCurrentPWM = headStopPointPWM;
                        
                      
                           //Wait up to 3 seconds before moving again
                        headDelay = random(1,3);
                        headDelay *= 1000;
  
  }
                else
                {
                  
                        SoftPWMServoServoWrite(HEADSERVO,headCurrentPWM);
              headLastUpdate = millis();
                }

 }

}

Here is the ControlSwitch code I was using before the challenge ended.  Still messy.

#include <Wire.h>
#include <SoftPWMServo.h>


#define SERVODEADBAND 5
#define READPWMMAXDELAYLOW 30
#define READPWMMAXDELAYHIGH 20
#define MINPWM 1200
#define MAXPWM 2000
/*
PWM output to Flight controller (PWM write)
3 - Rx Channel 1 (Left and Right)
5 - Rx Channel 2 (forward and reverse)
6 - Rx Channel 3 (climb and dive)
9 - Rx Channel 4 (rotate left and right)
*/
//PWM outut from ChipKit to Flight Controller
#define FLIGHTCONTROL_X 0
#define FLIGHTCONTROL_Y 1
#define FLIGHTCONTROL_Z A0
#define FLIGHTCONTROL_R 3
//PWM output to Head Servo
#define HEADSERVO  A1

//PWM input from Rx to Chipkit.
#define RXCHANNEL1 8
#define RXCHANNEL2 9
#define RXCHANNEL3 10
#define RXCHANNEL4 11
#define RXCHANNEL6 13
#define RXCHANNEL5 12
//Output pins to RPi for auto and macro mode switching
#define RPIAUTOMODE   2
//Move MACROMODE to RPI Read
#define RPIMACROMODE  0
/***********************************************************************
 The SPEED definition is the amount to increment or decrement
 the PWM nuetral point in order to move in that direction.  
 In the case it is
 not enough to cuase movement due to wind or other issues,
 the code will increment slowly by FASTER or decrement by SLOWER
 which is a small value.  This will allow the quad to make
 small adjustments in order to compensate without being 
 over controlled. 
***********************************************************************/
#define SPEED  100 
#define STOP            1500
#define STOPHOVER       1800
#define MOVELEFT STOP-SPEED
#define MOVERIGHT STOP+SPEED
#define MOVEFORWARD STOP+SPEED
#define MOVEREVERSE STOP-SPEED
#define ROTATERIGHT STOP-SPEED
#define ROTATELEFT STOP+SPEED

//an integer to indicate directions

//Climbing and diving is done slower
#define MOVECLIMB  STOP+SPEED/2
#define MOVEDIVE  STOP-SPEED/2
#define SPEEDFACTOR 5
#define FASTER  SPEED/SPEEDFACTOR
#define SLOWER  (SPEED/SPEEDFACTOR)*-1

//Adjustment variables for block and controlbyte
#define  FORWARDADJUST 1
#define  REVERSEADJUST 2
#define  LEFTADJUST    3
#define  RIGHTADJUST   4
#define  CLIMBADJUST   5
#define  DIVEADJUST    6
#define  RRIGHTADJUST  7
#define  RLEFTADJUST   8
#define  ADJUSTFASTER  10
#define  ADJUSTSLOWER  20
//Global Variables
//Registers



//Speed Vars
int xSpeed = 0;
int ySpeed = 0;
int zSpeed = 0;
int rSpeed = 0;

//Servo pins for PWM output to the flight controller
bool autoMode = false;
bool autoModeInProgress = false;
bool manualModeInProgress = false;
bool forceManual = false;
bool serialOut = true;
bool macroMode = false;
bool macroModeInProgress = false;
bool forward = false;
bool reverse = false;
bool left = false;
bool right = false;
bool climb = false;
bool dive = false;
bool rLeft = false;
bool rRight = false;
bool controlByteChanged = false;
bool controlByteBad = false;
bool ledOn = false;
bool heartBeatChecked = false;
unsigned char controlByte;
unsigned char lastControlByte;
unsigned char temp;
char *r;


//NEW block method of sending data
#define STARTBLOCK 204
#define STOPBLOCK 190
#define RESETBLOCK 195
bool blockStarted = false;
int block[10];
int blockCounter = 0;
bool blockCompleted = false;
bool blockBlock = false;
int blockSkipped = 0 ;

//Head control variables
long headCurrentPWM = STOP;
int headSpeedFactor = 100;
int headDirection = 1;
long headLastUpdate = millis();
long headStopPointPWM = MAXPWM;
int headStopPoint = 0;
int headDelay = 5000;
int headDivFactor = 1;
//A function that randomly moves the head around

void MoveHead()
{
  
    
 //SoftPWMServoServoWrite

        if(millis() - headLastUpdate > headDelay)      
 {
  
    if(headDirection == 0)
   headCurrentPWM -= headSpeedFactor;
  else
   headCurrentPWM += headSpeedFactor;

  if(random(1,10000) < 30)
                {
                  headDirection++;
                  headDirection %= 2;
                  headDelay=random(1,3) * 1000;
                  headSpeedFactor = random(1,6);
                  headSpeedFactor =10;
                }
                else  
                  headDelay = 10;
                  
                if(headCurrentPWM >= MAXPWM || headCurrentPWM <= MINPWM)
  {
                    
   if(headDirection == 0)
                        {
                            headDirection = 1;
                            headCurrentPWM = MINPWM + 10;
                        }
                        else
                        {
                            headDirection = 0;
                            headCurrentPWM = MAXPWM - 10;
                        }
                        
   headSpeedFactor = random(1,3) * 10;
;
                        
                        //headCurrentPWM = headStopPointPWM;
                        
                     
                           //Wait up to 3 seconds before moving again
                        headDelay = random(1,3);
                        headDelay *= 1000;
  
  }
                else
                {
                 
                        SoftPWMServoServoWrite(HEADSERVO,headCurrentPWM);
              headLastUpdate = millis();
                }
 
 }
 
}

bool ControlByteCheck(unsigned char cb,unsigned char cbc)
{
 bool valid = true;
 ////////Serial1.print("CB: ");
 ////////Serial1.println(cb);
 ////////Serial1.print("CBC: ");
 ////////Serial1.println(cbc);
if(cb % 17 != cbc)
  valid =  false;
//Check for opposing motions, which may mean there is an issue
 //forward and reverse requested
 if(cb % 2 && (cb>>1) % 2)
  valid = false;
 //left and right requested
 if( (cb>>2) % 2 && (cb>>3) % 2)
  valid = false; 
 //rotate left and rotate right requested
 if((cb>>4) % 2 && (cb>>5) % 2)
  valid = false;
 //climb and dive requested
 if((cb>>6) %2 && (cb>>7) %2)
  valid = false;
return valid; 
 
 
 
}
inline int ParseControlByte()
{
 int cb = controlByte;
 rRight = false;
 rLeft = false;
 forward = false;
 reverse = false;
 left = false;
 right = false;
 climb = false;
 dive = false;

  if(cb & 1)
                {
   rRight = true;
                        rSpeed = ROTATERIGHT;
                }
  cb >>= 1;
                if(cb & 1)
                {
                        rLeft = true;
                        rSpeed = ROTATELEFT;
                }
                cb >>= 1;
                if(cb & 1)
                {
                        dive = true;
                        zSpeed = MOVEDIVE;
                }
                cb >>= 1;
                if(cb & 1)
                {
                        climb = true;
                        zSpeed = MOVECLIMB;
                }
                cb >>= 1;
                if(cb & 1)
                {
                        right = true;
                        xSpeed = MOVERIGHT;
                }
                cb >>= 1;
                if(cb & 1)
                {
                        left = true;
                        xSpeed = MOVELEFT;
                }
                cb >>= 1;
                if(cb & 1)
                {
                        reverse = true;
                        ySpeed = MOVEREVERSE;
                }
                cb >>= 1;
                if(cb & 1)
                {
                        forward = true;
                        ySpeed = MOVEFORWARD;
                }
                
                //Set default speeds here
                if(!forward && !reverse)
                    ySpeed = STOP;
                if(!left && !right)
                    xSpeed = STOP;
                if(!climb && !dive)
                    zSpeed = STOPHOVER;

}
void PrintDirections()
{
 ////Serial1.println("------------------------------");
//if(forward)
  ////Serial1.println("FORWARD");
 //if(reverse)
  //////Serial1.println("REVERSE");
 //if(left)
  //////Serial1.println("LEFT");
 //if(right)
  //////Serial1.println("RIGHT");
 //if(climb)
  //////Serial1.println("CLIMB");
 //if(dive)
  //////Serial1.println("DIVE");
 //if(rLeft)
  //////Serial1.println("RLEFT");
 //if(rRight)
  //////Serial1.println("RRIGHT");
        //////Serial1.println("------------------------------");


}


void I2CReceiveEventBlock(int numBytes)
{
        //Every 2 bytes are our data pairs, writes come in groups of 3
        unsigned char cb, cbc, reg;
 cb = Wire.receive();
 if(!blockBlock)
 {
  
                //Block Start
                if(cb == 204)
  {
   blockStarted  = true;
   blockCounter = 0;
   return;
  }
                //Block End
  if(cb == 190)
  {
   if(blockStarted)
   {
    blockStarted = false;
    blockCompleted = true;
    blockBlock = true;
    return;
   }
  }
                //Block Reset
                if(cb == 195)
                {
                   blockStarted = false;
                   blockCompleted = false;
                   blockCounter = 0;
                }
 
                //Data
  if(blockStarted)
  {
   block[blockCounter++] = cb;
   blockCounter %= 10;
  }
 }
        else
          blockSkipped++;
}

void ProcessBlock()
{
  int reg = block[0];
  if(reg == 22)
  {
    //heartbeat check
    heartBeatChecked = true;
  }
  else if(reg == 60)
  {
    if(ControlByteCheck(block[1],block[2]))
    {
      lastControlByte = controlByte;
      controlByte = block[1];
      controlByteChanged = true;
      controlByteBad = false;
    }
    else if(reg == 90)
    {
        //Speed Change
        //block[1] is the direction and block[2] is to indicate speedup or slowdown
        int direction = block[1];
        int adjust = 0;
        
        if(block[2] == ADJUSTFASTER)
          adjust = FASTER;
        if(block[2] == ADJUSTSLOWER)
          adjust = SLOWER;
        
        
        if(direction == FORWARDADJUST || direction == REVERSEADJUST)
          ySpeed += adjust;
        if(direction == LEFTADJUST || direction == RIGHTADJUST)
          xSpeed += adjust;
          
        if(direction == RRIGHTADJUST || direction == RLEFTADJUST)
          rSpeed += adjust;
          
        if(direction == CLIMBADJUST || direction == DIVEADJUST)
            zSpeed += adjust;
            
        controlByteChanged = true;
        controlByteBad = false;
        
          
          
          
    }
      controlByteBad = true;
  }
  else
    controlByteBad = true;
  blockBlock = false;
  
}


void setup()
{
 r = new char[20];
 
 //Random numbers for Head movement.
 randomSeed(analogRead(A1));
//if(serialOut)
  ////Serial1.begin(9600);
 ////Serial1.println("RESET");
 //Setup RPi input pins
//Setup PWM pins going to flight controller

 //Setup PWM input pins from RX
 pinMode(RXCHANNEL1,INPUT);
 pinMode(RXCHANNEL2,INPUT);
  pinMode(RXCHANNEL3,INPUT);
  pinMode(RXCHANNEL4,INPUT);
  pinMode(RXCHANNEL6,INPUT);
 pinMode(RXCHANNEL5,INPUT);
pinMode(RPIAUTOMODE,OUTPUT);
 pinMode(RPIMACROMODE,OUTPUT);
digitalWrite(RPIAUTOMODE,LOW);
 digitalWrite(RPIMACROMODE,LOW);
Wire.begin(40);
        Wire.onReceive(I2CReceiveEventBlock);
//Center all the servos
 SoftPWMServoServoWrite(HEADSERVO,STOP);
        SoftPWMServoServoWrite(FLIGHTCONTROL_X, STOP);
 SoftPWMServoServoWrite(FLIGHTCONTROL_Y, STOP);
        SoftPWMServoServoWrite(FLIGHTCONTROL_Z, MINPWM);
        SoftPWMServoServoWrite(FLIGHTCONTROL_R, STOP);
 
}

inline int ReadPWM2(int pin)
{
 unsigned long m1,m2;
 int d = 0;
 unsigned long functionStart = millis();
 //for(int i=0;i<2 && millis()-functionStart <= READPWMMAXDELAY;i++)
 //{ 
 //wait for the pin to go low
 while(digitalRead(pin) == HIGH && millis()-functionStart <= READPWMMAXDELAYLOW);
 while(digitalRead(pin) == LOW && millis()-functionStart <= READPWMMAXDELAYLOW);
 m1 = micros();
 while(digitalRead(pin) == HIGH && millis()-functionStart <= READPWMMAXDELAYLOW);
 m2 = micros();
 d = (m2-m1);
 //}
 
 //d /= 2;

 ////////Serial1.print("pin: ");
 ////////Serial1.println(pin);
//if(d < MINPWM || d > MAXPWM)
 //f d = 0;
if(millis() - functionStart <= READPWMMAXDELAYLOW)
 {
  ////////Serial1.println(d);
  return d;
 }
 else
 {
  ////////Serial1.println(0);
  return 0;
 }
}

char * CToS(unsigned char c)
{
  
  char temp[20]; 
  char t;
   int i = 0;
   
  while(c > 0)
 {
     t = c % 10;
     c = c  / 10;
     t = t + '0';
     temp[i] = t;
     i++;
 } 
 int q = 0;
 for(int j=i-1;j>=0;j--)
   r[q++] = temp[j];
 r[i] = 0;
return r;  
}
//More Global Vars for loop
int channel1;
int prevChannel1 = 0;
int channel2;
int prevChannel2 = 0;
int channel3;
int prevChannel3 = 0;
int channel4;
int prevChannel4 = 0;
int channel6;
int channel5;

unsigned int channel1Errors = 0;
unsigned int channel2Errors = 0;
unsigned int channel3Errors = 0;
unsigned int channel4Errors = 0;
unsigned int channel5Errors = 0;
unsigned int channel6Errors = 0;
bool servo1Removed = false;
char controlChar = 0;


void loop()
{
      ////Serial1.println("HERE");
 unsigned int a = 0;
        int channel6LastChecked = 0;
        
                             
        
 
 while(1)
 {
          ///////Serial1.println("Loop");
          //delay(100);
         // autoMode = false;
       //Move the Head.
 MoveHead();

 if(!autoMode || forceManual)
 {
  if(!manualModeInProgress)
  {
   //////Serial1.println("Entering Manual Mode");
   manualModeInProgress = true;
   autoModeInProgress = false;
  }
/*
                if(heartBeatChecked)
                {
                    //////Serial1.println("Heartbeat Checked");
                    heartBeatChecked = false;
                }
                if(controlByteChanged)
                {
                  //////Serial1.print("Bytes REceived: ");
                  //////Serial1.println(CToS(temp));
                  controlByteChanged = false;
                }
                */
  //Main manual mode logic
  if(channel1Errors < 50)
   channel1 = ReadPWM2(RXCHANNEL1);
  if(channel1 == 0)
   ;//channel1Errorsx++;
  else
   channel1Errors = 0;
 

  if(channel1Errors < 50 && channel1 != 0 && abs(prevChannel1 - channel1) > SERVODEADBAND)
  {
   //Serial1.print(prevChannel1); 
   //Serial1.print("---");
   //Serial1.println(channel1);
   //Serial1.println(abs(prevChannel1 - channel1));

   prevChannel1 = channel1;
   //velocityX.writeMicroseconds(channel1);
                        SoftPWMServoServoWrite(FLIGHTCONTROL_X, channel1);
                        servo1Removed = false;
  }
                else
                {
                  if(channel1Errors > 50)
                  {
                    if(!servo1Removed)
                    {
                        //Serial1.println("SERVO 1 REMOVED"); 
                        servo1Removed = true;
                    } 
                    else
                    {
                      channel1Errors++;
                      channel1Errors %= 5000;  //After 500 cycles see if the servo comes back up.
                    }
                  }
                }
  if(channel2Errors < 50) 
   channel2 = ReadPWM2(RXCHANNEL2);
  if(channel2 == 0) 
   ;//channel2Errors++;
  else
   channel2Errors = 0;
 
  if(channel2 != 0 && abs(prevChannel2 - channel2) > SERVODEADBAND)
  {
   SoftPWMServoServoWrite(FLIGHTCONTROL_Y, channel2);
   prevChannel2 = channel2;
  }
  if(channel3Errors < 50) 
   channel3 = ReadPWM2(RXCHANNEL3);
  if(channel3 == 0)
   ;//channel3Errors++;
  else
   channel3Errors = 0;
  if(channel3 != 0 && abs(prevChannel3 - channel3) > SERVODEADBAND)
  {
   SoftPWMServoServoWrite(FLIGHTCONTROL_Z, channel3);
   prevChannel3 = channel3;
  
  }
  if(channel4Errors < 50) 
   channel4 = ReadPWM2(RXCHANNEL4); 
  if(channel4 == 0)
   ;//channel4Errors++;
  else
   channel4Errors = 0;
  if(channel4 != 0 && abs(prevChannel4 - channel4) > SERVODEADBAND)
  {
   SoftPWMServoServoWrite(FLIGHTCONTROL_R, channel4);
   prevChannel4 = channel4;
  }

  channel6 = ReadPWM2(RXCHANNEL6);
  
  if(channel6 == 0 || channel6 >= STOP)
  {
   autoMode = true;
   digitalWrite(RPIAUTOMODE,HIGH);
  }
  else
  {
   if(channel5Errors < 50)
    channel5 = ReadPWM2(RXCHANNEL5);
   if(channel5 == 0)
   channel5Errors++;
   else
    channel5Errors = 0;
   if(channel5 > STOP)
   {
    macroMode = true;
    if(!macroModeInProgress)
    {
     digitalWrite(RPIMACROMODE,HIGH);
     //////Serial1.println("Entering Macro Record Mode.");
     macroModeInProgress = true;
    }
   }
   else
   {
    if(macroModeInProgress)
    {
     macroModeInProgress = false;
     macroMode = false;
     //////Serial1.println("Leaving Macro Record Mode.");
     digitalWrite(RPIMACROMODE,LOW); 
    }
   }
  }
 }
 else
 {
  //Main automode logic here
  if(!autoModeInProgress)
  {
   //////Serial1.println("Entering AUTOMODE");
   autoModeInProgress = true;
   manualModeInProgress =false;
   macroMode = false;
   digitalWrite(RPIMACROMODE,LOW);
   digitalWrite(RPIAUTOMODE,HIGH);
  }
  //automode get directions from Rpi
                //Do Testing
                
                         
                if(blockBlock &&   blockCompleted)
                {
                  ////////Serial1.println("BLOCK");
                  ProcessBlock();
                  //if(controlByteBad)
                    //////Serial1.println("BAD");
                  //else
                    //////Serial1.println("GOOD");
                  ////////Serial1.println(CToS(block[0]));
                  ////////Serial1.println(CToS(block[1]));
                  ////////Serial1.println(CToS(block[2]));
                  ////////Serial1.print("Skipped: ");
                  //////Serial1.println(blockSkipped);
                       
                }
  
  if(controlByteChanged)
  {
   controlByteChanged = false;
   ParseControlByte();
   //PrintDirections();

                            SoftPWMServoServoWrite(FLIGHTCONTROL_X, xSpeed);
                            SoftPWMServoServoWrite(FLIGHTCONTROL_Y, ySpeed);
                            SoftPWMServoServoWrite(FLIGHTCONTROL_Z, zSpeed);
                            SoftPWMServoServoWrite(FLIGHTCONTROL_R, rSpeed);

  }
                if(millis() - channel6LastChecked > 2000)
                {
          channel6 = ReadPWM2(RXCHANNEL6);
          if(channel6 != 0 &&  channel6 < STOP)
          {
              ////////Serial1.println(channel6); 
                     autoMode = false;
       digitalWrite(RPIAUTOMODE,LOW);
          }
                        channel6LastChecked =millis();
                }


}
 }
}


After some busy times, I finally have a weekend for working on this project


One of the ancillary parts of this project, is to make some blob analysis on the images captured by RaspiCam to detect laser beams. So I need install the OpenCV libraries and try to get images from RaspiCam inside a C program.

The idea is that an external application will command the autopilot subsystem (by means of MAVLink messages) and will detect reflected laser beams to start some special effect


So here are the steps to install OpenCV

 

1. Install RaspiCam. Installation procedure is very well described on Raspberry official site http://www.raspberrypi.org/archives/3890 Once installed, test it with this command:

raspistill -t 10000

2. Download the MMAL library aspivid/Raspistill source code from https://github.com/raspberrypi/userland .

3. Unzip the file and copy the directory userlan-master in /opt/vc. I also renamed the directory as "userland"

4.  Go to /opt/vc/userland and type

     sed -i ‘s/if (DEFINED CMAKE_TOOLCHAIN_FILE)/if (NOT DEFINED CMAKE_TOOLCHAIN_FILE)/g’ makefiles/cmake/arm-linux.cmake

5. create a build directory...

     sudo mkdir build

     cd build

6. ... and compile

     sudo cmake -DCMAKE_BUILD_TYPE=Release ..
     sudo
make
    
sudo make install

7. go to /opt/vc/bin and test one file typing : ./raspistill -t 3000



OK... now I'm ready to create a new project

 

1. create a new folder (/home/pi/vc) in your home directory

     mkdir cv
     cd cv

2. copy all raspicam apps source code

     cp /opt/vc/userland/host_applications/linux/apps/raspicam/*  .

     mv RaspiStill.c camcv.c

     sudo chmod 777 camcv.c

3. remove then content of CMakeLists.txt and replace with :
     cmake_minimum_required(VERSION 2.8)
     project( camcv )
     SET(COMPILE_DEFINITIONS -Werror)
     include_directories(/opt/vc/userland/host_applications/linux/libs/bcm_host/include)
     include_directories(/opt/vc/userland/interface/vcos)
     include_directories(/opt/vc/userland)
     include_directories(/opt/vc/userland/interface/vcos/pthreads)
     include_directories(/opt/vc/userland/interface/vmcs_host/linux)
     include_directories(/opt/vc/userland/interface/khronos/include)

     include_directories(/opt/vc/userland/interface/khronos/common)

     add_executable(camcv RaspiCamControl.c RaspiCLI.c RaspiPreview.c camcv.c RaspiText.c RaspiTexUtil.c gl_scenes/teapot.c gl_scenes/models.c gl_scenes/square.c gl_scenes/mirror.c gl_scenes/yuv.c gl_scenes/sobel.c tga.c)
     target_link_libraries(camcv /opt/vc/lib/libmmal_core.so /opt/vc/lib/libmmal_util.so /opt/vc/lib/libmmal_vc_client.so /opt/vc/lib/libvcos.so /opt/vc/lib/libbcm_host.so /opt/vc/lib/libGLESv2.so /opt/vc/lib/libEGL.so)

4. delete CMakeFiles directory if it exits
5. compile & test
     cmake .
     make
     ./camcv -t 1000


Great!!!
We are now ready to install OpenCV


1. install both dev lib and python lib. Even if I'm going to use pure C for development, Python is still useful for small scripts, so I recommend to install it.

     sudo apt-get update

     sudo apt-get install libopencv-dev
     sudo apt-get install python-opencv

2. to test if OpenCv library is well installed, write this test software. It just displays a picture using imread and imshow functions. You will need to provide a sample .jpg file. To compile using OpenCv lib, create a CMakeLists.txt file with the following lines

     cmake_minimum_required(VERSION 2.8)
     project( displayimage )
     find_package( OpenCV REQUIRED )
     add_executable( displayimage display_image.cpp )
     target_link_libraries( displayimage ${OpenCV_LIBS} )

3. compile and execute

     cmake .
     make
     ./displayimage

4. Modify your CMakeFiles.txt to include OpenCV library

     project( camcv )

     SET(COMPILE_DEFINITIONS -Werror)

     #OPENCV
     find_package( OpenCV REQUIRED )

     include_directories(/opt/vc/userland/host_applications/linux/libs/bcm_host/include)

     include_directories(/opt/vc/userland/interface/vcos)
     include_directories(/opt/vc/userland)
     include_directories(/opt/vc/userland/interface/vcos/pthreads)
     include_directories(/opt/vc/userland/interface/vmcs_host/linux)
     include_directories(/opt/vc/userland/interface/khronos/include)

     include_directories(/opt/vc/userland/interface/khronos/common)

     add_executable(camcv RaspiCamControl.c RaspiCLI.c RaspiPreview.c camcv.c RaspiText.c RaspiTexUtil.c gl_scenes/teapot.c gl_scenes/models.c gl_scenes/square.c gl_scenes/mirror.c gl_scenes/yuv.c gl_scenes/sobel.c tga.c)
     target_link_libraries(camcv /opt/vc/lib/libmmal_core.so /opt/vc/lib/libmmal_util.so /opt/vc/lib/libmmal_vc_client.so /opt/vc/lib/libvcos.so /opt/vc/lib/libbcm_host.so /opt/vc/lib/libGLESv2.so /opt/vc/lib/libEGL.so ${OpenCV_LIBS})

5. Recompile. It should be ok, because we didn't change anything in the source code

     make
     ./camcv

 

In next post I will make a basic application that can capture an image from RaspiCam and make some video processing using the power of the OpenCV library

My QuadCOP is fully repaired.  However there is appears to be one casualty, the Pi-Cam.

 

I am getting the infamous pi-cam error and all the normal workarounds are failing for me.  When the QuadCop "landed", the little eye/bubble on the head filled with water since it landed in a puddle.  Apparently sound sensors don't detect water real well.  I am not sure if that killed the cam or if the jolt from the ribbon being pulled out did.  I confirmed the ribbon is ok.  The little brown cable from the black camera you can see in the pic, I get the same error if I unplug it so I think the camera itself is shot, but the breakout board is functioning.

 

I plan to get more flights and continue, but I want to order another Pi Cam to get onboard video.  So stay tuned!  I also need to update my GitHub with some more mods I have been making to try to stabilize it.

 

 

IMG_20150914_232608329.jpg

Introduction

The Meditech project is moved to the further step 1. This will produce the formerly testing version of the device; this means a version enabled for testing with volunteers. To move the project and the prototype to the end of this step a series of essential upgrades has been focused playing on the actual version. While Meditech phase zero aimed to reach a full working prototype, despite of the aspect the testing version Meditech phase 1 will be the first full working prototype.

 

This introduction post points out the first series of changes that will be applied to the actual running prototype to set it as perfectly working in a test environment. Further improvements will be added to the internal architecture and the software component; the release date for the Phase 1 prototype version is expected around the mid - end of the month of October.

 

Display

The actual prototyped display was 15 inches so an external support was needed. The main issue of this display is its weight and the portability: the device and be easily put in-place but an extra transport bag is needed to carry it and this will reduce the usability of the system that should be set in the normal working conditions in a very short time.

IMG_20150909_113052.jpg IMG_20150909_113126.jpg

How the display actuallly fits and the back support.

 

The obvious solution mentioned in the posts related to the screen is a smaller 10" or 7" screen that will fit well hosted in the middle of the Meditech device when it is closed. The following image shows the free space for the display that is about 40x20 cm. A custom support should be created supporting the mechanics to slide it in the usage position.

IMG_20150909_113724.jpg

 

The newly announced <strong>7" touch screen for Raspberry PI</strong><strong>7" touch screen for Raspberry PI</strong> maybe a good solution also for the good price it is proposed on the market.

 

Control panel cover

In the first version of the prototype the control panel cover has been done with two half of soft 2mm plastic material. The following image shows how it is now; this simplified a lot the disposition of the components on the surface (the GPS and a couple of jack plugs are always missed in the image) as it is very simple to drill and cut.

IMG_20150909_113916.jpg

 

Then next version will be precisely cut and milled on a 1mm white Aluminium plate; the material is shown in the image below. This solve also the problem of labelling the plugs and signals: a full adhesive surface will be done and applied with the same material used to put the advertising images on the car surface. With the size of the surface this solution will be efficient at a very low cost (about 3-5 Euro)

IMG_20150909_114222.jpg

 

Cabling

As show in the following image the actual version is using common commercial cables that result very longer than needed. A series of custom cables will be wired saving a lot of space. Also the power distribution will be affected with a better single board circuit and all where it is possible the round cables will be replaced by flat ones.

IMG_20150909_113408.jpg

 

Internal devices and components

Also for the internal devices a strong revision will be provided.

IMG_20150909_113442.jpg

  • Make more reliable supports for the Raspberry PI Devices
  • Single-board including all the control panel components (fan control, IR controller, LCD, LEDs
  • Rationalise the power supply, powering the Raspberry PI via the GPIO connector instead the mini USB  plugs
  • Use flat cables all where is possible
  • Optimise the network cabling
  • Improve the door-open switch

Hello!

I'm one of those people who has been selected to participate in this exchange. Unfortunately, my involvement in it was close to zero. I did have a hard time fullfilling my obligations to Element14 community and the participants of this contest. I had external circumstances that made it quite problematic for me to participate, the most important being clinical depression, which I still feel like I'm yet to get rid of even though it's been a year since I started my medication. Unfortunately, a recession happened due to severe health issues of my girlfriend and it complicated nearly every aspect of my life, leading to me being almost dropped out of my university - thankfully, I got a last chance to reinstate and managed to do so. It had crippled my ability to manage my work as well as I thought I could when I was applying for this challenge. I apologise for letting you all down, and it's solely my fault.
That doesn't mean I've finished any work on my project. I have managed to put the interfacing part together and even exceed my own expectations of what it could become. What I have now is a framework that exposes a display and keypad combo to an arbitrary number of applications which can then make use of them. This makes it a simple yet effective control system for any Linux-driven device, from Raspberry Pi boards to desktops, routers and other Linux-running home appliances, and it's astonishingly cheap - I can add this system to anything for around 10$. You can write various applications for it, for example, one that lets you control your network interfaces or connect to WiFi, one that lets you read your Twitter feed, one that controls your home automation setup and one for general system control such as shutting down or rebooting the whole system. And I'll make it so that applications will be really simple to write, possibly producing a couple of general-purpose tools in the process =) I just wish I could have completed and presented it earlier, then think I could've had seen it being used in some of projects you guys have developed.
Right now, I have a LiIon-powered Raspberry Pi setup that I use both as my desktop computer (hey, I submitted this blog entry using it ;-) ) and a portable music player, and I have written an application that enables me to switch tracks and control volume of my music player. The next application I'll write will probably be a task manager, the one we use for keeping schedules and so on - or maybe a camera app, because as for now I don't have any appliance with a camera, except for my 5-year-old tablet with a 2MP one =) The system already has quite a lot of planning put in it, and I'll soon add lots of crucial elements facilitating application creation, as well as re-build parts of the system re-buildable before it's too late, since its functionality is already limited in some aspects compared to what it could achieve.
I plan on taking the next month off to work on it, and I'm sure I'll be posting my results here. See, I currently am bound contract that requires me to build a control system for 30 Modbus-controlled devices, operating them by a given scenario - as well as build a lot more of those devices =) Sure is a fun thing to implement in Python, and I'll get money which will allow me to live at least the next month without worrying much about money, which is what's necessary now for me to be able to fully dedicate my time to a project that requires as much work as this one. I'll be able to build a better enclosure for my PipBoy (cardboard just doesn't cut it, even if it's painted silver with spraypaint ;-) ), as well as finally let myself stuff it with all the electronics I've dreamt to put in it. I know I'm already outside all the terms, but I know this project is worth it and I feel obliged to finish it, not only because it's fun and useful, but also because I promised all of you to do so by my participation. So during the October, I'll be posting here in this competition blog, or elsewhere on the site if this blog gets closed.
Sorry, guys, no photos now, but I'll soon assemble a second system using a RPi and PiFaceCAD which will be able to take photos - using my system, of course =)

This past week finished up the Sci Fi Your Pi Design Challenge, and we saw a mass influx of final project updates being posted. Following the spirit of my Weekly Design Challenge Summary post, I wanted to make a post that would wrap up the Sci Fi Your Pi Design Challenge and showcase some of my favorite projects.

 

2015-08-31 20_55_39-Sci Fi Your Pi _ element14.jpg

 

To get started let’s take a quick look at each of the 25 Sci Fi Your Pi projects that captivated our imagination and inspired us over the last several months.

 

  • Project: Rover Pi Protector - Brenda Armour ( armour999 ) got off to a rough start with Rover Pi Protector after falling victim to a freak accident in her garage which resulted in some badly hurt arms. She did not let that stop her though, and in the end Rover Pi Protector was a success.
  • Project: Prince Dakkar's patent log taking chart compass - Neil Bizzell ( nbizzell ) cut it close with this project after life got in the way for most of the competition. However, Neil did manage to get a lot of work completed in the final week of the challenge. Neal did manage to get the GPS portion of the project up and running though, so that is a plus!
  • Project: Intelligent body Armor - Unfortunately this project by Joe Carender ( jlcarender ) was destined to become a no-starter and we never saw any progress post made past two very short postings.
  • Project: Advanced Dog Trainer - This project by Vivien Chin ( vivienchin ) , while great in concept, this project was a non-starter with not a single blog post being made.
  • Project: I Ching Hexagrams - Trevor Clarke’s ( taodude ) entry into the Sci Fi Your Pi challenge was a bit of a daunting one, but some great progress was made, and anyone who followed the updates definitely learned a thing or two. Unfortunately Trevor experienced lots of issues with the PiFaceCAD which costed him lots of valuable time.
  • Project: Escape the Past -  Eric Ellwanger ( frellwan ) set out to change the way the industrial world controls its equipment, with this project. By the end, he had managed to successfully send and receive data from an old-school PLC onto his Raspberry Pi, making it a very practical and useful project.
  • Project: Training Sphere - This was another project that got off to a late start due to its builder being part of the Enchanted Objects Challenge. Ambrogio Galbusera ( amgalbu ) set out to create the ultimate training sphere that would hone Jedi skills.
  • Project: Cybernetic Computer Interface - Never before has a project with so few updates managed to crank the WOW-Factor to 11. This wearable cybernetic device by Sebastian Groza ( sebathorus ) is the stuff borgs dream about!
  • Project: Picorder - Michael Hahn ( saturnv ) took Star Trek prop replication to the next level, and built his interpretation of what a TriCorder would be if it were around today! This project is one of my favorites and I recommend everyone check it out!
  • Project: C3P1 - This project was yet another no-starter with Augusto Lisbôa ( augusto.diniz.l ) only posting two short updates..
  • Project: Glove Computer & Control - Unfortunately this project never made it past the challenger announcement, and its builder deleted his user account.
  • Project: Empathy box - Despite being “really excited to begin this project,” Eric Lovejoy ( j0h ) never posted any project updates other than an intro where he talked about ordering some USB dongles and RGB LEDs for the project.
  • Project: Meditech - Enrico Miglino ( balearicdynamics ) knocked the ball out of the park with this medical-based project. With well over 20 updates, Meditech, is one of the most thoroughly documented, well written, and completed projects of the entire challenge. I highly suggest everyone take a few hours and read through this entire project!
  • Project: Knight Rider - This project by Wilson Oberholzer ( scrpn17w ) only saw a few updates.
  • Project: PizzaPi - Margot Paez ( dmrobotix ) set out to change the way pizza is delivered, and the end result is nothing short of amazing. This was one of the more regularly updated projects, and Margot’s enthusiasm and dedication to the project really shown through.
  • Project: Visus Sancto - This project by Cecil Perks ( sirusmage ) was another non-starter.
  • Project: PipBoy Personal Helper - Arsenijs Picugins ( crimier ) got off to a good start with two very well written blog post, but fell silent thereafter.
  • Project: PiBo - This project never made it past the first blog post by  Rajesh C ( kcrajesh ).
  • Project: Real-Life Holographic Projector - This was one of the projects that I was really excited to see progress, but unfortunately Kenny Rasschaert ( kenny_r ) did not make it past the first few post.
  • Project: Sci Fi Advanced Controls - Shrenik Shikhare  had a cool concept with this project, but unfortunately it never made it past the first post that showed off all of the hardware he received.
  • Project: Verbal & Physical Morality Monitor - This project by Harsahib Singh ( harsahib ) was a non-starter.
  • Project: VIRUS - Inderpreet Singh ( ipv1 ) suffered a delay during the build of this project, but despite the setback he still managed to work up a cool project. Bonus points from me for the use of 3D printing!
  • Project: QuadCOP - was one of those projects that saw a ton of updates, and really delivered in each update! Props to Joey Thompson ( screamingtiger ) for writing a wonderful series of updates, and teaching me a few things along the way.
  • Project: PiDesk- Much like Meditech, PiCorder, and a few other projects, PiDesk really turned out way above what I expected. Frederick Vandenbosch ( fvan ) built something that I can only describe as beautiful, and PiDesk is in my top three favorite projects from this design challenge
  • Project: RAED - Conceived by Jeremy Walker ( trenchleton ), this project got off to a good start, but quickly faltered when the update post stopped being posted.

 

With the projects covered I want to take a few moments to talk about my favorite top three projects. Please keep in mind that I am not a judge of this competition, and all of the projects that were submitted were amazing in their own right. These three projects are simply three of the ones that I enjoyed following the most. I truly enjoyed watching all of the projects progress, and I hope I see more from each contestant in the future.

 

Project: Meditech

 

Meditech-1024.jpg

If Enrico Miglino ( balearicdynamics ) set out to create one of the coolest projects that has ever been part of an Element14 Design Challenge, then he succeeded several times over. Enrico finished the core Meditech project weeks ago, and has continued posting updates ever since by building new accessories that augment the medical device. Great job Enrico!

 

 

Project: PiDesk

 

 

Frederick Vandenbosch ( fvan ) built one of the coolest desk I have ever seen, and as I said in my Weekly Design Challenge Summary, he inspired me to build my own desk over this winter season. From the use of Neo Pixels, to the design and integration of custom touch controls, this whole project was A+ quality!

 

 

Project: PiCorder

 

I would be lying if I said that I was not a bit of a closet Trekie, and Michael Hahn’s ( saturnv ) PiCorder build really brought out the geek in me. I have loved every aspect of this build, and it has really taught me that I need to focus more on getting my projects finished rather than making them 100% aesthetically perfect. From the use of protoboard as the front and rear panels, to using component leads as point to point jumpers makes this project super cool.

 

Well that is going to wrap up my coverage of the Sci Fi Your Pi Design Challenge until the judging process begins and winners are announced. I hope everyone enjoyed this challenge as much as I did, and I can not wait to see how the Vertical Farming design challenge turn out.