Skip to content

Commit 9d2853d

Browse files
committed
Add pendulum visualisation
1 parent 1e3581d commit 9d2853d

1 file changed

Lines changed: 55 additions & 1 deletion

File tree

src/ppo/main.clj

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111
:tags [:physics :machine-learning :optimization :ppo :control]}}}
1212

1313
(ns ppo.main
14-
(:require [clojure.math :refer (PI cos sin)]
14+
(:require [clojure.math :refer (PI cos sin to-radians)]
15+
[clojure.core.async :as async]
16+
[quil.core :as q]
17+
[quil.middleware :as m]
1518
[libpython-clj2.require :refer (require-python)]))
1619

1720
(require-python '[torch :as torch])
@@ -203,3 +206,54 @@
203206
max-speed (:max-speed config)
204207
velocity (- (rand (* 2.0 max-speed)) max-speed)]
205208
(->Pendulum config (setup angle velocity))))
209+
210+
;; ### Visualisation
211+
;;
212+
;; The following method is used to draw the pendulum and visualise the motor control input.
213+
(defn draw-state [{:keys [angle]} {:keys [control]}]
214+
(let [origin-x (/ (q/width) 2)
215+
origin-y (/ (q/height) 2)
216+
length (* 0.5 (q/height) (:length config))
217+
pendulum-x (+ origin-x (* length (sin angle)))
218+
pendulum-y (- origin-y (* length (cos angle)))
219+
size (* 0.05 (q/height))
220+
arc-radius (* (abs control) 0.2 (q/height))
221+
positive (pos? control)
222+
tip-angle (if positive 225 -45)]
223+
(q/frame-rate frame-rate)
224+
(q/background 255)
225+
(q/stroke-weight 5)
226+
(q/stroke 0)
227+
(q/fill 175)
228+
(q/line origin-x origin-y pendulum-x pendulum-y)
229+
(q/stroke-weight 1)
230+
(q/ellipse pendulum-x pendulum-y size size)
231+
(q/no-fill)
232+
(q/arc origin-x origin-y (* 2 arc-radius) (* 2 arc-radius) (to-radians -45) (to-radians 225))
233+
(q/with-translation [(+ origin-x (* (cos (to-radians tip-angle)) arc-radius)) (+ origin-y (* (sin (to-radians tip-angle)) arc-radius))]
234+
(q/with-rotation [(to-radians (if positive 225 -45))]
235+
(q/triangle 0 (if positive 10 -10) -5 0 5 0)))
236+
(when (:save config)
237+
(q/save-frame "frame-####.png"))))
238+
239+
;; ### Animation
240+
;;
241+
;; The following method animates the pendulum and facilitates mouse control.
242+
(defn run []
243+
(let [done-chan (async/chan)
244+
last-action (atom {:control 0.0})]
245+
(q/sketch
246+
:title "Inverted Pendulum with Mouse Control"
247+
:size [854 480]
248+
:setup #(setup PI 0.0)
249+
:update (fn [state]
250+
(let [action {:control (min 1.0 (max -1.0 (- 1.0 (/ (q/mouse-x) (/ (q/width) 2.0)))))}
251+
state (update-state state action config)]
252+
(when (done? state config) (async/close! done-chan))
253+
(reset! last-action action)
254+
state))
255+
:draw #(draw-state % @last-action)
256+
:middleware [m/fun-mode]
257+
:on-close (fn [& _] (async/close! done-chan)))
258+
(async/<!! done-chan))
259+
(System/exit 0))

0 commit comments

Comments
 (0)