Skip to content

Commit 6d716b8

Browse files
committed
Graceful shutdown
1 parent e795e17 commit 6d716b8

1 file changed

Lines changed: 58 additions & 25 deletions

File tree

deploy/src/main.jl

Lines changed: 58 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -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
3637
end
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+
3857
function 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, "\nCtrl-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
170203
end

0 commit comments

Comments
 (0)