1414
1515#define IR_SENSOR_PIN GPIO_NUM_5 // IR receiver wire - GPIO5
1616
17- //DRV8833 input pins for one motor
1817#define MOTOR_IN1_PIN GPIO_NUM_18 // DRV8833 IN1 (forward)
1918#define MOTOR_IN2_PIN GPIO_NUM_16 // DRV8833 IN2 (reverse)
2019
2423#define DETECT_DELAY_MS 500 // wait time after ball detection
2524#define SPIN_TIME_MS 2000 // how long to spin the motor
2625
27- //server config
28- // change to your Raspberry Pi / game server IP
29- #define GOAL_SERVER_IP "???"
30-
31- #define GOAL_SERVER_PORT 30000
26+ #define GOAL_LISTEN_PORT 30000
3227
3328static const char * TAG = "IR_MOTOR" ;
3429
@@ -60,20 +55,20 @@ static void goalpost_led_pulse(int times)
6055//motor helper functions
6156static void motor_init (void )
6257{
63- // Configure motor pins as plain GPIO outputs
58+ //configure motor pins as plain GPIO outputs
6459 gpio_reset_pin (MOTOR_IN1_PIN );
6560 gpio_reset_pin (MOTOR_IN2_PIN );
6661 gpio_set_direction (MOTOR_IN1_PIN , GPIO_MODE_OUTPUT );
6762 gpio_set_direction (MOTOR_IN2_PIN , GPIO_MODE_OUTPUT );
6863
69- // Start with motor stopped (both low => coast)
64+ //start with motor stopped (both low => coast)
7065 gpio_set_level (MOTOR_IN1_PIN , 0 );
7166 gpio_set_level (MOTOR_IN2_PIN , 0 );
7267}
7368
7469static void motor_spin_forward (void )
7570{
76- // Spin the motor forward: IN1 = 1, IN2 = 0
71+ //spin the motor forward: IN1 = 1, IN2 = 0
7772 gpio_set_level (MOTOR_IN1_PIN , 1 );
7873 gpio_set_level (MOTOR_IN2_PIN , 0 );
7974}
@@ -84,11 +79,17 @@ static void motor_stop(void)
8479 gpio_set_level (MOTOR_IN2_PIN , 0 );
8580}
8681
87- //ir sensor functions
82+ //IR sensor functions
8883static void ir_sensor_init (void )
8984{
90- // Configure IR sensor as input with internal pull-up
91- // Adafruit break-beam receiver is open-collector and needs a pull-up.
85+ //configure IR sensor as input with internal pull-up
86+ //Adafruit break-beam receiver is open-collector and needs a pull-up.
87+ /*
88+ turns on the ESP32’s internal pull-up resistor because
89+ the Adafruit break-beam sensor has an open-collector output
90+ it basically pulls the line low when the beam is broken
91+ otherwise it floats and needs a pull-up
92+ */
9293 gpio_config_t io_conf = {
9394 .pin_bit_mask = (1ULL << IR_SENSOR_PIN ),
9495 .mode = GPIO_MODE_INPUT ,
@@ -107,31 +108,58 @@ static int ir_beam_broken(void)
107108}
108109
109110//network functions
110- static int connect_to_goal_server (void )
111+ static int wait_for_pi_connection (void )
111112{
112- struct sockaddr_in dest_addr ;
113- int sock = -1 ;
113+ int listen_sock = -1 ;
114+ int client_sock = -1 ;
115+ struct sockaddr_in listen_addr ;
116+ struct sockaddr_in source_addr ;
117+ socklen_t addr_len = sizeof (source_addr );
118+
119+ //create TCP socket
120+ listen_sock = socket (AF_INET , SOCK_STREAM , IPPROTO_IP );
121+ if (listen_sock < 0 ) {
122+ ESP_LOGE (TAG , "Unable to create socket: errno %d" , errno );
123+ return -1 ;
124+ }
114125
115- dest_addr . sin_addr . s_addr = inet_addr ( GOAL_SERVER_IP );
116- dest_addr . sin_family = AF_INET ;
117- dest_addr . sin_port = htons ( GOAL_SERVER_PORT );
126+ //allow quick reuse of the port if we reset
127+ int opt = 1 ;
128+ setsockopt ( listen_sock , SOL_SOCKET , SO_REUSEADDR , & opt , sizeof ( opt ) );
118129
119- sock = socket (AF_INET , SOCK_STREAM , IPPROTO_IP );
120- if (sock < 0 ) {
121- ESP_LOGE (TAG , "Unable to create socket: errno %d" , errno );
130+ //bind to all local interfaces on GOAL_LISTEN_PORT
131+ listen_addr .sin_family = AF_INET ;
132+ listen_addr .sin_port = htons (GOAL_LISTEN_PORT );
133+ listen_addr .sin_addr .s_addr = htonl (INADDR_ANY );
134+
135+ int err = bind (listen_sock , (struct sockaddr * )& listen_addr , sizeof (listen_addr ));
136+ if (err < 0 ) {
137+ ESP_LOGE (TAG , "Socket unable to bind: errno %d" , errno );
138+ close (listen_sock );
122139 return -1 ;
123140 }
124141
125- ESP_LOGI (TAG , "Connecting to %s:%d" , GOAL_SERVER_IP , GOAL_SERVER_PORT );
126- int err = connect (sock , (struct sockaddr * )& dest_addr , sizeof (dest_addr ));
127- if (err != 0 ) {
128- ESP_LOGE (TAG , "Socket unable to connect: errno %d" , errno );
129- close (sock );
142+ err = listen (listen_sock , 1 );
143+ if (err < 0 ) {
144+ ESP_LOGE (TAG , "Error during listen: errno %d" , errno );
145+ close (listen_sock );
130146 return -1 ;
131147 }
132148
133- ESP_LOGI (TAG , "Successfully connected to goal server" );
134- return sock ;
149+ ESP_LOGI (TAG , "Waiting for Raspberry Pi to connect on port %d..." , GOAL_LISTEN_PORT );
150+
151+ //block here until the client/Pi connects
152+ client_sock = accept (listen_sock , (struct sockaddr * )& source_addr , & addr_len );
153+ if (client_sock < 0 ) {
154+ ESP_LOGE (TAG , "Unable to accept connection: errno %d" , errno );
155+ close (listen_sock );
156+ return -1 ;
157+ }
158+
159+ ESP_LOGI (TAG , "Raspberry Pi connected!" );
160+
161+ close (listen_sock );
162+ return client_sock ;
135163}
136164
137165static void send_goal_to_server (int sock )
@@ -140,7 +168,7 @@ static void send_goal_to_server(int sock)
140168 return ;
141169 }
142170
143- // Follow the convention of messages ending with '|'
171+ //Follow the convention of messages ending with '|'
144172 const char * msg = "GOAL|\n" ;
145173 int len = strlen (msg );
146174
@@ -152,51 +180,54 @@ static void send_goal_to_server(int sock)
152180 }
153181}
154182
183+ /*
155184//goalpost task
156185void goalpost_mechanism_task(void *pvParameters)
157186{
158- // Hardware init
187+ //hardware init
159188 ir_sensor_init();
160189 motor_init();
161190 goalpost_led_init();
162191
163192 ESP_LOGI(TAG, "Goalpost mechanism starting...");
164193
165- // At this point Wi-Fi should already be up (wifi_setup_init was called in app_main)
166- // Now connect to the game server:
194+
195+ //wait for the Raspberry Pi to connect to us
167196 int sock = -1;
168197 while (sock < 0) {
169- sock = connect_to_goal_server ();
198+ sock = wait_for_pi_connection ();
170199 if (sock < 0) {
171- ESP_LOGW (TAG , "Retrying server connection in 2 seconds..." );
200+ ESP_LOGW(TAG, "Failed to get Pi connection, retrying in 2 seconds...");
172201 vTaskDelay(pdMS_TO_TICKS(2000));
173202 }
174203 }
204+
205+ int sock = -1;
175206
176207 ESP_LOGI(TAG, "Waiting for ball...");
177208
178209 while (true) {
179210 if (ir_beam_broken()) {
180- // Beam broken → "ball detected"
211+ //beam broken → "ball detected"
181212 ESP_LOGI(TAG, "Ball detected! Beam broken.");
182213 goalpost_led_pulse(3); // 3 quick blinks
183214
184215 vTaskDelay(pdMS_TO_TICKS(DETECT_DELAY_MS));
185216
186- // Spin the motor
217+ //spin the motor
187218 goalpost_led_set(1); // LED ON while spinning
188219 motor_spin_forward();
189220
190- // Notify server about the goal
191- send_goal_to_server (sock );
221+ //notify server about the goal
222+ // send_goal_to_server(sock);
192223
193224 vTaskDelay(pdMS_TO_TICKS(SPIN_TIME_MS));
194225
195- // Stop motor and LED
226+ //stop motor and LED
196227 motor_stop();
197228 goalpost_led_set(0);
198229
199- // Wait until beam is restored before re-arming
230+ //wait until beam is restored before re-arming
200231 while (ir_beam_broken()) {
201232 vTaskDelay(pdMS_TO_TICKS(50));
202233 }
@@ -207,10 +238,61 @@ void goalpost_mechanism_task(void *pvParameters)
207238 vTaskDelay(pdMS_TO_TICKS(50)); // small poll delay
208239 }
209240
210- // Not really reached, but for completeness:
241+ //cleanup on exit (never reached in this example)
211242 if (sock >= 0) {
212243 shutdown(sock, 0);
213244 close(sock);
214245 }
215246 vTaskDelete(NULL);
216247}
248+ */
249+
250+ //task for testing goalpost mechanism without wifi
251+ void goalpost_mechanism_task (void * pvParameters )
252+ {
253+ //hardware init
254+ ir_sensor_init ();
255+ motor_init ();
256+ goalpost_led_init ();
257+
258+ ESP_LOGI (TAG , "Goalpost HARDWARE TEST: no Wi-Fi sockets, just IR + motor" );
259+
260+ bool last_broken = false;
261+
262+ while (true) {
263+
264+ bool broken = ir_beam_broken ();
265+
266+ //log when the beam state changes
267+ if (broken != last_broken ) {
268+ ESP_LOGI (TAG , "IR beam is now: %s" , broken ? "BROKEN" : "OK" );
269+ last_broken = broken ;
270+ }
271+
272+ //trigger ONCE per break (edge trigger)
273+ if (broken ) {
274+ ESP_LOGI (TAG , "Ball detected! Spinning motor once." );
275+
276+ goalpost_led_pulse (3 ); // blink a bit
277+ goalpost_led_set (1 ); // LED ON while spinning
278+
279+ motor_spin_forward (); // turn motor ON
280+ vTaskDelay (pdMS_TO_TICKS (SPIN_TIME_MS ));
281+
282+ motor_stop (); // turn motor OFF
283+ goalpost_led_set (0 ); // LED OFF
284+
285+ ESP_LOGI (TAG , "Motor stopped, waiting for beam to restore..." );
286+
287+ // Wait until beam is no longer broken
288+ while (ir_beam_broken ()) {
289+ vTaskDelay (pdMS_TO_TICKS (50 ));
290+ }
291+
292+ ESP_LOGI (TAG , "Beam restored, re-armed." );
293+ }
294+
295+ vTaskDelay (pdMS_TO_TICKS (50 ));
296+ }
297+ }
298+
0 commit comments