capi01 Custom Code


Custom startup shell script /home/pi/rpi-fb-matrix/run.sh

sudo /home/pi/rpi-fb-matrix/rpi-fb-matrix /home/pi/rpi-fb-matrix/matrix.cfg --led-rgb-sequence=rbg --led-slowdown-gpio=2 --led-gpio-mapping=adafruit-hat-pwm --led-pwm-bits=11 --led-scan-mode=1 --led-brightness=100

Start up code in /etc/rc.local

sudo /home/pi/rpi-fb-matrix/run.sh 2>&1 > /home/pi/fblog.log &
python /home/pi/motion.py
          

Motion Sensor PIR and RPI Camera code in /home/pi/motion.py


from gpiozero import MotionSensor
from picamera import PiCamera
import time

pir = MotionSensor(25)
camera = PiCamera()

while True:
    pir.wait_for_motion()
    if pir.motion_detected:
        #print("Person Detected")
        camera.start_preview(fullscreen=False,window=(900,496,128,128))
        #camera.start_preview()
        #for effect in camera.IMAGE_EFFECTS:
        #       camera.image_effect = effect
        #       camera.annotate_text = "Effect: %s" % effect
        time.sleep(10)
        camera.stop_preview()
        # Wait 10 seconds before repeating
        #time.sleep(10)

          

Rpi-fb-matrix matrix.cfg /home/pi/rpi-fb-matrix/matrix.cfg


// LED Matrix Display Configuration

// Define the entire width and height of the display in pixels.
// This is the _total_ width and height of the rectangle defined by all the
// chained panels.  The width should be a multiple of the panel pixel width (32),
// and the height should be a multiple of the panel pixel height (8, 16, or 32).
display_width = 128;
display_height = 128;

// Define the width of each panel in pixels.  This should always be 32 (but can
// in theory be changed).
panel_width = 64;

// Define the height of each panel in pixels.  This is typically 8, 16, or 32.
// NOTE: Each panel in the display _must_ be the same height!  You cannot mix
// 16 and 32 pixel high panels for example.
panel_height = 64;

// Define the total number of panels in each chain.  Count up however many
// panels are connected together and put that value here.  If you're using
// multiple parallel chains count each one up separately and pick the largest
// value for this configuration.
chain_length = 4;

// Define the total number of parallel chains.  If using the Adafruit HAT you
// can only have one chain so stick with the value 1.  The Pi 2 can support up
// to 3 parallel chains, see the rpi-rgb-led-matrix library for more information:
//   https://github.com/hzeller/rpi-rgb-led-matrix#chaining-parallel-chains-and-coordinate-system
parallel_count = 1;

// Configure each LED matrix panel.
// This is a two-dimensional array with an entry for each panel.  The array
// defines the grid that will subdivide the display, so for example a 64x64 size
// display with 32x32 pixel panels would be a 2x2 array of panel configurations.
//
// For each panel you must set the order that it is within its chain, i.e. the
// first panel in a chain is order = 0, the next one is order = 1, etc.  You can
// also set a rotation for each panel to account for changes in panel orientation
// (like when 'snaking' a series of panels end to end for shorter wire runs).
//
// For example the configuration below defines this grid display of panels and
// their wiring (starting from the upper right panel and snaking left, down, and
// right to the bottom right panel):
//       ______________    ______________
//      |    Panel     |  |    Panel     |
//   /==| order  = 1   |<=| order  = 0   |<= Chain start (from Pi)
//   |  | rotate = 0   |  | rotate = 0   |
//   |  |______________|  |______________|
//   |   ______________    ______________
//   |  |    Panel     |  |    Panel     |
//   \==| order  = 2   |=>| order  = 3   |
//      | rotate = 180 |  | rotate = 180 |
//      |______________|  |______________|
//
// Notice the chain starts in the upper right and snakes around to the bottom
// right.  The order of each panel is set as its position along the chain,
// and rotation is applied to the lower panels that are flipped around relative
// to the panels above them.
//
// Not shown but if you're using parallel chains you can specify for each entry
// in the panels list a 'parallel = x;' option where x is the ID of a parallel
// chain (0, 1, or 2).
panels = (
( { order = 1; rotate =   0; }, { order = 0; rotate =   0; } ),
( { order = 2; rotate = 180; }, { order = 3; rotate = 180; } )
)

// By default the rpi-fb-matrix tool will resize and scale down the screen
// to fit the resolution of the display panels.  However you can instead grab
// a specific pixel-perfect copy of a region of the screen by setting the x, y
// screen pixel coordinates below.  A rectangle of the exact size of the display
// (i.e. display_width x display_height pixels) will be copied from the screen
// starting at the provided x, y coordinates.  Comment this out to disable
// this crop behavior and instead resize the screen down to the matrix display.
#crop_origin = (736, 386)
crop_origin = (896,476)

          

Custom rpi-fb-matrix code /home/pi/rpi-fb-matrix/rpi-fb-matrix.cpp


// -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
// Program to copy the contents of the Raspberry Pi primary display to LED matrices.
// Author: Tony DiCola
#include <iostream>
#include <stdexcept>

#include "Adafruit_PixelDust.h"
#include "lis3dh.h"
#include <bcm_host.h>
#include <fcntl.h>
#include <led-matrix.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <signal.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <link.h>
#include "pixy.h"

#include "Config.h"
#include "GridTransformer.h"

using namespace std;
using namespace rgb_matrix;

#define BLOCK_BUFFER_SIZE    25

// Pixy Block buffer //
struct Block blocks[BLOCK_BUFFER_SIZE];


#define N_GRAINS (8*8*8) ///< Number of sand grains on 64x64 matrix
int     nGrains = N_GRAINS; // Runtime grain count (adapts to res)
Adafruit_LIS3DH      lis3dh;

uint8_t colors[][3] = { // Sand grain colors, 8 groups...
          0,  0,  0,   // Black
        120, 79, 23,   // Brown
        228,  3,  3,   // Red
        255,140,  0,   // Orange
        255,237,  0,   // Yellow
          0,128, 38,   // Green
          0, 77,255,   // Blue
        117,  7,135 }; // Purple

#define BG_RED    0 // Background color (r,g,b)
#define BG_GREEN 20
#define BG_BLUE  80

// Global to keep track of if the program should run.
// Will be set false by a SIGINT handler when ctrl-c is
// pressed, then the main loop will cleanly exit.
volatile bool running = true;

// Class to encapsulate all the logic for capturing an image of the Pi's primary
// display.  Manages all the BCM GPU and CPU resources automatically while in scope.
class BCMDisplayCapture {
public:
  BCMDisplayCapture(int width=-1, int height=-1):
    _width(width),
    _height(height),
    _display(0),
    _screen_resource(0),
    _screen_data(NULL)
  {
    // Get information about primary/HDMI display.
    _display = vc_dispmanx_display_open(0);
    if (!_display) {
      throw runtime_error("Unable to open primary display!");
    }
    DISPMANX_MODEINFO_T display_info;
    if (vc_dispmanx_display_get_info(_display, &display_info)) {
      throw runtime_error("Unable to get primary display information!");
    }
    cout << "Primary display:" << endl
         << " resolution: " << display_info.width << "x" << display_info.height << endl
         << " format: " << display_info.input_format << endl;
    // If no width and height were specified then grab the entire screen.
    if ((_width == -1) || (_height == -1)) {
      _width = display_info.width;
      _height = display_info.height;
    }
    // Create a GPU image surface to hold the captured screen.
    uint32_t image_prt;
    _screen_resource = vc_dispmanx_resource_create(VC_IMAGE_RGB888, _width, _height, &image_prt);
    if (!_screen_resource) {
      throw runtime_error("Unable to create screen surface!");
    }
    // Create a rectangular region of the captured screen size.
    vc_dispmanx_rect_set(&_rect, 0, 0, _width, _height);
    // Allocate CPU memory for copying out the captured screen.  Must be aligned
    // to a larger size because of GPU surface memory size constraints.
    _pitch = ALIGN_UP(_width*3, 32);
    _screen_data = new uint8_t[_pitch*_height];
  }

  void capture() {
    // Capture the primary display and copy it from GPU to CPU memory.
    vc_dispmanx_snapshot(_display, _screen_resource, (DISPMANX_TRANSFORM_T)0);
    vc_dispmanx_resource_read_data(_screen_resource, &_rect, _screen_data, _pitch);
  }

  void getPixel(int x, int y, uint8_t* r, uint8_t* g, uint8_t* b) {
    // Grab the requested pixel from the last captured display image.
    uint8_t* row = _screen_data + (y*_pitch);
    *r = row[x*3];
    *g = row[x*3+1];
    *b = row[x*3+2];
  }

  ~BCMDisplayCapture() {
    // Clean up BCM and other resources.
    if (_screen_resource != 0) {
      vc_dispmanx_resource_delete(_screen_resource);
    }
    if (_display != 0) {
      vc_dispmanx_display_close(_display);
    }
    if (_screen_data != NULL) {
      delete[] _screen_data;
    }
  }

private:
  int _width,
      _height,
      _pitch;
  DISPMANX_DISPLAY_HANDLE_T _display;
  DISPMANX_RESOURCE_HANDLE_T _screen_resource;
  VC_RECT_T _rect;
  uint8_t* _screen_data;
};

static void sigintHandler(int s) {
  running = false;
}

static void usage(const char* progname) {
    std::cerr << "Usage: " << progname << " [flags] [config-file]" << std::endl;
    std::cerr << "Flags:" << std::endl;
    rgb_matrix::RGBMatrix::Options matrix_options;
    rgb_matrix::RuntimeOptions runtime_options;
    runtime_options.drop_privileges = -1;  // Need root
    rgb_matrix::PrintMatrixFlags(stderr, matrix_options, runtime_options);
}

int main(int argc, char** argv) {
  try {
    // Initialize from flags.
    rgb_matrix::RGBMatrix::Options matrix_options;
    rgb_matrix::RuntimeOptions runtime_options;
    runtime_options.drop_privileges = -1;  // Need root
    if (!rgb_matrix::ParseOptionsFromFlags(&argc, &argv,
                                           &matrix_options, &runtime_options)) {
      usage(argv[0]);
      return 1;
    }

    // Read additional configuration from config file if it exists
    Config config(&matrix_options, argc >= 2 ? argv[1] : "/dev/null");
    cout << "Using config values: " << endl
         << " display_width: " << config.getDisplayWidth() << endl
         << " display_height: " << config.getDisplayHeight() << endl
         << " panel_width: " << config.getPanelWidth() << endl
         << " panel_height: " << config.getPanelHeight() << endl
         << " chain_length: " << config.getChainLength() << endl
         << " parallel_count: " << config.getParallelCount() << endl;

    // Set screen capture state depending on if a crop region is specified or not.
    // When not cropped grab the entire screen and resize it down to the LED display.
    // However when cropping is enabled instead grab the entire screen (by
    // setting the capture_width and capture_height to -1) and specify an offset
    // to the start of the crop rectangle.
    int capture_width = config.getDisplayWidth();
    int capture_height = config.getDisplayHeight();
    int x_offset = 0;
    int y_offset = 0;
    if (config.hasCropOrigin()) {
      cout << " crop_origin: (" << config.getCropX() << ", " << config.getCropY() << ")" << endl;
      capture_width = -1;
      capture_height = -1;
      x_offset = config.getCropX();
      y_offset = config.getCropY();
    }


    // Initialize matrix library.
    // Create canvas and apply GridTransformer.
    RGBMatrix *canvas = CreateMatrixFromOptions(matrix_options, runtime_options);
    if (config.hasTransformer()) {
      canvas->ApplyStaticTransformer(config.getGridTransformer());
    }
    canvas->Clear();
    FrameCanvas *offscreen_canvas = canvas->CreateFrameCanvas();
    int width = canvas->width();
    int height = canvas->height();
    int ii, i, xx, yy, zz, scale, bounce;
    char buf[128];
    int blocks_copied;
    dimension_t  sx, sy;
    dimension_t  x, y;
    int pxx = 0;
    int pyy = 0;

    if(width  < 64) nGrains /= 2; // Adjust sand count
    if(height < 64) nGrains /= 2; // for smaller matrices
    //if(lis3dh.begin()) {
    //      puts("LIS3DH init failed");
    //      return 2;
    //}

    pixy_close();
    int pixy_init_status = pixy_init();

    // Was there an error initializing pixy? //
    if(!pixy_init_status == 0)
    {
     // Error initializing Pixy //
        printf("pixy_init(): ");
        pixy_error(pixy_init_status);

        return pixy_init_status;
    }
    Adafruit_PixelDust        *sand = NULL;
    scale = 2;
    bounce = 64;
    sand = new Adafruit_PixelDust(width, height, nGrains, scale, bounce, false);
    if(!sand->begin()) {
           puts("PixelDust init failed");
           return 3;
    }

    //sand->randomize(); // Initialize random sand positions

    // Set up initial sand coordinates, in 8x8 blocks
    int n = 0;
    for(i=0; i<8; i++) {
         xx = i * width / 8;
         yy =  height * 7 / 8;
         for(y=0; y<8; y++) {
               for(x=0; x<8; x++) {
               sand->setPosition(n++, xx + x, yy + y);
               }
         }
    }

    // Initialize BCM functions and display capture class.
    bcm_host_init();
    BCMDisplayCapture displayCapture(capture_width, capture_height);

    // Loop forever waiting for Ctrl-C signal to quit.
    signal(SIGINT, sigintHandler);
    cout << "Press Ctrl-C to quit..." << endl;
    ii = 0;
    while (running) {
      // Read accelerometer...
      //lis3dh.accelRead(&xx, &yy, &zz);
      //sand->iterate(xx, -yy, zz);
      //printf("accelRead xx:%d yy:%d zz:%d\n", xx, yy, zz);

      //Read Pixy
      if(pixy_blocks_are_new() && running) {
                blocks_copied = pixy_get_blocks(BLOCK_BUFFER_SIZE, &blocks[0]);
                //printf("frame %d: bclocks_copied %d\n", ii, blocks_copied);
                int size = 0;
                for(i = 0; i != blocks_copied; ++i) {
                //      printf("  %s\n", buf);
                //      printf("sig:%d x:%d y:%d\n", blocks[i].signature, blocks[i].x, blocks[i].y);
                        //find and use the largest block
                        if ((blocks[i].width * blocks[i].height) > size) {
                                size = blocks[i].width * blocks[i].height;
                                //blocks[i].print(buf);
                                xx = blocks[i].x * 256;
                                yy = blocks[i].y * 256;
                                zz = 10240;
                                //printf("  %s xx:%d yy:%d\n", buf, xx, yy);
                        }
                }
                if(blocks_copied > 0){
                        ii++;
                        pxx = pixy_rcs_get_position(0);
                        pyy = pixy_rcs_get_position(1);
                        sand->iterate(xx, -yy, zz);
                        //printf("frame %d: bclocks_copied %d xx:%d -yy;%d\n", ii, blocks_copied, xx, -yy);
                }
      }
      // Capture the current display image.
      displayCapture.capture();
      // Loop through the frame data and set the pixels on the matrix canvas.
      for (int y=0; y<config.getDisplayHeight(); ++y) {
        for (int x=0; x<config.getDisplayWidth(); ++x) {
          uint8_t red, green, blue;
          displayCapture.getPixel(x+x_offset, y+y_offset, &red, &green, &blue);
          offscreen_canvas->SetPixel(x, y, red, green, blue);
        }
      }

      for(i=0; i<nGrains; i++) { // Sand...
        sand->getPosition(i, &sx, &sy);
        //printf("sand->getPosition i:%d x:%d y:%d\n", i, sx, sy);
        int n = i / 64; // Color index
        offscreen_canvas->SetPixel(sx, sy,
                         colors[n][0], colors[n][1], colors[n][2]);
      }


      offscreen_canvas = canvas->SwapOnVSync(offscreen_canvas);
      // Sleep for 25 milliseconds (40Hz refresh)
      //usleep(25 * 1000);
      // Sleep for 33.3 milliseconds (30HZ refresh)
      usleep(33.3 * 1000);

    }
    canvas->Clear();
    delete canvas;
  }
  catch (const exception& ex) {
    cerr << ex.what() << endl;
    usage(argv[0]);
    return -1;
  }
  return 0;
}