'gurobi.TimeLimit','20' should be 'gurobi.TimeLimit',20 ('20' works, but that is not official behavior)
What I am confused about is that you model x*y for binary y with only 1 constraint. That would require 2 constraints in most situations. Perhaps you have a model where 1 of the constraints will be satisfied by optimality, and you've proven that, but I would definitely keep the full model to give the MILP solver as much information as possible (redundant constraints are good for MILP solvers, as they might lead to improved relaxations)
and of course, you can simplify your code tremendously by dumping all the indexing
So, if you really want psi_w_plus to model pi*z_w_plus, the model would normally be
constraint = [constraint, BM_pi*z_w_plus >= psi_w_plus >= -BM_pi*z_w_plus];
constraint = [constraint, BM_pi*(1-z_w_plus) >= psi_w_plus-pi >= - BM_pi*(1-z_w_plus)];
constraint = [constraint, -BM_pi*z_w_minus <= psi_w_minus <= BM_pi*z_w_minus];
constraint = [constraint, -BM_pi*(1-z_w_minus) <= psi_w_minus-pi <= BM_pi*(1-z_w_minus)];
However, I am still wondering what it is you actually try to model, i.e., what kind of piecewise affine/quadratic structure is it you minimize, I'm slightly worried that you actually have a piecewise convex quadratic that you waste binary variables on