RoadShark's Bug Game Thread

General project help for Adafruit customers

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
adafruit_support_bill
 
Posts: 88093
Joined: Sat Feb 07, 2009 10:11 am

RoadShark's Bug Game Thread

Post by adafruit_support_bill »

Hi RoadShark - Let's continue the discussion started in your previous thread here: viewtopic.php?f=25&t=84806

User avatar
roadshark
 
Posts: 652
Joined: Sun Nov 29, 2015 5:53 am

Re: RoadShark's Bug Game Thread

Post by roadshark »

:) At the moment I am using 8 I/O pins on the itsy. Would it be simpler to drive the servos (2) directly from these if possible or am I better of using the servo driver shield on the mega.
Here is what I have coded so far for the master.

Code: Select all

#include <AccelStepper.h>
#include <MultiStepper.h>

#include <Adafruit_PWMServoDriver.h>
#include <Adafruit_LEDBackpack.h>
#include <Wire.h> // Enable this line if using Arduino Uno, Mega, etc.
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"
#include <SPI.h>
#include <Adafruit_VS1053.h>

int gameScore = 0;//Players score
int soundEffectPins[] = {22, 23, 24, 25, 26, 27, 28}; //22 is "Get Ready"  23 is "Game Over" 24 to 28 are bug whack sounds.
int bugWhackSensorPins[] = {29, 30, 31, 32, 33, 34};//29 is reset. Other pins are bugs
int ledStartSequencePins[] = {35, 36, 37, 38, 39};
int defTime = 30;
int state = 0;
int LimitSwitchPinHome [] = {40, 42, 44, 46, 48};
int LimitSwitchPinEnd [] = {41, 43, 45, 47, 49};
byte x = 0;
Adafruit_7segment matrixA = Adafruit_7segment();//Used to Display Score
Adafruit_7segment matrixB = Adafruit_7segment();//Used to Display countdown time

pinMode(LimitSwitchPinHome, INPUT_PULLUP);
pinMode(LimitSwitchPinEnd, INPUT_PULLUP);
pinMode(bugWhackSensorPins, INPUT_PULLUP);
pinMode(ledStartSequencePins, OUTPUT);
pinMode(soundEffectPins, OUTPUT);



void setup() {

  Wire.begin(); // join i2c bus


  // BugStepper class - derived from the AccelStepper class
  class BugStepper: public AccelStepper
  {
      // Add additional state variables here

      // BugStepper constructor - calls the base class AccelStepper constructor
      BugStepper(uint8_t pin1, uint8_t pin2, uint8_t pin3, uint8_t pin4, bool enable = true)
        : AccelStepper(AccelStepper::FULL4WIRE, pin1, pin2, pin3, pin4, enable)
      {
        // Add additional initialization here
      }

      // Add additional functions here
  }




}
uint32_t countdownTimeout;  // target end-time for the timeout.
void loop()
{
  switch (state)
  {
    case 0://Sets players score to 0. Puts 30 seconds on the clock.When reset button is pushed a sound effect is played.
      Wire.beginTransmission(8); // transmit to device #8
      Wire.beginTransmission(9); // transmit to device #9
      Wire.beginTransmission(10); // transmit to device #10
      matrixA.begin(0x70);
      matrixA.print(gameScore, DEC);
      matrixA.writeDisplay();
      //Displays timer
      matrixB.begin(0x71);
      matrixB.print(defTime);//Just puts 30 on the clock to indicate how many seconds in the round.
      matrixB.writeDigitNum(2, 0x10, true);//decimal point.
      matrixB.writeDisplay();
      if (digitalRead (29) == LOW)
      {
        digitalWrite((22), HIGH);//Play sound effect "Get Ready To Whack".
        state = 1;
      }
      break;

    case 1://LED start lighting sequence.
      for (int k = 0; k < ledStartSequenceCount; k++)//start of LED Start Sequence.
      {
        digitalWrite(ledStartSequence[k], HIGH);
        delay(500);
        digitalWrite(ledStartSequence[k], LOW);
      }

      // we are done with the startup light sequence
      countdownTimeout = millis() + 30 * 1000; // Initialize countdown timer
      state = 2; // transition to the next state
      break;

    case 2://Update the countdown timer and move the bugs
      if (countdownTimeout - millis() > 0) // keep going
      {
        int secondsRemaining = (countdownTimeout - millis()) / 1000;// display time remaining
        matrixB.begin(0x71);
        matrixB.print(secondsRemaining);
        matrixB.writeDigitNum(2, 0x10, true);//decimal point.
        matrixB.writeDisplay();
        // keep moving the bugs.

//bug scoring and link to sound effect player
        if ((digitalRead (30) == LOW) || (digitalRead (34) == LOW)) //bug whack indication pin bug 1 or 5
        {
          digitalWrite((24), HIGH);//Play sound effect s1 of bug getting squashed.
          playerScore = += 20;
        }
        if ((digitalRead (31) == LOW) || (digitalRead (33) == LOW)) //bug whack indication pin bug 2 and 4
        {
          digitalWrite((25), HIGH);//Play sound effect s2 of buggetting squashed.
          playerScore = += 50;
        }
         if((digitalRead (32) == LOW) //bug whack indication pin bug 3
      {
        digitalWrite((26), HIGH);//Play sound effect s3 bug getting squashed.
        playerScore = +=20
      }
      }
      else
      {
        //play game over sound and return bugs to home cave
        break;
      }
  }
}
I think an issue I might have is as there are two players, 2 bugs could be hit at the same or close to the same time. How to score this?

User avatar
adafruit_support_bill
 
Posts: 88093
Joined: Sat Feb 07, 2009 10:11 am

Re: RoadShark's Bug Game Thread

Post by adafruit_support_bill »

Would it be simpler to drive the servos (2) directly from these if possible or am I better of using the servo driver shield on the mega.
I suppose it could be done either way. If you have pins to spare, the slave could always point the bug in the direction the motor is moving.
I think an issue I might have is as there are two players, 2 bugs could be hit at the same or close to the same time. How to score this?
In your 'play' phase of the game (state 2) there are no delays or time consuming operations, so the master should be polling those switches at a good rate and should not miss much. If it does become a problem, we could look at solutions like pin-change interrupts.

User avatar
roadshark
 
Posts: 652
Joined: Sun Nov 29, 2015 5:53 am

Re: RoadShark's Bug Game Thread

Post by roadshark »

I think I have enough pins for the servo's to work of the itsy. The I/O pins I am using are for the motors Pins 5, 7, 9, 10 Limit pins A0, A1, A2, A3. I was planning to use Pins 11, 12 for servo 1 and pins A4 and A5 for servo two. Both servos use a commond Gnd pin on the itsy. Does the accelstepper library need to be on the master?
Is this piece of code is this how we send the data to the slaves?

Code: Select all

 //Send the bug moving information to the slaves
        Wire.beginTransmission(8); // transmit to device #8
        Wire.write("x is "); // sends five bytes
        x++;
        Wire.endTransmission();    // stop transmitting
        Wire.beginTransmission(9); // transmit to device #9
        Wire.write("x is ");        // sends five bytes
        Wire.endTransmission();    // stop transmitting
        x++;
        Wire.beginTransmission(10); // transmit to device #9
        Wire.write("x is ");        // sends five bytes
        Wire.endTransmission();    // stop transmitting
        x++;

User avatar
adafruit_support_bill
 
Posts: 88093
Joined: Sat Feb 07, 2009 10:11 am

Re: RoadShark's Bug Game Thread

Post by adafruit_support_bill »

Sounds like a good plan. No need for AccelStepper on the master, since it is not directly controlling any steppers.

And that is the way to talk to the slaves. Just replace the "x is " with something that the slave will understand.

User avatar
roadshark
 
Posts: 652
Joined: Sun Nov 29, 2015 5:53 am

Re: RoadShark's Bug Game Thread

Post by roadshark »

Just replace the "x is " with something that the slave will understand.
This is the bit I do not understand (among other things;)) I guess I have to define some sort of command the slave recognises to do something like move the motors forwards at half speed. For example 8 1 R 1R5
So Slave with the address of 8 motor 1 move R at moderate speed.
If the slave gets this command it would have to know that motor one is bugWacker1 and that R means to go right (normal direction) and that 1R5 means to move at 2000. This information would have to be defined in the set up?
I was thinking that maybe the slave (would it have enough memory seeing it has servo and accelstepper library) could already have this information in a program for example named PROG1. If it recieves this code from the master it executes the program like Motor one speed is 3000 Move to 2000 then turn servo and return and repeat until it receives notification from the master that the clock has run down so it goes home and re calibrates. Motor two does something similar.
If however it gets PROG2 it runs a similiar program with the difference being the speed parameter.
Or is this not how you do things. This is the code that I would use to communicate the slave with the master.

Code: Select all

void setup() {
   Wire.begin(8);                // join i2c bus with address #8
   Wire.onReceive(receiveEvent); // register event
   
}

void loop() {
   delay(100);
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany) {
   while (1 < Wire.available()) { // loop through all but the last
     char c = Wire.read(); // receive byte as a character
    
   }
   int x = Wire.read();    // receive byte as an integer
  
}

User avatar
adafruit_support_bill
 
Posts: 88093
Joined: Sat Feb 07, 2009 10:11 am

Re: RoadShark's Bug Game Thread

Post by adafruit_support_bill »

For example 8 1 R 1R5
So Slave with the address of 8 motor 1 move R at moderate speed.
The address is not part of the command string - since you have already specified the address in the beginTransmission:

Code: Select all

       Wire.beginTransmission(8); // transmit to device #8
If the slave gets this command it would have to know that motor one is bugWacker1 and that R means to go right (normal direction) and that 1R5 means to move at 2000. This information would have to be defined in the set up?
If you take a look at the 3-character codes I suggested earlier, the top-level command handling could look something like:

Code: Select all

void CommandHandler(char[] commandString)
{
    switch(commandString[1]) // second character is the actual command
    {
        case 'R':
        case 'L':
            MoveMotor(commandString); // move a motor
            break;
        case 'S':
            StopMotor(commandString);  // stop a motor
            break;
        case 'H':
            HomeMotor(commandString);  // home a motor
            break
    }
}
Then for each of the individual command handlers, you pull out the information you need to make the appropriate AccelStepper calls.

The MoveMotor command handler would look something like:

Code: Select all

void MoveMotor(char[] commandString)
{
    long distance = 5000; // default to moving right (positive number)
    if (commandString[1] == 'L')
    {
        distance = -5000;  //go negative for a left move
    }
    
    float speed = (commandString[0] - '0') * 500;  // set speed on a scale of 0-9
    
    switch(commandString[0]) // first character specifies the motor
    {
        case '1':
            bugWacker1.move(distance);
            bugwhacker2.setMaxSpeed(speed);
            break;
        case '2':
            bugWacker2.move(distance);
            bugwhacker2.setMaxSpeed(speed);
            break;
    }
}

User avatar
roadshark
 
Posts: 652
Joined: Sun Nov 29, 2015 5:53 am

Re: RoadShark's Bug Game Thread

Post by roadshark »

Wow! I will need a lot of coffee and munchies to unpack this!!

User avatar
roadshark
 
Posts: 652
Joined: Sun Nov 29, 2015 5:53 am

Re: RoadShark's Bug Game Thread

Post by roadshark »

Ok so we have 2 functions. CommandHandler and MoveMotor.
The commandString holds the values passed from the Master.
The first byte is either a 1 or 2 indicating the motor.
The second byte is either a L, R, S, or H. indicating what the motor is to do.
If the master sends this information
Wire.beginTransmission(8); // transmit to device #8
Wire.write(1 H); // sends two bytes
Wire.endTransmission(); // stop transmitting and the slave recieves
Wire.begin(8); // join i2c bus with address #8
Wire.onReceive(receiveEvent); // register event
void receiveEvent(int howMany) {
while (1 < Wire.available()) { // loop through all but the last
char c = Wire.read(); //
How does the slave take this information and make it into the command string??

User avatar
adafruit_support_bill
 
Posts: 88093
Joined: Sat Feb 07, 2009 10:11 am

Re: RoadShark's Bug Game Thread

Post by adafruit_support_bill »

Here is some (pre-coffee) code.

Code: Select all

// this function is registered as an event in setup()
void receiveEvent(int howMany) 
{
  char commandString[3];  //declare an array of (up to) 3 characters
  int index = 0;
  while (Wire.available()) 
  { 
    commandString[i++] = Wire.read(); // stuff next character into array
  }
  CommandHandler(commandString); //call the commandHandler with the completed string
}

User avatar
roadshark
 
Posts: 652
Joined: Sun Nov 29, 2015 5:53 am

Re: RoadShark's Bug Game Thread

Post by roadshark »

:) I assume this beverage will be sought after the Sunday morning pedal? The replacement itsy is in Australia. Hopefully it will read the usb.
The max speed I can get out of the motors is 4000.

[quote]float speed = (commandString[0] - '0') * 500; // set speed on a scale of 0-9[/quote
The lowest speed I would want the motors to travel (still experimenting) would be about 2000.

User avatar
adafruit_support_bill
 
Posts: 88093
Joined: Sat Feb 07, 2009 10:11 am

Re: RoadShark's Bug Game Thread

Post by adafruit_support_bill »

To scale the characters '0'-'9' to 2000-4000, you can use 'map'.

Code: Select all

float speed = map(commandString[2], '0', '9', 2000, 4000);

User avatar
roadshark
 
Posts: 652
Joined: Sun Nov 29, 2015 5:53 am

Re: RoadShark's Bug Game Thread

Post by roadshark »

Does this

Code: Select all

float speed = map(commandString[2], '0', '9', 2000, 4000);
Replace this

Code: Select all

float speed = (commandString[0] - '0') * 500; 
How do I go about coding the servo? As I am not using the servo driver shield like I originally intended but using the spare pins on the itsy I assume I do not need the associated library. So is this the way to go?

Code: Select all

/* Sweep
 by BANNED <http://BANNED.com>
 This example code is in the public domain.

 modified 8 Nov 2013
 by Scott Fitzgerald
 http://www.arduino.cc/en/Tutorial/Sweep
*/

#include <Servo.h>

Servo myservo;  // create servo object to control a servo
// twelve servo objects can be created on most boards

int pos = 0;    // variable to store the servo position

void setup() {
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
}

void loop() {
  for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
    // in steps of 1 degree
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(15);                       // waits 15ms for the servo to reach the position
  }
  for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(15);                       // waits 15ms for the servo to reach the position
  }
}
An argument I can use is that if the bugStepper1 is at 0 or home limit switch is Low then turn the servo 180 degrees.
If the bugStepper1 is at 2000 or the turn limit switch is low then turn the servo -180 degrees.

User avatar
adafruit_support_bill
 
Posts: 88093
Joined: Sat Feb 07, 2009 10:11 am

Re: RoadShark's Bug Game Thread

Post by adafruit_support_bill »

Does this
float speed = map(commandString[2], '0', '9', 2000, 4000);

Replace this
float speed = (commandString[0] - '0') * 500;
Yes.
How do I go about coding the servo?
You have the right idea. Just use the standard Arduino Servo library.

User avatar
roadshark
 
Posts: 652
Joined: Sun Nov 29, 2015 5:53 am

Re: RoadShark's Bug Game Thread

Post by roadshark »

Is this how to create my servos object
Servo bugWhack1servo; // create servo object to control a servo on motor 1 rail
Servo bugWhack2servo; // create servo object to control a servo on motor 2 rail


int pos = 0; // variable to store the servo position

void setup()
bugWhack1servo.attach(11); // attaches the servo on pin 11 to the servo object
bugWhack2servo.attach(A4)//attaches the servo on pin A4 to the servo object

Locked
Please be positive and constructive with your questions and comments.

Return to “General Project help”