The new logic (Arduino) to a tennis ball machine

Hello
My Arduino project. Background information: I have owned for many years tennis ball machine: Ihr Tennis Partner. The machine model year is 1994 and it was at that time advanced. The machine has a programmable logic controller. Unfortunately, the device does not work and can not find wiring diagrams. The new logic is used to build the Arduino components.
The device has six electric motors:
2 DC motors, between which the ball travels.
4 AC motor: 1) a horizontal movement, 2) the vertical motion, 3) ballon feed motor and 4) balls collectibles engine.
In addition, the device has six pieces of reed relays, micro switch and etc ....
I approached the challenge by building a scale model. Scale model works just like a real tennis ball machines. This makes it easier to build functionality.

I post pictures of this project.

Arduino programming is new to me, but I am eager to learn new things. So far I have tested the functionality of the device. Next, I need to design the structure of the program. The aim is that the device can be operated manually and automatic (forecourt, top spin, backspin backcourt and etc ...)

Could I ask for your help, what should be taken into notice at this stage?

Scale model has 4 relays that control the horizontal movement, vertical movement, pass the ball, and the collection.

Reed relays are replaced by the MPU-6050 module (tested), which is measured in horizontal and vertical position. (the ball flies right direction and at the right height)

Ball feeder motor control used L298N Stepper DC Motor Driver Shield Expansion module (tested)

Normally, the device (real machine) is controlled by a wired remote control and rear of the machine. I would be interested blue tooth technology (limited range?), Or the wireless network. Was it sensible to control the device with your phone or tablet device?

Thanks for your help and advice!

Vesa P

5.jpg

1.jpg

3.jpg

programs are sequential logic.

I would offer that you have your 6 or so variations. top spin, fore court... etc. not knowing how they change all the parameters, I can only guess that the spins are done solely by motor/wheel speed, and fore and back court are by elevation for lofting shots, and motor speed to keep it closer to the net.

you could write a routine for each of these

forecourt()
top_motor_speed =
bottom_motor_speed=
elevation=
angle=
back_loft()
top_motor_speed =
bottom_motor_speed=
elevation=
angle=

to set the parameters.

you also have to do the ball verification bits. make sure that is in place.

I would think that you would then have the part of the sketch that would control timing and call the settings from above
it would be this part that you would have connected to your control panel or cell phone.
it is in this part of the sketch I would add all the randomity.

top_motor_speed = top_motor_speed + random_number_range1

some order of structure to keep the bits in locations you can find and adjust easily.

Thanks for your advice Dave. These are important to me.

I'll post attached file where is process description. This is the first version. When the device is operated automatically, whether the variables have a queue that are read. Forecourt, top_motor_speed, bottom_motor_speed, elevation, angle, etc ... (13,23,12,60, etc ..). Would it be so easier to update tennis drills?

Does anyone have a link on a simple code that directs the MPU-6050 module? and at this point I need to look for a suitable module, which controls the correct tennis ball machine to dc motors. The motor is a DC shunt design with a 200VDC and 180VDC armature field. The motor current is 0.52 / 0.08 Amps Which is quite low as the motor power is only 70 Watts. (for model I use L298N module) Any advice is welcome.

Any tips for mobile phone controlling are also welcome. Annikken andee ??

tennisballmachine.pdf (21.1 KB)

Try this MPU6050 tutorial

MPU6050 Library with examples

surbyte:
Try this MPU6050 tutorial

MPU6050 Library with examples

Thanks.

I tested the code. The code works. After the test, I started to feel a sense of Novice. I was left to reflect on what kind of loop I need to write. Vertical and horizontal movement controls by the relay. Motor which controls by the relay, rotates in only one direction. The objective is to that a certain value of the MPU-6050 x-axis and y-axis to stop the relay1 and relay2. First, read the value of the x-axis and switched off Relay 1 and the y-axis and the turn-off Relay2 off. Or can this happen in parallel?

I am grateful for your advice!

V

Hello again.

I designed the structure of the program. What do you think, am I on the right track? I was wondering tennis drill. Along with drill includes a 4-5 change of top_motor_speed, bottom_motor_speed, the elevation, angle and time. Loop?

void setup() {

}
void loop() {


choose_drill(); 
ball_stirrer_motor()
mpu_6050()

} 

void choose_drill() { //8 drill, every drill have 4-6 change
Case 1,2,3,4..8
Get parameters;
 	top_motor_speed = 
    	bottom_motor_speed=
    	elevation=
    	angle=
	time?=
}

Void mpu_6050_() {
	read mpu_6050
	activate parameters (x,y)
	void send_ball();
	time= time +1 (repeat?)
	stop
}
Void send_ball() {
	turn on ball selector
	adjust top_motor_speed
	adjust bottom_motor_speed
	adjust elevation
	adjust angle
	check time // drills duration
	read microswitch
	turn off ball selector

}
Void ball_stirrer_motor() {
	turn on ball_stirrer_selector
	turn off ball_stirrer_selector
}

}

Hello
I have made some progress in the project. However, I miss the ideas of the loop. I should take advantage of the MPU-6050 data. The MPU-6050 Matrix (quaternion values ​​in easy-matrix form: w x y z) I use w and x.
"Mpu.dmpGetQuaternion (& q, fifoBuffer);"
I get values ​​range from the x value: 0.00 - 0.18 and w: the value of 0.70 to 0.92. This is sufficiently accurate.
The aim is to:

  1. read q.w value and set Relay1 ON and stop it when the preset (eg. XPosition 0.07) is reached.
  2. read q.x value and set Relay2 ON and stop it when the preset (eg. YPosition 0.78) value is reached
  3. Starts program Forward Motor (motor speed); Which is set to "motor speed" value
  4. Launch relay3 and keep it on until the switch1 value = LOW. This spins the tennis ball into the chute.

In other words. I have values ​​eg. 0.07 (q.w), 0.78 (q.x), 128 (motorSpeed1), 255 (motorSpeed2). Half-height, rear left field, a little top spin ... :-). Next, read the new values ​​eg. 0.01,0.60,64,64. This can be repeated 4-5 times, new values ​​are read from the table?

As a beginner I would ask for your help. I have tried to resolve the matter, but I have not succeeded. I think that you have this simple tip or assistance.

I am grateful for the assistance

Show us your current code. What does it do when you run it? What do you want it to do different?

There it is. I have try first to IR-transmit.

// Tennisball machine 2016 first try
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
MPU6050 mpu;
//MPU6050 mpu(0x69); // <-- use for AD0 high
#define OUTPUT_READABLE_QUATERNION
#define LED_PIN 13 // (Arduino is 13, Teensy is 11, Teensy++ is 6)
bool blinkState = false;
#include <IRremote.h> // IR -library
#include <LiquidCrystal.h>

// MPU control/status vars
bool dmpReady = false;  // set true if DMP init was successful
uint8_t mpuIntStatus;   // holds actual interrupt status byte from MPU
uint8_t devStatus;      // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize;    // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount;     // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer

char inData[20]; // Allocate some space for the string
char inChar; // Where to store the character read
byte index = 0; // Index into array; where to store the character

// orientation/motion vars
Quaternion q;          
VectorInt16 aa;        
VectorInt16 aaReal;     
VectorInt16 aaWorld;    
VectorFloat gravity;    
float euler[3];         
float ypr[3];           

// packet structure for InvenSense teapot demo
uint8_t teapotPacket[14] = { '

, 0x02, 0,0, 0,0, 0,0, 0,0, 0x00, 0x00, '\r', '\n' };
volatile bool mpuInterrupt = false;     // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
   mpuInterrupt = true;
}

// motor one
int enA = 3;
int in1 = 38;
int in2 = 40;

// motor two
int enB = 4;
int in3 = 42;
int in4 = 44;

// variables button
int button1=30; // ball motors button
int button2=32; // ball stirrer motor button
int button3=34; // ball selector motor button

int xPosition = 0;
int yPosition = 0;
int buttonState = 0;

// Relay variables
int Relay1 = 22; //ball selector motor
int Relay2 = 24; //ball stirrer motor
int Relay3 = 28; //x-horisontal motor
int Relay4 = 26; //y-horisontal motor

// Ball selector variables
int switch1 = 46;
int SwitchStatus =HIGH;
int SwitchState=0;

// IR variables
int IRpin = 11;  // pin for the IR sensor
IRrecv irrecv(IRpin);
decode_results results;
int Relay1on = true; // initializing Relay1on as true
int Relay2on = true; // initializing Relay2on as true
int Relay3on = true; // initializing Relay3on as true, xPosition
int Relay4on = true; // initializing Relay4on as true, yPosition
int Motoron = true; // initializing Ballmotor on as true
int VerMotoron = true; // initializing Ballmotor on as true

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(5, 6, 7, 8, 9, 10 );

//DC motor variables
byte motorSpeed = 255;

void setup()
{

// join I2C bus (I2Cdev library doesn't do this automatically)
   #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
       Wire.begin();
       TWBR = 24; // 400kHz I2C clock (200kHz if CPU is 8MHz)
   #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
       Fastwire::setup(400, true);
   #endif
 
   Serial.begin(38400);
   while (!Serial); // wait for Leonardo enumeration, others continue immediately

// initialize device
   Serial.println(F("Initializing I2C devices..."));
   mpu.initialize();

// verify connection
   Serial.println(F("Testing device connections..."));
   Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));

// load and configure the DMP
   Serial.println(F("Initializing DMP..."));
   devStatus = mpu.dmpInitialize();

// supply your own gyro offsets here, scaled for min sensitivity
   mpu.setXGyroOffset(-75);
   mpu.setYGyroOffset(69);
   mpu.setZGyroOffset(-242);
   mpu.setZAccelOffset(1688); // 1688 factory default for my test chip

// make sure it worked (returns 0 if so)
   if (devStatus == 0) {
       // turn on the DMP, now that it's ready
       Serial.println(F("Enabling DMP..."));
       mpu.setDMPEnabled(true);

// enable Arduino interrupt detection
       Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)..."));
       attachInterrupt(0, dmpDataReady, RISING);
       mpuIntStatus = mpu.getIntStatus();

// set our DMP Ready flag so the main loop() function knows it's okay to use it
       Serial.println(F("DMP ready! Waiting for first interrupt..."));
       dmpReady = true;

// get expected DMP packet size for later comparison
       packetSize = mpu.dmpGetFIFOPacketSize();
   } else {
       
       Serial.print(F("DMP Initialization failed (code "));
       Serial.print(devStatus);
       Serial.println(F(")"));
   }
 // set all the motor control pins to outputs

digitalWrite(switch1, HIGH); //pull-up ball selector micro switch
 pinMode(enA, OUTPUT);
 pinMode(enB, OUTPUT);
 pinMode(in1, OUTPUT);
 pinMode(in2, OUTPUT);
 pinMode(in3, OUTPUT);
 pinMode(in4, OUTPUT);

pinMode(Relay1, OUTPUT);     //Set Pin22, Output Selector Motor Relay
 pinMode(Relay2, OUTPUT);     //Set Pin24, Output Stirrel Motor Relay
 pinMode(Relay3, OUTPUT);     //Set Pin28, Output Vertical Relay
 pinMode(Relay4, OUTPUT);     //Set Pin26, Output Horisontal Relay
 digitalWrite(Relay1, HIGH); // Set Relay1 off
 digitalWrite(Relay2, HIGH); // Set Relay2 off
 digitalWrite(Relay3, HIGH); // Set Relay3 off
 digitalWrite(Relay4, HIGH); // Set Relay4 off

// IR - staff
 
 //Serial.begin(9600);
 irrecv.enableIRIn(); // Start the receiver

// set up the LCD's number of columns and rows:
 lcd.begin(16, 2);
 // Print a message to the LCD.
 lcd.print(" Tennisblaster ");
 lcd.setCursor(0, 1);
 lcd.print("  ver. 1.0");
}
void loop()

{
     // if programming failed, don't try to do anything
   if (!dmpReady) return;

}

// reset interrupt flag and get INT_STATUS byte
   mpuInterrupt = false;
   mpuIntStatus = mpu.getIntStatus();

// get current FIFO count
   fifoCount = mpu.getFIFOCount();

// check for overflow (this should never happen unless our code is too inefficient)
   if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
       // reset so we can continue cleanly
       mpu.resetFIFO();
       Serial.println(F("FIFO overflow!"));

// otherwise, check for DMP data ready interrupt (this should happen frequently)
   } else if (mpuIntStatus & 0x02) {
       while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();

// read a packet from FIFO
       mpu.getFIFOBytes(fifoBuffer, packetSize);
       fifoCount -= packetSize;

#ifdef OUTPUT_READABLE_QUATERNION
           // display quaternion values in easy matrix form: w x y z
           mpu.dmpGetQuaternion(&q, fifoBuffer);
           Serial.print("quat\t");
           Serial.print(q.w);
           Serial.print("\t");
           Serial.println(q.x);
     
       #endif
   }
if (irrecv.decode(&results))
   {
     
     irrecv.resume();   // Receive the next value
   }
 
 switch(results.value) // IR-code
{

case 16724175:
 if (Relay1on == true)   // is Relay1on equal to true? Start BallselectorMotor
        {
          Relay1on = false;  
          digitalWrite(Relay1, HIGH);
          delay(100);      // keeps the transistion smooth
       }
       else
         {
           Relay1on = true;
           digitalWrite(Relay1, LOW);
           delay(200);}
      break;

case 16718055:
 if (Relay2on == true)   // is Relay2on equal to true? BallDropMotor
        {
          Relay2on = false;  
          digitalWrite(Relay2, HIGH);
          delay(200);      // keeps the transistion smooth    
        }  
       else
         {
           Relay2on = true;
           digitalWrite(Relay2, LOW);
           delay(200);}
      break;
     
 case 16720605: // In this case I need help.....Tennisdrills
 
     {
//      digitalWrite(Relay3, LOW); // xPositionMotorRelay
//      
//      digitalWrite(Relay3, LOW); //  yPositionMotorRelay
     }
      break;
}
 if (digitalRead(switch1)==LOW) {
   delay(500);
   digitalWrite(Relay1, HIGH); // Relay1 OFF
   Relay1on = false;
 }
   if (xPosition == (q.w)) {
 
   digitalWrite(Relay4, HIGH); // Relay1 OFF
   
 }

}
void MotorForward()
{
 digitalWrite(in1, HIGH);
 digitalWrite(in2, LOW);  
 digitalWrite(in3, LOW);
 digitalWrite(in4, HIGH);
 analogWrite(enA, motorSpeed);
 analogWrite(enB, motorSpeed);

}

void MotorStop()
{
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);  
  digitalWrite(in3, LOW);
  digitalWrite(in4, LOW);
  analogWrite(enA, 0);
  analogWrite(enB, 0);
}

            delay(200);}

Two mistakes right there:

  1. Don't put the closing brace } on the same line as actual code. Use the auto-format tool on the Tools menu to clean this up.

  2. Don't use delay(). It stops everything else in your program from working. Have a look at the BlinkWithoutDelay example that comes with the Arduino program. Make that move your motor instead of lighting an LED. See if you can understand how it runs the loop() at high frequency but still starts and stops at defined times.

Thanks.. Could loop be something like this:

  while (xPosition == (q.w)){
          digitalWrite(Relay3, LOW); // Keep Relay4 ON
       }
          digitalWrite(Relay3, HIGH); // Keep Relay4 OFF
       while (yPosition == (q.x)){
       digitalWrite(Relay3, LOW); // Keep Relay4 ON
       }
       digitalWrite(Relay3, HIGH); // Keep Relay4 OFF 
       motorSpeed1 = 255;
       motorSpeed2 = 255;
       MotorForward();

The new values x Position, Position, 1 Motor Speed Motor Speed ans should retrieve the table? Array [....]?

I try this code, but relay do not work. Any ideas.

case 16720605: // IR-button <<

xPosition=0.80; // Testing value
start=1;
while (q.w <= xPosition){
   if (start)
   {
      digitalWrite(Relay3, LOW);
      //Serial.print(q.w);
      Serial.print(xPosition);
      start=0;
    }

  }
     // reset interrupt flag and get INT_STATUS byte
  mpuInterrupt = false;
  mpuIntStatus = mpu.getIntStatus();
  // get current FIFO count
  fifoCount = mpu.getFIFOCount();
  // check for overflow (this should never happen unless our code is too inefficient)
  if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
  // reset so we can continue cleanly
  mpu.resetFIFO();
  Serial.println(F("FIFO overflow!"));
  // otherwise, check for DMP data ready interrupt (this should happen frequently)
  } else if (mpuIntStatus & 0x02) {
    // wait for correct available data length, should be a VERY short wait
    while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
    // read a packet from FIFO
    mpu.getFIFOBytes(fifoBuffer, packetSize);
  // track FIFO count here in case there is > 1 packet available
    // (this lets us immediately read more without waiting for an interrupt)
    fifoCount -= packetSize;

#ifdef OUTPUT_READABLE_QUATERNION 
    // display quaternion values in easy matrix form: w x y z
    mpu.dmpGetQuaternion(&q, fifoBuffer);
    Serial.print("quat\t");
    Serial.print(q.w);
    Serial.print("\t");
    Serial.println(q.x);

#endif
  
}
      digitalWrite(Relay3, HIGH);
      break;
  }

I got print
Quat 0.80 0.00
Quat 0.80 0.00
Quat 0.80 0.00

But relay3 is not LOW

Perhaps because you set it HIGH at the end of the code?

DrDiettrich:
Perhaps because you set it HIGH at the end of the code?

LOW means that motor is on, HIGH motor off. Is loops wrong?

Thanks