Modeling Planar Belt Transmissions
Background
Belt transmissions involve several moving elements and a variety of materials, enabling flexible power transmission but leading to complex and interdependent system design requirements. The basic performance of a candidate belt transmission can be estimated from kinematic analysis, while a dynamic simulation can give a much better idea of actual system performance and limits.
This Julia package assists users in the kinematic analysis, designing belt transmissions using flat or synchronous belts. Primary structures model pulleys and belt segments, these can be analyzed and plotted through recipes for Plots.jl. BeltTransmission was used to determine the basic design of the Moover variants.
See the package readme for release, license, and development information.
Dependencies
And from the standard repository those defined in the Project.toml.
Installation
using Pkg
Pkg.add("https://github.com/mechanomy/BeltTransmission.jl.git")
Use Cases
Designing a planar belt transmission is the primary use case for BeltTransmission, but this design can have several objectives according to what is already known about the system. If the positions, sizes, and belt routing are known, these can be entered to calculate belt length and arrival and departure angles on each pulley. BeltTransmission can also be used to solve systems for other unknowns, say to determine the position of an idler pulley given a known belt length.
Basic belt transmissions
The goal of these examples is to calculate the belt length given pulley sizes and locations.
Two pulleys
using Unitful, Plots
using Geometry2D
using BeltTransmission
#create the pulleys
ctrA = Geometry2D.Point(10u"mm", 10u"mm")
pA = PlainPulley( pitch=Geometry2D.Circle( center=ctrA, radius=10u"mm"), axis=Geometry2D.UnitVector(0,0,1), name="A")
pB = PlainPulley( pitch=Geometry2D.Circle(100u"mm", 100u"mm", 20u"mm"), axis=Geometry2D.UnitVector(0,0,1), name="B")
#create the belt route
route = [pA, pB] #from A to B and back to A
#solve the departure and arrival angles on each PlainPulley
solved = calculateRouteAngles(route)
#create belt Segments between the Pulleys
segments = route2Segments(solved)
beltLength = calculateBeltLength(segments)
plot(segments, title="two pulleys")
By convention, Pulleys having a positive rotation (+uk) have a dot at their center to indicate the vector's tip, while negative rotation is shown with an X for the arrow's fletching. Once solved, the system can be interrogated:
calculateBeltLength(segments)
0.34959229994006674 m
A variety of pulleys
using Unitful, Plots
using Geometry2D
using BeltTransmission
#create the pulleys
ctrA = Geometry2D.Point(10u"mm", 10u"mm")
pA = PlainPulley( pitch=Geometry2D.Circle( center=ctrA, radius=10u"mm"), axis=Geometry2D.UnitVector(0,0,1), name="A")
pB = PlainPulley( pitch=Geometry2D.Circle(100u"mm", 20u"mm", 20u"mm"), axis=Geometry2D.UnitVector(0,0,1), name="B")
pC = PlainPulley( pitch=Geometry2D.Circle( 80u"mm", 40u"mm", 5u"mm"), axis=-Geometry2D.UnitVector(0,0,1), name="C")
pD = PlainPulley( pitch=Geometry2D.Circle(150u"mm", 40u"mm", 5u"mm"), axis=Geometry2D.UnitVector(0,0,1), name="D")
pE = PlainPulley( pitch=Geometry2D.Circle(100u"mm", 80u"mm", 5u"mm"), axis=Geometry2D.UnitVector(0,0,1), name="E")
#create the belt route
route = [pA, pB, pC, pD, pE]
#solve the departure and arrival angles on each PlainPulley
solved = calculateRouteAngles(route)
#create belt Segments between the Pulleys
segments = route2Segments(solved)
plot(segments, title="Various Pulleys" )
julia> calculateBeltLength(segments)
0.5507346870088579 m
julia> printSegments(segments)
FreeSegment: depart[A] [10.000mm, 0.000mm] --> arrive[B] [100.000mm, 0.000mm] l[90.000mm]@[0.000°] FreeSegment: depart[B] [94.114mm, 39.114mm] --> arrive[C] [81.471mm, 35.221mm] l[13.229mm]@[-162.886°] FreeSegment: depart[C] [80.714mm, 44.949mm] --> arrive[D] [149.286mm, 35.051mm] l[69.282mm]@[-8.213°] FreeSegment: depart[D] [153.123mm, 43.904mm] --> arrive[E] [103.123mm, 83.904mm] l[64.031mm]@[141.340°] FreeSegment: depart[E] [97.106mm, 84.078mm] --> arrive[A] [4.213mm, 18.155mm] l[113.908mm]@[-144.638°]
Positive rotation of PlainPulley A will cause PlainPulley C to rotate negatively, hence the negative rotation axis
on C. In addition to the PlainPulley rotation axis, the point of departure on each PlainPulley is given a slight arrow in the direction of positive belt rotation.
Multiple systems
using Unitful, Plots
using Geometry2D
using BeltTransmission
#create the pulleys
pA = PlainPulley( pitch=Geometry2D.Circle( 10u"mm", 20u"mm", 20u"mm"), axis=Geometry2D.UnitVector(0,0,1), name="B")
pB = PlainPulley( pitch=Geometry2D.Circle(100u"mm", 20u"mm", 30u"mm"), axis=Geometry2D.UnitVector(0,0,1), name="B")
pX = PlainPulley( pitch=Geometry2D.Circle( 10u"mm", 20u"mm", 15u"mm"), axis=Geometry2D.UnitVector(0,0,1), name="X")
pY = PlainPulley( pitch=Geometry2D.Circle( 50u"mm", 80u"mm", 5u"mm"), axis=Geometry2D.UnitVector(0,0,1), name="Y")
#create the belt systems
segAB = route2Segments( calculateRouteAngles( [pA, pB] ))
segXY = route2Segments( calculateRouteAngles( [pX, pY] ))
plot( segAB, title="Parallel Systems", xlabel="[mm]", ylabel="[mm]", xlims=([-50,150]), ylims=([-50,100]), legend=false, dpi=100, size=(1000,500))
plot!(segXY, segmentColor=:cyan)
PlainPulley body colors are assigned by the default colormap, but segmentColor
may be used to control the belt segment color. Other Plots.jl attributes may be used as expected.
Development Plan
BeltTransmission.jl is under active development, enhancement requests are welcome.
BeltTransmission.jl API
BeltTransmission.BeltTransmission
— ModuleGeometric modeling of 2D closed belt transmissions.
This module models closed belt transmissions with either:
- Plain pulleys with flat belting
- Timing pulleys and timing belts
With the general concept of a 'belt' entailing a continuous element, flat and timing belts add properties that affect which method may be called. For instance, a flat belt may have an arbitrary length, limited only by fabrication, while toothed belts are defined to have an integer number of teeth. Likewise, calculations involving tooth pitch are nonsensical if applied to flat or V belts. The module uses Julia's type system to differentiate between these belt types.
Timing and plain pulleys are specializaitons of AbstractPulley, permitting functions that need only the pulley location, rotation axis, or pitch diameter to accept any argument that maps to AbstractPulley, while allowing those needing tooth properties to specify arguments of TimingPulley type.
Calculations are perfomed on the pulley or belt pitch line.
Exports methods:
AbstractPulley
BeltSystem
FreeSegment
Optimizer
PlainPulley
SynchronousBelt
SynchronousBeltTable
SynchronousPulley
calculateBeltLength
calculateLength
calculateRatio
calculateRatios
calculateRouteAngles
calculateWrappedAngle
calculateWrappedLength
distance
findTangents
getArrivalPoint
getDeparturePoint
isSegmentMutuallyTangent
length
nGrooves2Length
nGrooves2Radius
nTeeth2PitchLength
pitchLength
pitchLength2NTeeth
printPulley
printRoute
printSegments
pulley2Circle
pulley2String
radius2NGrooves
route2Segments
toString
toStringPoints
toStringShort
BeltTransmission.AbstractFreeSegment
— TypeSubtypes of AbstractFreeSegment model free belt segments beginning at the depart
ure point traveling towards the arrive
point under postive motion.
BeltTransmission.AbstractPulley
— TypeSubtypes of AbstractPulley model a particular form of pulley. At present that includes PlainPulleys, having cylindrical faces, and SynchronousPulley. All subtypes have basic fields of pitch::Circle
, axis::UnitVector
, arrive::Angle
, depart::Angle
, and a name::String
.
BeltTransmission.BeltSystem
— TypeA BeltSystem is an ordered set of pulleys
connected by segments
of some belt
.
pulleys::Vector{AbstractPulley}
segments::Vector{BeltTransmission.AbstractSegment}
belt::BeltTransmission.AbstractBelt
BeltTransmission.BeltSystem
— MethodBeltSystem(
pulleys::Vector{AbstractPulley},
belt::BeltTransmission.AbstractBelt
) -> BeltSystem
Construct a new BeltSystem, creating segments from pulleys
and belt
.
BeltTransmission.FreeSegment
— TypeDescribes a belt segment between depart
and arrive
Pulleys.
depart
: Departing pulley
arrive
: Arriving pulley
BeltTransmission.PlainPulley
— TypePlainPulley(pp::PlainPulley, arrive=0u"rad", depart=0u"rad")
Copy constructor setting arrive
and depart
.
BeltTransmission.PlainPulley
— TypeModels a cylindrical plain pulley in a BeltTransmission with:
pitch
: the pitch Circle
axis
: the rotation axis for the pulley with +/- defining the 'positive' rotation direction
arrive
: angle of the radial vector of the belt's point of arrival
depart
: angle of the radial vector of the belt's point of departure
name
: convenience name of the pulley
BeltTransmission.PlainPulley
— MethodPlainPulley(pitch::Geometry2D.Circle, axis::Geometry2D.UnitVector, name::String)
Models a PlainPulley in a BeltTransmission, described by a circle
, rotation axis
, and name
.
BeltTransmission.SynchronousBelt
— TypeRepresents a synchronous belt with parameters: profile::String
- tooth profile name pitch::Unitful.Length
- distance between belt grooves length::Unitful.Length
- belt linear length if cut nTeeth::Int
- number of teeth over the length width::Unitful.Length
- belt width partNumber::String
- reference name supplier::String
- reference name url::String
- sourcing link id::UUID
- unique id
BeltTransmission.SynchronousBelt
— MethodSynchronousBelt( belt::SynchronousBelt; partNumber="", supplier="", url="" ) :: SynchronousBelt A copy constructor for adding/changing partNumber
, supplier
, or url
.
BeltTransmission.SynchronousPulley
— TypeSynchronousPulley(sp::SynchronousPulley, arrive=0u"rad", depart=0u"rad")
A copy constructor for setting the arrive
and depart
angles.
BeltTransmission.SynchronousPulley
— TypeModels a SynchronousPulley in a BeltTransmission, described by a pitch
circle, rotation axis
, and beltPitch
.
pitch
: Circle describing the pulley pitch diameter.
axis
: The rotation axis for the pulley with +/- defining the 'positive' rotation direction.
beltPitch
: Distance between belt teeth
arrive
: Angle of the radial vector of the belt's point of arrival.
depart
: Angle of the radial vector of the belt's point of departure.
name
: Convenience name of the pulley.
BeltTransmission.SynchronousPulley
— MethodSynchronousPulley(center::Geometry2D.Point, axis::Geometry2D.UnitVector, nGrooves::Integer, beltPitch::Unitful.Length, name::String)
Models a SynchronousPulley in a BeltTransmission located at center
rotating about axis
with nGrooves
(=nTeeth) spaced with arc length beltPitch
and covenience name
.
Base.length
— MethodBase.length(seg::FreeSegment) :: Unitful.Length
Returns the straight-line distance or length of FreeSegment seg
via distance
.
Base.show
— MethodBase.show(io::IO, p::AbstractPulley)
Function to show()
a AbstractPulley via pulley2String
.
Base.show
— MethodBase.show(io::IO, seg::FreeSegment)
show()s the FreeSegment via toStringShort
.
BeltTransmission.calculateBeltLength
— MethodcalculateBeltLength(segments::Vector{FreeSegment}) :: Unitful.Length
Calculates the belt length over the given route
as the sum of straight Segments.
BeltTransmission.calculateBeltLength
— MethodcalculateBeltLength(route::Vector{AbstractPulley}) :: Unitful.Length
Calculates the belt length over the given route
as the sum of circular sections at the pulley pitch radii between the arrival and departure angles.
BeltTransmission.calculateCenterDistance
— MethodcalculateCenterDistance(bs::BeltSystem, which::Integer)
Given a belt system, find the pulley position(s) that satisfy the given belt length. It does this through a linear optmization whose objective is to minimze the error between the given belt's length and the calculateBeltLength(). Since pulleys can each move in <x,y>, the
which
is an index or array to the pulley(s) that may be moved; by default all pulleys may be moved and the algorithm minimizes the total pulley movement. The pulleys in the belt
system need to be placed in approximate locations in order to determine the belt routing. That is even if their positions are not final some position must be given when creating the pulleys to permit the belt length to be accurately calculated. Pulleys are constrained from overlap
In a two-belt system this problem devolves to calculating the center distance between two pulleys: '''@example
'''
In larger systems,
BeltTransmission.calculateLength
— MethodcalculateLength(
bs::BeltSystem
) -> Union{Unitful.Quantity{T, 𝐋, U}, Unitful.Level{L, S, Unitful.Quantity{T, 𝐋, U}} where {L, S}} where {T, U}
Pass-through to calculateBeltLength.
BeltTransmission.calculateRatio
— MethodcalculateRatio(
driving::AbstractPulley,
driven::AbstractPulley
) -> Real
Calculate the transmission ratio between pulleys driving
and driven
, with the ratio defined as driven/driving
, being >1 when the driven pulley rotates more than the driving and <1 less. This can be developed from the belt translation or velocity, as:
xBelt = thA*rA = thB * rB; thB = thA * rA/rB
vBelt = wA*rA = wB*rB; wB = wA * rA/rB
Pulleys having a positive transmission ratio rotate in the same direction, negative opposing.
BeltTransmission.calculateRatios
— MethodcalculateRatios(bs::BeltSystem) -> Matrix{Float64}
Calculate the transmission ratio matrix between all pulleys, returning a matrix of ratios. Pulleys are numbered according to their order in bs
, with the ratio as in calculateRatio.
BeltTransmission.calculateRatios
— MethodcalculateRatios(
pulleys::Array{T<:AbstractPulley, 1}
) -> Matrix{Float64}
Calculate the transmission ratio matrix between all pulleys, returning a matrix of ratios. Pulleys are numbered according to their order in pulleys
, with the ratio as in calculateRatio.
BeltTransmission.calculateRouteAngles
— MethodcalculateRouteAngles(route::Vector{AbstractPulley}, plotSegments::Bool=false) :: Vector{AbstractPulley}
Given an ordered vector of Pulleys, output a vector of new Pulleys whose arrive and depart angles are set to connect the pulleys with mutually tangent segments. Convention: pulleys are listed in 'positive' belt rotation order, consistent with the direction of each pulley's rotation axis.
BeltTransmission.calculateWrappedAngle
— MethodcalculateWrappedAngle(p::AbstractPulley) :: Geometry2D.Angle
Given p
, calculate the wrapped angle from p.arrive
to p.depart
. Note that the wrapped angle is not restricted to <= 1 revolution, as the pulley may be wrapped multiple times.
BeltTransmission.calculateWrappedLength
— MethodcalculateWrappedLength(p::AbstractPulley) :: Unitful.Length
Given p
, calculate the arclength of the wrapped segment from p.arrive
to p.depart
Note that the wrapped length is not restricted to <= 1 revolution, as the pulley may be wrapped multiple times.
BeltTransmission.findTangents
— MethodfindTangents(seg::FreeSegment) :: Vector{FreeSegment}
Find four lines tangent to both pulleys a
and b
, returns 4 Segments with departure and arrival angles locating the points of tangency on the circles.
BeltTransmission.getArrivalPoint
— MethodgetArrivalPoint(p::AbstractPulley)::Geometry2D.Point
Returns the point of arrival.
BeltTransmission.getArrivalPoint
— MethodgetArrivalPoint(seg::FreeSegment) :: Geometry2D.Point
Returns the arrival Geometry2D.Point of seg
.
BeltTransmission.getDeparturePoint
— MethodgetDeparturePoint(p::AbstractPulley)::Geometry2D.Point
Returns the point of departure.
BeltTransmission.getDeparturePoint
— MethodgetDeparturePoint(seg::FreeSegment) :: Geometry2D.Point
Returns the departure Geometry2D.Point of seg
.
BeltTransmission.isSegmentMutuallyTangent
— MethodisSegmentMutuallyTangent( seg::FreeSegment ) :: Bool
Determines whether the departure and arrival points are tangent to the connecting belt segment.
For a segment a->b between ai&bi; the correct arrival and departure angles will have cross products that match both axes, (ra-a1)x(a1-b1) = ax1 && (rb-b1)x(a1-b1) = bx1, all others should be false.
BeltTransmission.nGrooves2Length
— MethodnGrooves2Length(pitch::Unitful.Length, nGrooves::Integer)::Unitful.Length
Convert the pitch
and nGrooves
to the circumferential length.
BeltTransmission.nGrooves2Radius
— MethodnGrooves2Radius(pitch::Unitful.Length, nGrooves::Integer)::Unitful.Length
Convert the pitch
and nGrooves
to the pitch radius.
BeltTransmission.nTeeth2PitchLength
— MethodnTeeth2PitchLength(; pitch::Unitful.Length, nTeeth::Integer) :: Unitful.Length
Belt length
is pitch
* nTeeth
.
BeltTransmission.pitchLength
— MethodpitchLength(p::AbstractPulley) :: Unitful.Length
Returns the circumferential length of the pitch diameter of the pulley.
BeltTransmission.pitchLength2NTeeth
— MethodpitchLength2NTeeth(; pitch::Unitful.Length, length::Unitful.Length )::Integer
nTeeth
is simply length
/pitch
.
BeltTransmission.printPulley
— MethodprintPulley(p::AbstractPulley)
Prints the result of pulley2String
to the standard output
BeltTransmission.printRoute
— MethodprintRoute(route::Vector{AbstractPulley})
Prints the Pulleys and total belt length for the given route
.
BeltTransmission.printSegments
— MethodprintSegments(segments::Vector{FreeSegment})
Prints the Segments, and total belt length for the given route
.
BeltTransmission.pulley2Circle
— Methodpulley2Circle(p::AbstractPulley) :: Geometry2D.Circle
Returns the pitch Circle of p
.
BeltTransmission.pulley2String
— Methodpulley2String(p::PlainPulley) :: String
Returns a descriptive string of the given PlainPulley p
of the form: PlainPulley[struct] @ [1.000mm,2.000mm] r[3.000mm] arrive[57.296°] depart[114.592°] aWrap[57.296°] lWrap[3.000mm]"
BeltTransmission.pulley2String
— Methodpulley2String(p::SynchronousPulley) :: String
Returns a descriptive string of the given SynchronousPulley p
of the form: SynchronousPulley[struct] @ [1.000mm,2.000mm] r[3.000mm] arrive[57.296°] depart[114.592°] aWrap[57.296°] lWrap[3.000mm]"
BeltTransmission.radius2NGrooves
— Methodradius2NGrooves(p::SynchronousPulley)::Integer
radius2NGrooves(pitch::Unitful.Length, radius::Unitful.Length)::Integer
Convert the pitch
and radius
to the number of grooves.
BeltTransmission.route2Segments
— Methodroute2Segments(route::Vector{AbstractPulley}) :: Vector{FreeSegment}
Given the ordered Pulleys of a belt routing, returns a vector of the free-space Segments connecting the Pulleys.
BeltTransmission.toString
— MethodtoString(seg::FreeSegment) :: String
Calls toStringShort
.
BeltTransmission.toStringPoints
— MethodtoStringPoints(seg::FreeSegment) :: String
Creates strings like: FreeSegment: depart[E] [-0.013m, 0.012m] –> arrive[A] [0.110m, 0.083m] l[0.142m]@[29.973°]
BeltTransmission.toStringShort
— MethodtoStringShort(seg::FreeSegment) :: String
Returns a short string of the form 'A – B', for a departing pulley named A arriving at a pulley named B.
Geometry2D.distance
— Methoddistance(seg::FreeSegment) :: Unitful.Length
Returns the straight-line distance or length of FreeSegment seg
.
KeywordDispatch.kwcall
— MethodFreeSegment(; depart::AbstractPulley, arrive::AbstractPulley) :: FreeSegment
Create a belt FreeSegment between depart
and arrive
Pulleys
KeywordDispatch.kwcall
— MethodPlainPulley(; pitch::Geometry2D.Circle, axis::Geometry2D.UnitVector, name::String)
PlainPulley(; pitch::Geometry2D.Circle, axis::Geometry2D.UnitVector, arrive::Geometry2D.Radian, depart::Geometry2D.Radian, name::String)
Models a PlainPulley in a BeltTransmission through keyword arguments.
KeywordDispatch.kwcall
— MethodSynchronousBelt(; pitch::Unitful.Length, length::Unitful.Length, nTeeth::Int, width::Unitful.Length, profile::String, partNumber::String, supplier::String, url::String, id::UUID )
SynchronousBelt(; pitch::Unitful.Length, length::Unitful.Length, width::Unitful.Length, profile::String)
SynchronousBelt(; pitch::Unitful.Length, nTeeth::Int, width::Unitful.Length, profile::String)
Creates a SynchronousBelt with tooth pitch
, overall length
, nTeeth
, belt width
and profile
name.
KeywordDispatch.kwcall
— MethodSynchronousPulley(; center::Geometry2D.Point, axis::Geometry2D.UnitVector, nGrooves::Integer, beltPitch::Unitful.Length, arrive::Geometry2D.Radian, depart::Geometry2D.Radian, name::String)
SynchronousPulley(; center::Geometry2D.Point, axis::Geometry2D.UnitVector, nGrooves::Integer, beltPitch::Unitful.Length, name::String)
Models a SynchronousPulley in a BeltTransmission, described by a circle
, rotation axis
, and name
. nGrooves
and beltPitch
are used to find the pulley pitch diameter. The belt's arrive
and depart
angles are the polar angles about the pulley axis of the belt's arrival and departure contact points, usually found by calculateRouteAngles()
RecipesBase.apply_recipe
— MethodplotRecipe(seg::FreeSegment; n=2, lengthUnit=u"mm", segmentColor=:magenta, arrowFactor=0.03)
Plot recipe to plot the free sections of a segment, does not plot the pulleys. using Plots, Unitful, BeltTransmission, Geometry2D a = PlainPulley( Geometry2D.Circle(1u"mm",2u"mm",3u"mm"), Geometry2D.uk, "recipe" ) b = PlainPulley( Geometry2D.Circle(10u"mm",2u"mm",3u"mm"), Geometry2D.uk, "recipe" ) seg = FreeSegment(depart=a, arrive=b) plot(seg)
RecipesBase.apply_recipe
— MethodplotRecipe(p::PlainPulley; n=100, lengthUnit=u"mm", segmentColor=:magenta, arrowFactor=0.03)
A plot recipe for plotting Pulleys under Plots.jl. Keyword n
can be used to increase the number of points constituting the pulley edge. lengthUnit
is a Unitful unit for scaling the linear axes. arrowFactor
controls the size of the arrow head at depart. using Plots, Unitful, BeltTransmission, Geometry2D p = PlainPulley( Geometry2D.Circle(1u"mm",2u"mm",3u"mm"), Geometry2D.uk, "recipe" ) plot(p)
RecipesBase.apply_recipe
— MethodplotRecipe(p::SynchronousPulley; n=100, lengthUnit=u"mm", segmentColor=:magenta, arrowFactor=0.03)
A plot recipe for plotting Pulleys under Plots.jl. Keyword n
can be used to increase the number of points constituting the pulley edge. lengthUnit
is a Unitful unit for scaling the linear axes. arrowFactor
controls the size of the arrow head at depart. using Plots, Unitful, BeltTransmission, Geometry2D p = SynchronousPulley( Geometry2D.Circle(1u"mm",2u"mm",3u"mm"), Geometry2D.uk, "recipe" ) plot(p)
RecipesBase.apply_recipe
— MethodplotRecipe(route::Vector{PlainPulley})
Plots the Pulleys in a route
vector of Pulleys. using Plots, Unitful, BeltTransmission, Geometry2D a = PlainPulley( Geometry2D.Circle(1u"mm",2u"mm",3u"mm"), Geometry2D.uk, "recipe" ) b = PlainPulley( Geometry2D.Circle(10u"mm",2u"mm",3u"mm"), Geometry2D.uk, "recipe" ) route = calculateRouteAngles([a,b]) plot(route)
RecipesBase.apply_recipe
— MethodplotRecipe(segments::Vector{T}) where T<:AbstractSegment
Plots the Pulleys and Segments in a route
vector. using Plots, Unitful, BeltTransmission, Geometry2D a = PlainPulley( Geometry2D.Circle(1u"mm",2u"mm",3u"mm"), Geometry2D.uk, "recipe" ) b = PlainPulley( Geometry2D.Circle(10u"mm",2u"mm",3u"mm"), Geometry2D.uk, "recipe" ) route = calculateRouteAngles([a,b]) segments = route2Segments(route) plot(segments)
BeltTransmission.SynchronousBeltTable
BeltTransmission.SynchronousBeltTable
— ModuleReads, writes, and generates CSVs that represent catalogs of synchronous belts, having headers: toothProfile
- trade name of the tooth profile, eg gt2, gt3, mxl, ... pitchMM
- tooth spacing nTeeth
- number of teeth about the closed belt lengthMM
- circumferential belt length widthMM
- belt width id
- a UUID4 unique identifier partNumber
- manufacturer or supplier part number supplier
- supplier name url
- link to the data source
Basic usage:
Generate a DataFrame of belts: @julia using BeltTransmission belts = SynchronousBeltTable.generateBeltDataFrame(pitch=2u"mm", width=6u"mm", toothRange=10:5:30)
Write these to a CSV: @repl SynchronousBeltTable.writeBeltCSV(belts, "gt2Belts.csv")
This creates a CSV file at the given path, with format profile,pitchMM,nTeeth,lengthMM,widthMM,id,partNumber,supplier,url gt2,2,10,20,6,3a9ee2fa-95a2-4217-b5c6-4bde0d9c65c9,pn0,none,none gt2,2,15,30,6,319f2899-b714-43a4-b37c-830179524311,pn0,none,none gt2,2,20,40,6,7e15cab0-58f2-4c4e-be0b-f168d1091ce9,pn0,none,none gt2,2,25,50,6,6f5fcd44-26f0-44c7-bf38-5aea52c51dd1,pn0,none,none gt2,2,30,60,6,ce84bc3b-4025-4de1-b79c-f536f9e95794,pn0,none,none
(note the UUID ids will differ).
This file can then be read in @repl beltsdf = SynchronousBeltTable.readBeltCSVIntoDataFrame("gt2Belts.csv")
The table of belts can be filtered by @repl filtered = SynchronousBeltTable.lookupLength(beltsdf, 35u"mm", n=2)
to get the top two belts nearest the desired length.
These can be converted into SynchronousBelts by @repl sync = SynchronousBeltTable.dfRow2SyncBelt( filtered[1,:] )
BeltTransmission.SynchronousBeltTable.AbstractOptimizableBelt
— TypeAn abstract belt type for belt optimization
BeltTransmission.SynchronousBeltTable.dfRow
— MethoddfRow( sb::SynchronousBelt)
Converts a SynchronousBelt into a DataFrame row.
BeltTransmission.SynchronousBeltTable.dfRow2SyncBelt
— MethoddfRow2SyncBelt( row::DataFrames.DataFrameRow )
Converts a DataFrame row to a SynchronousBelt struct.
BeltTransmission.SynchronousBeltTable.generateBeltDataFrame
— MethodgenerateBeltDataFrame(; pitch::Unitful.Length, width::Unitful.Length, toothRange)
Generates a belt DataFrame with a given pitch
and width
over toothRange
. toothRange
can be specified as toothRange=20:5:200
to create a tooth range array starting with 20 teeth, then proceeding to 200 teeth in 5-tooth increments.
BeltTransmission.SynchronousBeltTable.lookupLength
— MethodGiven a desired belt length
, return a vector of the closest options from the belts
dataframe for the given pitch
and width
. If n
= 1 the single nearest result is returned, else a DataFrame sorted by abs(length error).
BeltTransmission.SynchronousBeltTable.readBeltCSVIntoDataFrame
— MethodreadBeltCSVIntoDataFrame(csvPath::String)
Returns a dataframe with the belt information from the given csvPath
belt description file. See writeBeltCSV for the file format.
BeltTransmission.SynchronousBeltTable.writeBeltCSV
— MethodwriteBeltCSV(belts::DataFrame, csvPath::String )
Given a belts
DataFrame describing one or more belts, write that to the csvPath
file.
BeltTransmission.Optimizer
Pulley locations and radii can be optimized via the Optimizer
.
Optimizer example
This example moves and resizes pulleys to achieve a given belt length. We start with the initial system which has a belt length of 1050mm.
using Unitful, Plots
using Geometry2D
using BeltTransmission
uk = Geometry2D.UnitVector(0,0,1)
#a square of pulleys, arranged ccw from quadrant1
pA = SynchronousPulley( center=Geometry2D.Point( 100u"mm", 100u"mm"), axis=uk, nGrooves=62, beltPitch=2u"mm", name="1A" )
pB = SynchronousPulley( center=Geometry2D.Point(-100u"mm", 100u"mm"), axis=uk, nGrooves=30, beltPitch=2u"mm", name="2B" )
pC = SynchronousPulley( center=Geometry2D.Point(-100u"mm",-100u"mm"), axis=uk, nGrooves=80, beltPitch=2u"mm", name="3C" )
pD = SynchronousPulley( center=Geometry2D.Point( 100u"mm",-100u"mm"), axis=uk, nGrooves=30, beltPitch=2u"mm", name="4D" )
pE = PlainPulley( pitch=Geometry2D.Circle( 0u"mm", 0u"mm", 14u"mm"), axis=-uk, name="5E") # -uk axis engages the backside of the belt
solved0 = BeltTransmission.calculateRouteAngles( [pA, pB, pC, pD, pE] )
l0 = BeltTransmission.calculateBeltLength(solved0)
1.0501215661822083 m
Next, we add an available belt for this system.
# Initially the belt length is 1050mm. Reduce that to force the pulleys to move.
pitch = 8u"mm"
l = 1000u"mm"
n = Int(round(ustrip(l/pitch)))
belt = BeltTransmission.SynchronousBelt(pitch=pitch, nTeeth=n, width=6u"mm", profile="gt2")
println("Closest belt is $belt")
Closest belt is SynchronousBelt("gt2", 8 mm, 1000 mm, 125, 6 mm, "pn00", "spA", "url0", UUID("93384618-8130-4d09-9ccd-2e1178d859a6"))
While this is a bit trivial, this is where a BeltTable belt can be used. Now we indicate which system variables are allowed to change, and their acceptable ranges.
pRoute = [pA, pB, pC, pD, pE]
cfg = BeltTransmission.Optimizer.Config(belt, pRoute, 4)
BeltTransmission.Optimizer.addVariable!(cfg, pA, BeltTransmission.Optimizer.xPosition, low=60, start=100.1, up=113 )
BeltTransmission.Optimizer.addVariable!(cfg, pA, BeltTransmission.Optimizer.yPosition, low=90, start=100.2, up=111 )
BeltTransmission.Optimizer.addVariable!(cfg, pB, BeltTransmission.Optimizer.yPosition, low=90, start=100.3, up=112 )
BeltTransmission.Optimizer.addVariable!(cfg, pC, BeltTransmission.Optimizer.radius, low=20, start=25, up=95 )
solved = BeltTransmission.Optimizer.solveSystem(cfg)
p = plot(solved0, segmentColor=:magenta)
p = plot!(solved, segmentColor=:yellow)
Here, the initial, unavailable belt length is plotted in magenta, with the optimization to the available belt in yellow. Solving the system minimizes the difference between the given belt's length and that of the most recent system iteration. Note that each variable was utilized, as the optimization generally spreads the task between the available freedoms. The ranges set in each addVariable!
provide an ability to fine-tune the solution as desired.
Infeasible systems will return warnings like:
Optimizer could not achieve the desired belt length given other constraints, desired[] vs solved[]. Try reducing the number of constraints or expanding their range.
Optimizer stopped prior to completion, consider changing the starting point or constraints.
The latter indicates that somewhere along the optimization the calculation of the system's belt length ran into an error. This error was probably reported elsewhere in the output, but likely results from the overlapping of two pulleys, or the movement of one pulley such that the belt cannot touch it.
API
BeltTransmission.Optimizer
— ModuleProvides functions for optimizing belt transmissions according to various metrics.
BeltTransmission.Optimizer.Config
— TypeThe Config
struct holds optimization configuration options and system information.
belt::BeltTransmission.AbstractBelt
: Belt information
routing::Vector{AbstractPulley}
: Routing of the belt through the pulleys.
pulley::Vector{AbstractPulley}
: Vector of pulleys to be optimized, set via addVariable
.
variable::Vector{BeltTransmission.Optimizer.OptimizationVariable}
: Vector of variables on each pulley be optimized, set via addVariable
.
start::Vector{Real}
: Vector of start values of each variable
, set via addVariable
.
lower::Vector{Real}
: Vector of lower bounds of each variable
, set via addVariable
.
upper::Vector{Real}
: Vector of upper bounds of each variable
, set via addVariable
.
nlOptions::NLopt.Opt
: Options for the NLOpt optimization algorithm, see NLOpt's documentation.
BeltTransmission.Optimizer.Config
— MethodConfig(
belt::BeltTransmission.AbstractBelt,
routing::Vector{AbstractPulley},
nConstraints::Int64
) -> BeltTransmission.Optimizer.Config
Constructor of Config
objects, sets default optimization options in the .nlOptions
field. nConstraints
is the number of constraints that will be added through addVariable
.
BeltTransmission.Optimizer.OptimizationVariable
— TypeEnum defining optimizable entities as:
xPosition
= the x position of the pulley centeryPosition
= the y position of the pulley centerradius
= the pulley pitch radius
BeltTransmission.Optimizer.addVariable!
— MethodaddVariable!(
opts::BeltTransmission.Optimizer.Config,
pulley::AbstractPulley,
variable::BeltTransmission.Optimizer.OptimizationVariable;
low,
start,
up
)
Adds variable
on pulley
to the list of entities to optimize over. solveSystem
will evaluate values of the variable
, starting at start
, between low
and up
.
BeltTransmission.Optimizer.lookupPulley
— MethodlookupPulley(
routing::Vector{AbstractPulley},
p::AbstractPulley
) -> Int64
Find the index of p
in routing
.
BeltTransmission.Optimizer.solveSystem
— MethodsolveSystem(opts::BeltTransmission.Optimizer.Config) -> Any
Solves the system descriped by opts
, returning the solved system.
BeltTransmission.Optimizer.x2route
— Methodx2route(
opts::BeltTransmission.Optimizer.Config,
ox::Array{T<:Real, 1}
) -> Vector{AbstractPulley}
Converts optmization vector ox
into a solved belt system via the system description in opts
.