@@ -30,11 +30,30 @@ mutable struct HardwareContext
3030 ain1:: GPIO.GPIOPin
3131 bin1:: GPIO.GPIOPin
3232 stby:: GPIO.GPIOPin
33+ ltrans_oe:: GPIO.GPIOPin
3334 pwm_chip:: PWM.PWMChip
3435 pwm_left:: PWM.PWMChannel
3536 pwm_right:: PWM.PWMChannel
3637end
3738
39+ """
40+ shutdown!(hw::HardwareContext)
41+
42+ Safely shutdown hardware: disable motors and level translator.
43+ Called on Ctrl-C or program exit.
44+ """
45+ function shutdown! (hw:: HardwareContext )
46+ println (Core. stdout , " Shutting down hardware..." )
47+ # Stop PWM first
48+ PWM. pwmWrite (hw. pwm_left, 0 , PWM_MAX_VALUE)
49+ PWM. pwmWrite (hw. pwm_right, 0 , PWM_MAX_VALUE)
50+ # Put motor controller into standby
51+ GPIO. set_value (hw. stby, 0 )
52+ # Disable level translator
53+ GPIO. set_value (hw. ltrans_oe, 0 )
54+ println (Core. stdout , " Hardware shutdown complete." )
55+ end
56+
3857function handle_err (ec)
3958 if ec == 0
4059 return
@@ -125,7 +144,7 @@ function (@main)(args)::Cint
125144 println (Core. stdout , " pwm startup done" )
126145
127146 # Create hardware context
128- hw = HardwareContext (gpio, ain1, bin1, stby, pwm_chip, pwm_left, pwm_right)
147+ hw = HardwareContext (gpio, ain1, bin1, stby, ltrans_oe, pwm_chip, pwm_left, pwm_right)
129148
130149 # Initialize I2C for IMU (bus 1, address 0x68)
131150 imu = MPU6000 (1 , 0x68 )
@@ -138,33 +157,47 @@ function (@main)(args)::Cint
138157 tenc_1a = ThreadedEncoder (Encoder (gpio, M1A))
139158 tenc_2a = ThreadedEncoder (Encoder (gpio, M2A))
140159
141- GPIO. set_value (ltrans_oe, 1 )
142- GPIO. set_value (stby, 1 ) # take the motor controller out of standby
143- apply_motor_output! (hw, 512.0f0 , 512.0f0 )
144- while true end
145- ctrl = BalanceController ()
146-
147- ml_update_rate_ns = 50000000
148- imu_read_margin = 12600000
149- println (Core. stdout , " start loop!" )
150- start = time_ns ()
151- while true
152- wait_until (start + ml_update_rate_ns - imu_read_margin)
153- put! (timu. request, true ) # trigger the IMU request
154- wait_until (start + ml_update_rate_ns)
155- imu_data = take! (timu. response)
156- enc_1_cnts = reset! (tenc_1a)
157- enc_2_cnts = reset! (tenc_2a)
158- command = balance_car! (ctrl, enc_1_cnts, enc_2_cnts,
159- imu_data. accel_x, imu_data. accel_y, imu_data. accel_z,
160- imu_data. gyro_x, imu_data. gyro_y, imu_data. gyro_z)
160+ # Disable default SIGINT handling so we can catch Ctrl-C
161+ ccall (:jl_exit_on_sigint , Cvoid, (Cint,), 0 )
162+
163+ try
164+ GPIO. set_value (hw. ltrans_oe, 1 )
165+ GPIO. set_value (hw. stby, 1 ) # take the motor controller out of standby
166+ apply_motor_output! (hw, 512.0f0 , 512.0f0 )
167+ while true end
168+ ctrl = BalanceController ()
169+
170+ ml_update_rate_ns = 50000000
171+ imu_read_margin = 12600000
172+ println (Core. stdout , " start loop!" )
161173 start = time_ns ()
162- if isnothing (command)
163- car_stop! (hw)
174+ while true
175+ wait_until (start + ml_update_rate_ns - imu_read_margin)
176+ put! (timu. request, true ) # trigger the IMU request
177+ wait_until (start + ml_update_rate_ns)
178+ imu_data = take! (timu. response)
179+ enc_1_cnts = reset! (tenc_1a)
180+ enc_2_cnts = reset! (tenc_2a)
181+ command = balance_car! (ctrl, enc_1_cnts, enc_2_cnts,
182+ imu_data. accel_x, imu_data. accel_y, imu_data. accel_z,
183+ imu_data. gyro_x, imu_data. gyro_y, imu_data. gyro_z)
184+ start = time_ns ()
185+ if isnothing (command)
186+ car_stop! (hw)
187+ else
188+ left, right = command
189+ apply_motor_output! (hw, left, right)
190+ end
191+ end
192+ catch e
193+ if e isa InterruptException
194+ println (Core. stdout , " \n Ctrl-C received, stopping..." )
164195 else
165- left, right = command
166- apply_motor_output! (hw, left, right )
196+ println (Core . stdout , " Error: " , e)
197+ rethrow (e )
167198 end
199+ finally
200+ shutdown! (hw)
168201 end
169202 return 0
170203end
0 commit comments