-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpytrain_simple.py
More file actions
212 lines (181 loc) · 6.37 KB
/
pytrain_simple.py
File metadata and controls
212 lines (181 loc) · 6.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# pytrain_simple.py
# v0.4
# https://github.com/zus2/PyTrain
#
# A simple Pybricks train motor controller - with a great controller handler
# for extra precise playability. Easy to customise simple logic.
# Auto detects all hubs and up to 2 motors, DC or Technic
#
# Tested with Pybricks v3.6.1 (Pybricks Code v2.6.0)
#
# © 2025 Paul Walsh
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. See LICENCE in the official repository.
#
"""
Instructions for use:
Use any hub
Install Pybricks from https://code.pybricks.com
Download, install and run pytrain_simple.py
Motor detection is automatic ( 1 or 2 motors, DC or Technic in port A and/or B )
Change the motor directions below to suit your train
Use left +/- and left center to control the train
Red light = stop , amber = ready , green = go and cyan = crawl
You can change the crawl speed below (DCMIN) and max (DCMAX)
Center red button once: stop the program and train instantly
Center red button hold 1 second: shut down the hub and controller
Run the program from your computer, or the hub - 2 clicks ! (switch the remote on promptly)
NB: DC stands for "duty charge" - train parlance for the power setting (%)
"""
# ----------
# --- User defined values
# ----------
DCMIN = 20 # min dc power (%) to move the train - crawl speed
DCMAX = 80 # max dc power (%) to keep train upright
DIRMOTORA = -1 # Hub motor A Direction clockwise 1 or -1
DIRMOTORB = 1 # Hub motor B Direction clockwise 1 or -1
STOP_DELAY = 400 # short pause when braked to zero DC
# ----------
# --- Main programme
# --- Do not change anything below here unless you are a programmer
# ----------
from pybricks.hubs import ThisHub
from pybricks.pupdevices import DCMotor, Remote, Motor
from pybricks.parameters import Button, Color, Direction, Port
from pybricks.tools import wait, StopWatch, run_task
from pybricks.iodevices import PUPDevice
def getmotors(motor):
"""
Check ports and auto add DC or Technic motors
Args:
motor(Motor()) - the motor object
"""
for x in (0,1):
port = (Port.A,Port.B)[x]
try:
device = PUPDevice(port)
id = device.info()["id"]
print("device",id,"on",x)
if device.info()["id"] < 3:
print("DC motor on",port)
motor.append(DCMotor(port,motordirection[x]))
else:
print("Motor on",port)
motor.append(Motor(port,motordirection[x]))
except OSError as err:
print("no device on",port)
motor.append("")
def controller():
INITIAL_DELAY = 350
REPEAT_DELAY = 100
watch = StopWatch()
dc = 0
while True:
#print(hub.battery.current())
pressed = ()
# Wait until a button is pressed.
while not pressed:
pressed = remote.buttons.pressed()
print(pressed)
dc = drive(pressed, dc)
# Wait until all buttons are released
# Or repeat if held down longer than INITIAL_DELAY
watch.reset()
while pressed:
if watch.time() > INITIAL_DELAY:
print(pressed)
dc = drive(pressed, dc)
wait(REPEAT_DELAY)
pressed = remote.buttons.pressed()
def drive(p, dc):
pressed = p
if Button.LEFT_PLUS in pressed:
if dc == 0: dc = DCMIN
elif dc < DCMAX: dc += 2
if abs(dc) < DCMIN*0.7: dc = 0
elif Button.LEFT_MINUS in pressed:
if dc == 0: dc = -DCMIN
elif dc > -DCMAX: dc -= 2
if abs(dc) < DCMIN*0.7: dc = 0
elif Button.LEFT in pressed:
hub.light.on(LED_STOP)
remote.light.on(LED_STOP)
"""
# hard stop
for m in motor:
if (m): m.stop()
dc = 0
"""
# gentle stop
while abs(dc) > 10:
dc = dc - 10 if dc > 0 else dc + 10
for m in motor:
if (m): m.dc(dc)
print(dc)
wait(150)
dc = 0
elif Button.CENTER in pressed:
# press once to stop the train AND the programme
# hold 2 secs to shutdown hub
print("remote center")
for m in motor:
if (m): m.dc(0)
count = 0
while Button.CENTER in pressed:
pressed = remote.buttons.pressed()
count+=1
if (count == 10): # 1 seconds ( plus brake in stop() )
print("Shutting down hub ...")
wait(100)
hub.system.shutdown()
wait(100)
raise SystemExit("Closing program..")
# send drive command to motors 1 and 2
for m in motor:
if (m): m.dc(dc)
if dc == 0:
hub.light.on(LED_STOP)
remote.light.on(LED_STOP)
# hard coded delay for added UX
wait(STOP_DELAY)
# orange for ready to move
hub.light.on(LED_READY)
remote.light.on(LED_READY)
elif abs(dc) == DCMIN:
hub.light.on(LED_CRAWL)
remote.light.on(LED_CRAWL)
else:
hub.light.on(LED_GO)
remote.light.on(LED_GO)
print(dc)
return dc
# --- set up hub
hub = ThisHub(broadcast_channel=None)
# You may not need to change these
LED_STOP = Color.RED*0.5
LED_GO = Color.GREEN*0.4
LED_CRAWL = Color.CYAN*0.5
LED_READY = Color.ORANGE*0.4
# --- clear terminal
print("\x1b[H\x1b[2J", end="")
print("Pytrain Simple - Train Controller")
print(hub.system.name())
print("---\nCell voltage:",round(hub.battery.voltage()/6000,2))
# --- set up remote
print ("Looking for remote ..")
try:
remote = Remote(timeout=15000)
except OSError as ex:
print ("Not found - shutting down ..")
wait(1000)
hub.system.shutdown()
# --- define motors - max 2 for CityHub
motor = []
motordirectionA = Direction.CLOCKWISE if DIRMOTORA == 1 else Direction.COUNTERCLOCKWISE
motordirectionB = Direction.CLOCKWISE if DIRMOTORB == 1 else Direction.COUNTERCLOCKWISE
motordirection = (motordirectionA , motordirectionB)
getmotors(motor)
###
# my new controller
run_task(controller())