On the receiving side, our RFM69 Feather M0 and Motor FeatherWing combo has two primary functions: listen for commands transmitted by the chess board system, and then driving the linear actuator's motor either forward or in reverse to open or close the drawer.
Here's the code you'll use below. Again, to use it, make a new document in the Arduino IDE, copy and paste the code, save it as chessBoardPuzzleLockRX.ino
and then upload it to the Feather M0.
//Chess Board Puzzle Lock RX // by John Park // Using Motor FeatherWing on Feather M0 RFM69HCW // to drive linear actuator based on remote commands /*************************** Libraries ******************************/ #include <RH_RF69.h> #include <SPI.h> #include <Adafruit_GFX.h> #include <RHReliableDatagram.h> #include <Wire.h> #include <Adafruit_MotorShield.h> /*************************** Motor Defines ******************************/ // Create the motor shield object with the default I2C address Adafruit_MotorShield AFMS = Adafruit_MotorShield(); // Select which 'port' M1, M2, M3 or M4. In this case, M1 Adafruit_DCMotor *myMotor = AFMS.getMotor(1); /*************************** Radio Defines ******************************/ // Change to 434.0 or other frequency, must match RX's freq! #define RF69_FREQ 915.0 #define RFM69_CS 8 #define RFM69_INT 3 #define RFM69_RST 4 // Where to send packets to! #define DEST_ADDRESS 2 // who am i? (server address) #define MY_ADDRESS 1 // Singleton instance of the radio driver RH_RF69 rf69(RFM69_CS, RFM69_INT); // Class to manage message delivery and receipt, using the driver declared above RHReliableDatagram rf69_manager(rf69, MY_ADDRESS); int16_t packetnum = 0; // packet counter, we increment per xmission #define LED_PIN 13 //use as a power ON indicator int drawerClosed = 1; //to keep track of state /*************************** Setup ******************************/ void setup() { Serial.begin(115200); //while (!Serial) { delay(1); } // wait for serial console to open. remove if not tethered to computer pinMode(LED_PIN, OUTPUT); digitalWrite(LED_PIN,HIGH); //AFMS.begin(); // create with the default frequency 1.6KHz AFMS.begin(1000); // OR with a different frequency, say 1KHz // Set the speed to start, from 0 (off) to 255 (max speed) myMotor->setSpeed(255); // turn on motor //open and close once on startup myMotor->run(FORWARD); delay(6000); myMotor->run(BACKWARD); delay(6000); myMotor->run(RELEASE); /////////////////////// radio /////////////////////// pinMode(RFM69_RST, OUTPUT); digitalWrite(RFM69_RST, LOW); Serial.println("Feather RFM69 RX Test!"); Serial.println(); // manual reset digitalWrite(RFM69_RST, HIGH); delay(10); digitalWrite(RFM69_RST, LOW); delay(10); if (!rf69_manager.init()) { Serial.println("RFM69 radio init failed"); while (1); } Serial.println("RFM69 radio init OK!"); // Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM (for low power module) if (!rf69.setFrequency(RF69_FREQ)) { Serial.println("setFrequency failed"); } // If you are using a high power RF69 eg RFM69HW, you *must* set a Tx power with the // ishighpowermodule flag set like this: rf69.setTxPower(20, true); // range from 14-20 for power, 2nd arg must be true for 69HCW // The encryption key has to be the same as the one in the server uint8_t key[] = { 0x05, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; rf69.setEncryptionKey(key); Serial.print("RFM69 radio @"); Serial.print((int)RF69_FREQ); Serial.println(" MHz"); } // Dont put this on the stack: uint8_t data[] = "Message recieved, thanks"; uint8_t buf[RH_RF69_MAX_MESSAGE_LEN]; /*************************** Loop ******************************/ void loop(void) { uint8_t i;//for motor speed if (rf69_manager.available()) { // Wait for a message addressed to us from the client uint8_t len = sizeof(buf); uint8_t from; if (rf69_manager.recvfromAck(buf, &len, &from)) { buf[len] = 0; // zero out remaining string Serial.print("\nGot packet from #"); Serial.print(from); Serial.print(" [RSSI :"); Serial.print(rf69.lastRssi()); Serial.print("] : "); Serial.println((char*)buf); char radiopacket[2]; if ( buf[0]=='A'){ //this is the unlock code Serial.println("Unlocked"); //turn the motor forward /////////////// if(drawerClosed==1){ Serial.println("Opening drawer"); myMotor->run(FORWARD); //ramp up the speed for (i=0; i<255; i++) { myMotor->setSpeed(i); delay(10); } //how long to run at top speed delay(2500); //this will vary depending on the throw of your actuator //ramp down the speed for (i=255; i!=0; i--) { myMotor->setSpeed(i); delay(10); } myMotor->run(RELEASE); drawerClosed=0;//prevents multiple open signals from being sent } // Send a reply back to the originator client if (!rf69_manager.sendtoWait(data, sizeof(data), from)) Serial.println("Sending failed (no ack)"); } else if ( buf[0]=='B'){//this is the lock code Serial.println("Locked"); //turn the motor backwards /////////////// if(drawerClosed==0){ Serial.println("Closing drawer"); myMotor->run(BACKWARD); //ramp up the speed for (i=0; i<255; i++) { myMotor->setSpeed(i); delay(10); } //how long to run at top speed delay(2500); //this will vary depending on the throw of your actuator //ramp down the speed for (i=255; i!=0; i--) { myMotor->setSpeed(i); delay(10); } myMotor->run(RELEASE); drawerClosed=1;//prevents multiple open signals from being sent } // Send a reply back to the originator client if (!rf69_manager.sendtoWait(data, sizeof(data), from)) Serial.println("Sending failed (no ack)"); } } }// if radio available delay(100); //prevent a flood }//end loop()
You can see in the code that the first thing it does upon power up or reset is to open and close the drawer once. This resets things to the ready position for the puzzle.
Then, rather than worry about the particular combinations of pieces on the chess board, it only receives two different commands. A letter 'A' means open the drawer, and a letter 'B' means close it!
You could add other behaviors if you like, including driving different motors, lights, sounds, and so on.
Text editor powered by tinymce.