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;
}