Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ jobs:
fail-fast: true
matrix:
version:
- '1.6'
- 'nightly'
- '1.10'
- '1.12'
os:
- macos-13 # only for x86_64
- macos-latest # only for aarch64
Expand Down Expand Up @@ -50,8 +50,7 @@ jobs:
fail-fast: true
matrix:
version:
- '1.6'
- 'nightly'
- '1.10'
os:
- ubuntu-latest
arch:
Expand Down
10 changes: 7 additions & 3 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,25 @@ BangBang = "198e06fe-97b7-11e9-32a5-e1d131e6ad66"
FFMPEG = "c87230d0-a227-11e9-1b43-d7ebe4e7570a"
GLFW = "f7f18e0c-5ee9-5ccd-a5bf-e8befd85ed98"
Observables = "510215fc-4207-5dde-b226-833fc4488ee2"
PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d"
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"

[extensions]
VisualiserExt = ["BangBang", "FFMPEG", "GLFW", "Observables", "PrettyTables", "Printf", "StaticArrays"]
VisualiserExt = ["BangBang", "FFMPEG", "GLFW", "Observables", "Printf", "StaticArrays"]

[compat]
CEnum = "0.3, 0.4, 0.5"
julia = "1.6"
julia = "1.10"
LinearAlgebra = "1.6"
MuJoCo_jll = "3.1.6"
Requires = "1"
UnsafeArrays = "1"
StaticArrays = "1"
Observables = "0.5"
BangBang = "0.4"
FFMPEG = "0.4"
GLFW = "3"

[extras]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Expand Down
2 changes: 1 addition & 1 deletion docs/src/examples/humanoid_lqr.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ heights_mm = heights .* 1000
# Compare force to weight of humanoid
weight = sum(model.body_mass) * norm(model.opt.gravity)

fig = Figure(resolution=(500,300))
fig = Figure(size=(500,300))
ax = Axis(fig[1,1], xlabel="Vertical offset (mm)", ylabel="Vertical force (N)")
lines!(ax, heights_mm, u_vert, label="Vertical force")
lines!(ax, heights_mm, weight*ones(length(heights)), linestyle=:dash, label="Weight")
Expand Down
1 change: 0 additions & 1 deletion examples/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,5 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
MatrixEquations = "99c1a7ee-ab34-5fd5-8076-27c950a045f4"
MuJoCo = "1c101251-5e0f-4746-b44c-0728d433b68a"
Observables = "510215fc-4207-5dde-b226-833fc4488ee2"
PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d"
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
2 changes: 1 addition & 1 deletion examples/humanoid_lqr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ height = heights[argmin(abs.(u_vert))]
# Plot the relationship just to see - compare force to weight of humanoid
weight = sum(model.body_mass) * norm(model.opt.gravity)

fig = Figure(resolution=(600,400))
fig = Figure(size=(600,400))
ax = Axis(fig[1,1], xlabel="Vertical offsets (mm)", ylabel="Vertical force (N)")
lines!(ax, heights*1000, u_vert)
lines!(ax, heights*1000, weight*ones(length(heights)), linestyle=:dash)
Expand Down
2 changes: 0 additions & 2 deletions ext/VisualiserExt/VisualiserExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ if isdefined(Base, :get_extension)
using FFMPEG
using GLFW: GLFW, Window, Key, Action, MouseButton, GetKey, RELEASE, PRESS, REPEAT
using Observables: Observable, on, off
using PrettyTables: pretty_table
using Printf: @printf
using StaticArrays
using UnsafeArrays: UnsafeArray
Expand All @@ -33,7 +32,6 @@ else
using ..FFMPEG
using ..GLFW: GLFW, Window, Key, Action, MouseButton, GetKey, RELEASE, PRESS, REPEAT
using ..Observables: Observable, on, off
using ..PrettyTables: pretty_table
using ..Printf: @printf
using ..StaticArrays
using ..UnsafeArrays: UnsafeArray
Expand Down
131 changes: 129 additions & 2 deletions ext/VisualiserExt/functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ function writedescription!(io, hs::Union{Vector{EventHandler},Vector{<:NamedTupl

w1 = min(w1max, div(ncols, 2))
w2 = min(w2max, ncols - w1 - 4 * length(header)) # each column is padded by 4 spaces
pretty_table(
io, hcat(whens, whats);
custom_pretty_table(
io, whens, whats,
header=["Command", "Description"],
alignment = [:c, :l],
linebreaks = true,
Expand Down Expand Up @@ -212,3 +212,130 @@ function setpause!(ui::UIState, p::PhysicsState, status::Bool)
ui.paused = status
return ui
end

"""
custom_pretty_table(io, col1, col2; header=nothing, alignment=nothing, columns_width=nothing, kwargs...)

Custom implementation of pretty_table for backwards compatibility.
This function handles two-column tables with proper alignment and truncation.
Takes two vectors as input for the columns.
"""
function custom_pretty_table(io::IO, col1::AbstractVector, col2::AbstractVector;
header=nothing,
alignment=nothing,
columns_width=nothing,
linebreaks=false,
autowrap=false,
kwargs...)

# Ensure both columns have the same length
if length(col1) != length(col2)
error("custom_pretty_table requires both column vectors to have the same length")
end

nrows = length(col1)

# Set default column widths if not provided
if columns_width === nothing
_, terminal_cols = get_terminalsize()
# Reserve space for separators and padding: " | " = 3 chars
available_width = terminal_cols - 3
columns_width = [div(available_width, 2), div(available_width, 2)]
end

w1, w2 = columns_width

# Set default alignment if not provided
if alignment === nothing
alignment = [:l, :l] # left align both columns by default
end

# Helper function to truncate text to fit width
function truncate_text(text::AbstractString, width::Int)
if length(text) <= width
return text
else
return text[1:max(1, width-3)] * "..."
end
end

# Helper function to wrap text
function wrap_text(text::AbstractString, width::Int)
if !autowrap || length(text) <= width
return [truncate_text(text, width)]
end

lines = String[]
remaining = string(text)
while length(remaining) > width
# Find a good break point (space or punctuation)
break_point = width
for i in min(width, length(remaining)):-1:max(1, width÷2)
if remaining[i] in [' ', '\t', '-', ',', '.', ';', ':', '!', '?']
break_point = i
break
end
end

push!(lines, truncate_text(remaining[1:break_point], width))
remaining = lstrip(remaining[break_point+1:end])
end
if !isempty(remaining)
push!(lines, truncate_text(remaining, width))
end
return lines
end

# Helper function to align text within a given width
function align_text(text::AbstractString, width::Int, align::Symbol)
text = truncate_text(text, width)
if align == :c || align == :center
padding = width - length(text)
left_pad = div(padding, 2)
right_pad = padding - left_pad
return " "^left_pad * text * " "^right_pad
elseif align == :r || align == :right
return lpad(text, width)
else # :l or :left (default)
return rpad(text, width)
end
end

# Print header if provided
if header !== nothing && length(header) >= 2
col1_header = align_text(string(header[1]), w1, alignment[1])
col2_header = align_text(string(header[2]), w2, alignment[2])
println(io, col1_header * " | " * col2_header)

# Print separator line
sep1 = "-"^w1
sep2 = "-"^w2
println(io, sep1 * "-+-" * sep2)
end

# Print data rows
for i in 1:nrows
col1_text = string(col1[i])
col2_text = string(col2[i])

# Handle text wrapping
col1_lines = wrap_text(col1_text, w1)
col2_lines = wrap_text(col2_text, w2)

# Determine the number of lines needed for this row
max_lines = max(length(col1_lines), length(col2_lines))

# Print each line of the row
for line_idx in 1:max_lines
col1_line = line_idx <= length(col1_lines) ? col1_lines[line_idx] : ""
col2_line = line_idx <= length(col2_lines) ? col2_lines[line_idx] : ""

col1_aligned = align_text(col1_line, w1, alignment[1])
col2_aligned = align_text(col2_line, w2, alignment[2])

println(io, col1_aligned * " | " * col2_aligned)
end
end

return nothing
end
4 changes: 2 additions & 2 deletions ext/VisualiserExt/util.jl
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ function startffmpeg(w::Integer, h::Integer, rout::Integer; squashoutput::Bool =
FFMPEG.@ffmpeg_env begin
indata = Base.PipeEndpoint()
if squashoutput
p = Base._spawn(`$(FFMPEG.ffmpeg) $arg`, Base.SpawnIO[indata, devnull, devnull])
p = Base._spawn(`$(FFMPEG.ffmpeg) $arg`, Base.Redirectable[indata, devnull, devnull])
else
p = Base._spawn(`$(FFMPEG.ffmpeg) $arg`, Base.SpawnIO[indata, stdout, stderr])
p = Base._spawn(`$(FFMPEG.ffmpeg) $arg`, Base.Redirectable[indata, stdout, stderr])
end
p.in = indata
return p, dst
Expand Down
49 changes: 23 additions & 26 deletions src/MuJoCo.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ using .LibMuJoCo
# Re-export non polluting symbols of LibMuJoCo
begin
exported_prefixes = ["mj_", "mju_", "mjv_", "mjr_", "mjui_", "mjd_", "mjp_", "mjr", "mjt"]
for name in names(LibMuJoCo; all = true)
for name in names(LibMuJoCo; all=true)
name_str = string(name)
if any(startswith(name_str, prefix) for prefix in exported_prefixes) && !endswith(name_str, "_")
@eval export $name
Expand All @@ -21,15 +21,15 @@ include("carray.jl")
export mj_array, mj_zeros

module Wrappers
using ..LibMuJoCo
import ..Utils
include("wrappers.jl")
include("visualiser_wrappers.jl")
include("named_access.jl")
using .NamedAccess

# Fix for https://github.com/JamieMair/MuJoCo.jl/issues/120
Base.transpose(x::LibMuJoCo.mjContact_) = x
using ..LibMuJoCo
import ..Utils
include("wrappers.jl")
include("visualiser_wrappers.jl")
include("named_access.jl")
using .NamedAccess

# Fix for https://github.com/JamieMair/MuJoCo.jl/issues/120
Base.transpose(x::LibMuJoCo.mjContact_) = x
end
using .Wrappers
using .Wrappers.NamedAccess
Expand Down Expand Up @@ -78,8 +78,8 @@ export Model, Data

include("visualiser.jl")

const MODEL_TYPES = Union{Model, NamedAccess.NamedModel}
const DATA_TYPES = Union{Data, NamedAccess.NamedData}
const MODEL_TYPES = Union{Model,NamedAccess.NamedModel}
const DATA_TYPES = Union{Data,NamedAccess.NamedData}

import .Visualiser: visualise!

Expand Down Expand Up @@ -160,7 +160,7 @@ Resets the data struct to values in the supplied keyframe.

If no keyframe is specified, the first keyframe is used. The keyframe is a 1-based index into the list supplied by the model's specification.
"""
resetkey!(m::Model, d::Data, keyframe::Integer) = mj_resetDataKeyframe(m, d, keyframe-1)
resetkey!(m::Model, d::Data, keyframe::Integer) = mj_resetDataKeyframe(m, d, keyframe - 1)

"""
timestep(model::MODEL_TYPES)
Expand All @@ -180,7 +180,7 @@ The state vector is [joint positions, joint velocities, actuator states] with di
See also [`mj_getState`](@ref) and [`set_physics_state!`](@ref).
"""
function get_physics_state(m::Model, d::Data)
x = mj_zeros(m.nq+m.nv+m.na)
x = mj_zeros(m.nq + m.nv + m.na)
mj_getState(m, d, x, Int(LibMuJoCo.mjSTATE_PHYSICS))
return transpose(x)
end
Expand Down Expand Up @@ -217,12 +217,11 @@ the visualisation features, or run "install_visualiser()".
- FFMPEG
- GLFW
- Observables
- PrettyTables
- Printf
- StaticArrays
"""
function init_visualiser()
@eval Main using BangBang, FFMPEG, GLFW, Observables, PrettyTables, Printf, StaticArrays
@eval Main using BangBang, FFMPEG, GLFW, Observables, Printf, StaticArrays
if isdefined(Base, :get_extension)
@eval Main Base.retry_load_extensions()
end
Expand All @@ -239,27 +238,26 @@ into the current running environment.
- FFMPEG
- GLFW
- Observables
- PrettyTables
- Printf
- StaticArrays
"""
function install_visualiser()
@eval Main import Pkg
@eval Main Pkg.add(["BangBang", "FFMPEG", "GLFW", "Observables", "PrettyTables", "Printf", "StaticArrays"])
@eval Main Pkg.add(["BangBang", "FFMPEG", "GLFW", "Observables", "Printf", "StaticArrays"])
end

@static if !isdefined(Base, :get_extension)
function __init__()
@static if !isdefined(Base, :get_extension)
@require BangBang = "198e06fe-97b7-11e9-32a5-e1d131e6ad66" begin
@require FFMPEG = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" begin
@require GLFW = "f7f18e0c-5ee9-5ccd-a5bf-e8befd85ed98" begin
@require Observables = "510215fc-4207-5dde-b226-833fc4488ee2" begin
@require PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d" begin
function __init__()
@static if !isdefined(Base, :get_extension)
@require BangBang = "198e06fe-97b7-11e9-32a5-e1d131e6ad66" begin
@require FFMPEG = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" begin
@require GLFW = "f7f18e0c-5ee9-5ccd-a5bf-e8befd85ed98" begin
@require Observables = "510215fc-4207-5dde-b226-833fc4488ee2" begin
@require Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" begin
@require StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" begin
include("../ext/VisualiserExt/VisualiserExt.jl")
end

end
end
end
Expand All @@ -268,6 +266,5 @@ function __init__()
end
end
end
end

end
Loading