This guide provides step-by-step instructions for wiring a robot arm to your MATRIX Creator and then having that arm hit a gong whenever a Stripe sale or Slack command is received. It demonstrates how to use the GPIO pins of the MATRIX Creator to control a servo and how to receive a Slack or Stripe response to trigger the arm.
Required Hardware
Before you get started, let's review what you'll need.
- Raspberry Pi 3 (Recommended) or Pi 2 Model B (Supported) - Buy on Element14 - Pi 3 or Pi 2.
- MATRIX Creator - The Raspberry Pi does not have a built-in microphone, the MATRIX Creator has an 8 mic array perfect for Alexa - Buy MATRIX Creator on Element14.
- Micro-USB power supply for Raspberry Pi - 2.5A 5V power supply recommended
- Micro SD Card (Minimum 8 GB) - You need an operating system to get started. NOOBS (New Out of the Box Software) is an easy-to-use operating system install manager for Raspberry Pi. The simplest way to get NOOBS is to buy an SD card with NOOBS pre-installed - Raspberry Pi 16GB Preloaded (NOOBS) Micro SD Card. Alternatively, you can download and install it on your SD card.
- A USB Keyboard & Mouse, and an external HDMI Monitor - we also recommend having a USB keyboard and mouse as well as an HDMI monitor handy if you're unable to remote(SSH)into your Pi.
- Internet connection (Ethernet or WiFi)
- (Optional) WiFi Wireless Adapter for Pi 2 (Buy on Element14). Note: Pi 3 has built-in WiFi.
- Gong - You can use a bell or anything else that makes noise when hit - Buy on Amazon
- Robot Arm - we recommend the meArm because it is a simple robot arm with many degrees of motion - Buy Here
- Jumper Wires - used to connect the robot arm to the MATRIX Creator - Buy on Amazon
For extra credit, enable remote(SSH) into your device, eliminating the need for a monitor, keyboard and mouse - and learn how to tail logs for troubleshooting.
Let's get started
We will be using MATRIX CORE to program the Raspberry Pi and MATRIX Creator in Javascript by using its Protocol Buffers.
Step 1: Build your meArm
Follow this guide to build your meArm. (skip step 2 of the meArm guide)
Step 2: Setting up MATRIX CORE
Download MOS (MATRIX Open System) to get all the dependencies for MATRIX CORE on your computer using the following installation guide in the MATRIX Docs: Installation Guide
Step 3: Create the app folder and its files
In the directory that you choose create a folder called MATRIX-Gong-Master. Within that folder create three files names as follows: app.js, configure.json, and package.json.
Step 4: Configuration
The configure.json file is used to read your API Keys, server port, and slack channel to post in. Here is the code:
{
"apiKeys":{
"slack":"YOUR-BOT-USER-OAUTH-ACCESS-TOKEN",
"stripe":"YOUR-KEY-HERE"
},
"slackChannel": "#gong_master",
"serverPort": 6000
}
Follow Step 5 to retrieve your Slack access token and follow Step 6 to retrieve your Stripe key. Set the slackChannel to your desired channel to list all gong events and set the serverPort to the port you will be using to accept the requests.
Step 5: Slack Setup
To properly integrate Slack, a few minor edits need to be made before we insert the API Key.
1. Create a new Slack app and select which team you want to install it for.
2. Under features, click on slash commands to create a new command.
Set the Command to what you would like to type to trigger the arm in Slack.
Point the Request URL to http://YOUR-PUBLIC-IP:PORT/slack_events. You can find your Public IP here and you can learn how to port forward here.
Example of this below:
3. Once saved, go into Bot Users and set a username of your choice.
4. The next step for Slack is to go into OAuth & Permissions and allow the following under Scopes:
Send a bot with the username [your bot's name]
Post messages as [your bot's name]
Example of this below:
5. Slack is now configured to run your Gong Master! At the top of the page you'll find 2 API Keys. Copy the Bot User OAuth Access Token and paste it into your configure.json file. Example of the API keys below:
Step 5: Stripe Setup
1. If you do not already have a Stripe account register here and activate your account.
2. Go to API on the left side of the Stripe Dashboard and click Webhooks at the top.
3. Click Add endpoint on the right and type your URL that you will be received requests at as follows: http://YOUR-PUBLIC-IP:PORT/events. You can find your Public IP here and you can learn how to port forward here.
4. From there select the Webhook version you would like to use and press "Select types to send" where you will be able to select what event types you want to accept. In our case we will be using "charge.succeeded" and "invoice.payment_succeeded". Example of this below:
5. Stripe is now configured to send events to your URL. Go to the Webhook you just created click "Click to reveal" in the Signing Secret section to retrieve your API key to add to your configure.json file. Example of this below:
Step 6: Robot Arm Wiring
1. Using the jumper wires we are going to wire the bottom servo of the robot arm to the MATRIX Creator. First connect the Yellow servo wire to pin the pin on the MATRIX Creator labeled GP00.
2. Connect the Red servo wire to one of the pins on the MATRIX Creator labeled 5V. (there are two pins labeled 5V, either one will work)
3. Finally connect the Brown Servo wire to one of the pins on the MATRIX Creator labeled GND. (there are two pins labeled GND, either one will work)
Examples of this below:
Step 7: app.js Code Overview
Below all the code for the app.js file is reviewed. You can copy and paste it all or copy the file from the GitHub repo for the project here.
Global Variables
This is section defines and configures all the necessary libraries we need.
///////////////////////////
// Global Vars
///////////////////////////
var creator_ip = '127.0.0.1'//local ip
var creator_servo_base_port = 20013 + 32;//port to use servo driver.
var matrix_io = require('matrix-protos').matrix_io;//MATRIX protocol buffers
//Setup connection to use MATRIX Servos
var zmq = require('zmq');
var configSocket = zmq.socket('push')
configSocket.connect('tcp://' + creator_ip + ':' + creator_servo_base_port);
//Api keys
var fs = require("fs");
var userConfig = JSON.parse(fs.readFileSync(__dirname+'/configure.json'));
//Libraries
var stripe = require('stripe')(userConfig.apiKeys.stripe);
var request = require('request');
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
Set Servo Position
This function is meant to simplify moving a servo in MATRIX CORE. The pin for the servo used is set to 0, but it can be changed to any other pin freely with no errors.
///////////////////////////
// SET SERVO POSITION
//////////////////////////
function moveServo(angle){
//configure which pin and what angle
var servo_cfg_cmd = matrix_io.malos.v1.io.ServoParams.create({
pin: 0,
angle: angle
});
//build move command
var servoCommandConfig = matrix_io.malos.v1.driver.DriverConfig.create({
servo: servo_cfg_cmd
});
//send move command
configSocket.send(matrix_io.malos.v1.driver.DriverConfig.encode(servoCommandConfig).finish());
}
Gong Swing Timing
Using our previously defined function, for moving servos, this function is creating the swing motion that will be called when we want our Gong Master to use the gong. The variables above our function, gongsInQueue and gongInUse, are meant to allow the gong to handle multiple requests and to properly wait for each swing before swinging again.
///////////////////////////
// GONG SWING TIMING
//////////////////////////
var gongsInQueue = 0;//gongs requested
var gongInUse = false;//control swing usage
function gongMaster(){
setInterval(function() {
//checks for gongs queued and for current swing to stop
if(gongsInQueue > 0 && !gongInUse){
gongInUse = true;
gongsInQueue--;//lower queue amount by 1
moveServo(180);//swing gong arm
//delay for position transition
setTimeout(function(){
moveServo(90);//gong arm rest position
//delay for position transition
setTimeout(function(){
gongInUse = false;
},400);
},300);
}
},200)
}
Post Slack Message
Using your Slack API Key, a message can be posted to the slack channel set in configure.json.
///////////////////////////
// POST SLACK MESSAGE
//////////////////////////
function logToSlack(message){
request({
// HTTP Archive Request Object
har: {
url: 'https://slack.com/api/chat.postMessage',
method: 'POST',
headers: [
{
name: 'content-type',
value: 'application/x-www-form-urlencoded'
}
],
postData: {
mimeType: 'application/x-www-form-urlencoded',
params: [
{
name: 'token',
value: userConfig.apiKeys.slack
},
{
name: 'channel',
value: userConfig.slackChannel
},
{
name: 'link_names',
value: true
},
{
name: 'text',
value: message
}
]
}
}
});
}
Handle API Events
This function is where the events for the Slack and Stripe API are handled. Once either API is processed, gongsInQueue is increased to let the GongMaster() function know that it's time to gong!
///////////////////////////
// HANDLE API EVENTS
//////////////////////////
function processEvents(api, event){
//stripe events
if(api === 'stripe'){
if(event.type === 'charge.succeeded'){
if(event.data.object.status === 'paid'){
console.log('There was a charge for '+event.data.object.amount);
logToSlack("A Charge Has Occured");
gongsInQueue++;//gong once
}
}
else if(event.type === 'transfer.paid'){
if(event.data.object.status === 'paid'){
console.log('There was a transfer for '+event.data.object.amount);
logToSlack("A Transfer Has Occured");
gongsInQueue+=2;//gong twice
}
}
}
//slack event
else if(api === 'slack'){
//check that slack is sending a slash command event
if(typeof event.command !== 'undefined' && event.command !== null)
//check that the command is /gong
if(event.command === '/gong'){
gongsInQueue++;
logToSlack('@'+event.user_name+' has summoned me!');
}
}
//unhandled event
else{
console.log('I was not made to handle this event');
}
}
Server
The final part of the code is creating the server that listens to messages from Stripe and Slack. Once the server receives a message (POST Request) it will begin to make use of all the previously defined functions.
//////////////////////
// SERVER
/////////////////////
app.use(bodyParser.urlencoded({ extended: true })); //handle urlencoded extended bodies
app.use(bodyParser.json()); //handle json encoded bodies
//STRIPE POST Request Handling
app.post('/events', function(req, res) {
processEvents('stripe', req.body);//begin gong process
res.sendStatus(200);//evrything is okay
});
//SLACK POST Request Handling
app.post('/slack_events', function(req, res) {
//check that request is from slack (not guaranteed)
if( req.headers['user-agent'].indexOf('https://api.slack.com/robots') > 0){
processEvents('slack', req.body);//begin gong process
console.log("received request from slack");
res.send(req.body.user_name + ', Your Wish Has Been Gonged!');//response to user for /gong
}
//request is not from slack
else
res.send('You Have Angered The Gong Master!');
});
//Create Server
app.listen(userConfig.serverPort, function() {
console.log('Gong listening on port '+userConfig.serverPort+'!');
gongMaster();//listening for gong requests
});
Step 8: Code for package.json
This is the reference for all the libraries and scripts used in this project.
{
"name": "gong_master",
"version": "1.0.0",
"description": "robot gong that uses the slack and stripe api",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Carlos Chacin",
"license": "ISC",
"dependencies": {
"body-parser": "^1.17.2",
"express": "^4.15.4",
"matrix-protos": "0.0.13",
"request": "^2.81.0",
"stripe": "^4.24.1",
"zmq": "^2.15.3"
}
}
Step 9: Running the program
From the project directory run "node app.js" in the CLI to start the program.
To test in Slack, use the command you made and the Gong Master should respond to your request!
All code for the app can be found on GitHub here: https://github.com/matrix-io/MATRIX-Gong-Master















