What's new

Breaking scripts into reusable classes

bolsover

Senior Member
My background is in programming and I am accustomed to breaking my work into separate logical files containing related functions and data.

How do I do this using AlibreScript?

For example, I want a class CycloidalGear

class CycloidalGear:
module
toothCount
....

Normally, in another class, I would just call:

cg1 = CycloidalGear()

I could then access the variables and functions of CycloidalGear

db
 

NateLiquidGravity

Alibre Super User
It's Python based so as long as you look at docs for the correct Python version it should work. However not all modules work so there is some trial and error.

This should be the right doc:
https://docs.python.org/2/tutorial/classes.html

Here is a working example of a class I made for easily saving/loading settings in an external XML file. As you can read in the topic - there was some trouble getting the class to import correctly - so this example will probably help.
https://www.alibreforum.com/forum/i...s-release-load-save-external-variables.21047/
 

bolsover

Senior Member
Thanks for the examples - certainly help.
Most of my programming over the last few years has been in Java; mostly creating desktop applications that work with SQL backends - so scripting with Python is a bit strange and not helped by the rather poor Alibre scripting interface.

The initial goal is to develop a script that can create cycloidal gears (as used in clocks).
I've got most of the math working - now need to translate that into actual parts.

db
 

bolsover

Senior Member
Is is just me or is the Alibre scripting interface just completely rubbish?

I've been tearing my hair out writing and debugging scripts - I've lost count of the number of times I've had to restart Alibre because it does not appear to pick up on corrections made in referenced classes.
 

NateLiquidGravity

Alibre Super User
I did notice that scripts sometimes carried baggage of previously imported or ran scripts - which is a problem when developing a script but not running a finished script.

Can be more specific about what problems you've got?
 

bolsover

Senior Member
Hi I had hoped to upload a short screen capture to illustrate - but the file extension .wmv is not allowed so I've had to put that in the attached .zip.

The attached .py files illustrate the problem..

1 Open both in Alibre.
2 TestClass is called from TestScript - you need to run TestScript
3 TestClass contains one deliberate error. There is no colon after def __str__(self)
4 From the console, run TestScript. You should get a SyntaxError: unexpected token '<newline>'
5 Correct the error (missing colon) in TestClass and save the file.
6 Re-run TestScript. This time you should get: Result = This is expected result
7 Go back to TestClass and remove the colon and save the file.
8 Re-run TestScript. This time you should get: SyntaxError: unexpected token '<newline>' but it incorrectly shows: Result = This is expected result

I have been battling with this for some while - and is the main reason I was having the initial problems of breaking down complex scripts into classes.
What is worse is that often, correcting an error is not picked up by Alibre.

db
 

Attachments

  • TestClass.py
    211 bytes · Views: 5
  • TestScript.py
    118 bytes · Views: 5
  • ScreenCapture_25-01-2021 10.54.56.zip
    2 MB · Views: 4

idslk

Alibre Super User
I have been battling with this for some while
may you let it flow and try this one:
Code:
sys.path.append(ScriptFolder)

#replace: "from TestClass import TestClassi" with:
import TestClass

reload(TestClass)

test_class = TestClass.TestClassi()

print (test_class)

hope it is going to do what you want...

Regards
Stefan
 

NateLiquidGravity

Alibre Super User
Stefan, That seems to work (when I removed the 'i' from TestClassi()). I'll have to use reload in my code. I had thought it only applied to modules that were expected to change while the script was running.


@bolsover having a different module name than class name would make it easier. Rename TestClass.py to TestClassModule.py
Code:
sys.path.append(ScriptFolder)

import TestClassModule
reload(TestClassModule)
TestClass = TestClassModule.TestClass

test_class = TestClass()

print (test_class)

Also in Python this:
Code:
r = "".join(["Result = ", self.expected_result])
can be simplified to this:
Code:
r = "Result = " + str(self.expected_result)
the str() could even be removed if you know it's all strings already.
 

bolsover

Senior Member
Thanks all for the pointers. It's getting better!

Coming as I do from using mostly Java, the notion of having to reload a module seems odd. Also in Java, classes are always in files of the same name.

I'm not sure I've got it all straight in my head yet - but I'm making progress :)

I'll post up some real code in a day or two - be useful to get some feedback.

David
 

bolsover

Senior Member
Ok - So I've managed to do what I originally wanted..

I'm in the process of making a clock and wanted to have some 'proper' drawings of all the various components before I actually attempt to make them (another skill altogether!).

Clock wheels and pinions are quite different when compared with 'normal' involute gears. Strictly, the tooth apex should be formed as a cycloid curve but these are difficult to calculate and the British Standard (978 Part 2: Cycloidal Type Gears) takes a shortcut by defining the gear apex as a circular curve. However, calculating this curve (and taking into account some 'tweaks') is an iterative process that tends toward an acceptable error level. For details see the compute and addendum_factor functions in CycloidalGearModule. Having calculated the addendum factor, and with the module, the wheel pitch diameter can be determined together with the addendum radius (radius of curve at gear tip.).

The next problem is calculating the positions of the lines and curves that make up the tooth profile. The only difficult one is the location of the addendum curve centre point. Because the positions of the tooth apex, the end of the curve and the curve radius are known it is possible to calculate two possible locations for the curve centre point. The correct point lies within the wheel pitch circle diameter. See addendum_radius_centre and is_point_within_wheel for details.

I've attached a zip containing the relevant python code. The script CycloidalGearRunner is the entry point. You will be prompted to enter the Module (this is the standard metric measure of tooth profile. The wheel tooth count, the meshing pinion tooth count and the plane for the sketch.

Problems I have...
It is slow... I know there are a few calculations but why this slow?
Why can't I use SketchPoint on the CycloidalGear class? Every time I try I get an error: 'NameError: global name 'SketchPoint' is not defined'

Anyway that's all for now.. Back to the lathe.
David B
 

Attachments

  • CycloidalGears.zip
    2.9 KB · Views: 9

NateLiquidGravity

Alibre Super User
The calculations are fast but are being slowed majorly by three things:

Printing to console is very slow - remove that from your loop - or accumulate it and print it all at once at the end.

Each figure added to the sketch opens the sketch, adds the figure and closes the sketch - hence the flashing sketch. This can be avoided by wrapping your sketch functions like below. NOTE: AutomaticStartEndEditing, StartEditing, and StopEditing are undocumented and could break or change in the future.

Code:
part = CurrentPart()
sketch = part.AddSketch("Gear", plane)
sketch.AutomaticStartEndEditing = False
sketch.StartEditing()
gear.build_sketch_lines(sketch)
sketch.StopEditing()
sketch.AutomaticStartEndEditing = True

Each thing added to a part/assembly updates the explorer and view for the user. This can be avoided by wrapping your part functions like below.

Code:
part = CurrentPart()
part.PauseUpdating()
sketch = part.AddSketch("Gear", plane)
gear.build_sketch_lines(sketch)
part.ResumeUpdating()

These can be combined like so:
Code:
part = CurrentPart()
part.PauseUpdating()
sketch = part.AddSketch("Gear", plane)
sketch.AutomaticStartEndEditing = False
sketch.StartEditing()
gear.build_sketch_lines(sketch)
sketch.StopEditing()
sketch.AutomaticStartEndEditing = True
part.ResumeUpdating()
 
  • Like
Reactions: vec

idslk

Alibre Super User
Hello David B,

have you tried your script with a "Wheel tooth count" other than 30?
If you are not tied to do the wheel comletetly with a script, you can draw only one tooth, extrude it and than manualy do a circular pattern...

Regards
Stefan
 

idslk

Alibre Super User
Stefan with the changes I suggested it takes less time to make the whole sketch than it does to open the circular pattern dialog.
you are probably right (I also use the undocumented functions ...), but I don't know how fast David B's computer runs ;-)
have you tried your script with a "Wheel tooth count" other than 30?
Nate, have you tried that?

Regards
Stefan
 

bolsover

Senior Member
Nate, Stefan

Thank you both for all the helpful suggestions.
I realized when I tried the script with other tooth, pinion and module values that I had made a fundamental blunder in the compute method by not setting the self.wheel_count, self.pinion_count and self.modul variables correctly leading to some rather odd looking gears!

With the code provided by Nate, I now have the whole routine running MUCH faster and I'm actually able to produce some accurate drawings.

I want to make a few more changes to the code - but mostly done for now.

Just for info, here's a photo of this mornings effort on the lathe.. 72 tooth wheel, 0.8 module 20210128_144441.jpg
 

bolsover

Senior Member
Just found the cause of a significant error..

CycloidalGearModule.CycloidalGear.build_sketch_lines()
..
tooth_angle = 360 / (self.wheel_count)

should be

tooth_angle = 360.0 / (self.wheel_count)

David
 

idslk

Alibre Super User
Hello David B,

have you tried to create a gear with eg.10 teeth. I've i type in 10
upload_2021-1-28_18-33-6.png

i get this:
upload_2021-1-28_18-34-28.pngupload_2021-1-28_18-35-2.png

Regards
Stefan
 

bolsover

Senior Member
Hi Stefan

I know what the problem is - I have fixed in latest version...
Time to short to explain just now... dinner is waiting.
Thanks, David
 

Attachments

  • CycloidalGearModule.py
    9.5 KB · Views: 9
  • CycloidalGearRunner.py
    1.2 KB · Views: 8
  • PointModule.py
    565 bytes · Views: 8
Top