We used the open-cv python library to detect the green ball and the blue goalie by searching for pixels within a range of HSV values and storing the x and y coordinates of the largest collection of pixels. Pixel data from the camera is accessed using the cv2.VideoCapture function, as this made it easy to visualize the computer vision and to record positions. The ball and goalie positions are then used to determine the desired location of the goalie. Based on the distance between the actual and desired positions, different commands are sent to the ESP32 using the pyserial library.
Initial Desired Functionality
Knowing where to send the goalie was critical to the success of the entire project. Initially, we had the following (rather lofty goals):
Implement a trajectory estimator that included ball spin, friction, and (inelastic) collision with walls and players.
Plan the ideal collision angle (and possibly rotation speed) to maximize the chance of a counter-attacking goal.
Use PID on encoder data to control goalie location.
Final Implementation
We soon realized that our goals were both difficult and unnecessary. Ball collisions were highly inelastic and hard to predict, and shots that end up on target do not often involve bounces. Spin is extremely hard to track with computer vision, and due to friction, changes rapidly. Also, more accurate prediction models involve more computation time. Since we used python, our code already runs slower than we would like. So, we sought to minimize computational needs.
We thus implemented an LLSE regression between the x-position and y-position of the last 10 ball locations and predicted where the ball would cross the goalie line. This became our (unfiltered) desired goalie position. We added a saturation at the safe limits for the goalie to prevent motor stall when the goalie was physically blocked from moving further. Finally, ths desired position was only kept if the ball was moving towards our goal; otherwise, the desired position was simply the current ball position.
We opted against a PID controller, and instead used a Bang-Bang Control for our final implementation for three reasons:
Computation time: PID requires (slightly) more data processing. Bang-Bang requires less, although this was not the primary concern.
Serial communication issues: Running PID on the ESP32 required more data transfer than Bang-Bang, and some messages were being corrupted, causing major issues for the controller.
Oscillations: PID limited the oscillations, which is normally desired. The oscillations from Bang-Bang's overshoot, however, effectively made the goalie "bigger" since it blocked shots in the entire region of oscillation
We used an ESP32 for our microcontroller since we had one available and all had prior experience working with them. Two PWM output pins were connected to a DRV8833 stepper motor breakout board. The breakout board connects to the motor inputs and controls the encoder.
Excerpt from Pololu micro gearmotor #2215 TDS. https://www.pololu.com/product/2215
We opted for a timing belt design to actuate on our goalie. We used a GT2 timing belt from a 3D printer as these parts are cheap and widely available.
The timing belt was clamped to the back of the goalie using two M3 bolts and two zip ties. The pulley was then suspended between an idler and a timing pulley. The timing pulley was mounted onto a brushed DC motor and both the motor and idler were mounted to the foosball table using 3D printed mounts and a handful of wood screws and bolts. We also used a belt tensioner to keep the belt taught.
We assembled our table in Jacobs, using their 3D printers and drills to mount the motor and idler. We used two clamps to hold the table steadily in place under the camera
Our desired speed for our motor was 10cm/s. Our idler had a circumference of ~2cm, meaning we would need to achieve 5 rps = 300 rpm.
To keep costs low, we chose to use the 75:1 Pololu micro metal gearmotor. Whilst this costs $20 on their website, all MechE students are given these in our lab kits hence we were able to use components we already owned. An excerpt from the data sheet for this motor can be seen on the right, and you can see it is capable of achieving over 300rpm without excessive wear and tear.
To drive the motor, we used Pololu's complementary DRV8833. Again, these are provided in the MechE lab kit hence we saved cost by using components we already owned.