News

Friday Facts 7: A 2D physics engine in Processing (Java) and the Sunk Cost Fallacy

I have a robot dog being operated on by the Students at Alpha Secondary school in Burnaby, BC, as part of a work experience program. The goal is to make the dog walk as good or better than Spot Micro. Obviously this is not done in a weekend. How do you eat an elephant? One piece at a time. The current plan is to tackle things in order:

  • get it to turn on (done!)
  • move each motor individually (done!)
  • move them together (done!)
  • make it stand up and sit down (working on it!)
  • teach it to roll over and recover from a fall
  • teach it to walk

In a sense I’ve delegated all these steps to the students. Which frees me to do the part that needs experience – making tools that will empower them to do the hard steps at the end.

I don’t want to break the robot because it’s expensive to fix. Therefore I don’t want anyone to drop the robot hundreds of times while testing it. Given the tools I have, what can I do to test the robot without dropping the robot? The same thing I’ve done with all my robots – simulate them! But I’ve never used a phsyics system in Robot Overlord before.

I already have all my code and development tools in Java, so my first instinct is to continue in that direction. I didn’t find any up-to-date physics engines that work in Java. JBullet hasn’t been updated since 2016. Other engines I found were Java ports of C libraries. I don’t have links to them any more but those I found were stale and had no “contact us” system. Two solutions present themselves:

  1. Write my own physics system in Robot Overlord from scratch
  2. Install Gazebo on a linux system, ?, profit.

For your consideration, this is my attempt at number 1.

2D physics with circles and boxes in Processing

This is the first time I’ve had to simulate things with physics in Java.

This is a 2D physics engine written in Processing 4.0b. At tag 1.0, it looks like this:

Much help and inspiration was obtained by reading the code for Impulse Engine by Randy Gaul. Do your homework!

It took a day to write the drawing of shapes and 13 more to debug the physics up to this point. Here’s what it looked like at the half-way point:

The hope is to extend this into 3D, add constraints (think bones connected by joints), add friction, and then make physically approximate ragdoll models of the Spot Mini. They can be dropped, kicked, drop kicked, and beat up over and over until the simulated walking gets them up and balanced. Then the simulation can be tied to the real machine and our goal should be within sight if not in reach.

The sunk cost fallacy

Initially I didn’t even consider option no 2. The cost of setting up a linux box or partition, learning Gazebo, installing the robot model, unknown further mysteries tbd… I choose the devil I know over the devil I don’t!

Discord user M2710 DM’d me to ask “why don’t you just [gazebo]?” and made a compelling case that it might be easier than running my own physics engine. I couldn’t immediately prove the idea wrong so I have to consider it might be right. I’ve booked a day in the near future to try Gazebo and Webots. Look for that in an upcoming FF.

Hiring

If you have experience with Gazebo or Webots, share your story with us on the Discord channel. we really want to eat your juicy brains know what you know.

If you have java/physics skills and you think you can get the Robot Overlord features (3D, constraints, friction, physically approximate ragdoll models of the Spot Mini) working, DM me! I want to help you help me. Make me an offer, I’m eager. I only have so many hours in the day and I need your help.

Makelangelo News

Friday Facts 6: Makelangelo software 7.28.2

Today I’m pleased to announce the stable release of Makelangelo software 7.28.2. I’d like to thank everyone in the community for your support, especially the Discord users working to find and report bugs.

Lookin’ good, good lookin’!

Goodbye, Makelangelo Firmware

The big news is that Marginally Clever is no longer maintaining Makelangelo-firmware. It was too much esoteric work taking up all my time. Instead I teamed up with the good people that make Marlin 3D printer firmware. Together we’ve added polargraph robot support. Check out FF4 if you want the open source code or to make your custom machine tweaks.

New plotter controls separate making art from driving robot.

Get Makelangelo Software

The newest makelangelo software is available in our store, by donation. You can also get releases from our open source github repository.

In order to make it run you will need to install Java JDK 17 or later.

Use Makelangelo Software

Video time!

video late because editor is AFK. one more pandemic shortage!

Contribute

We’d love more people translating the app and sharing ideas about how to make it better. Join us on Discord or submit a ticket to github today.

News

Friday Facts 5: How (and why) be a Makelangelo Tester

To describe the mood here this week in a word it would be “challenged”. My productivity is greatly affected by the all-grey of Vancouver winters – I can’t work if I’m not happy and it takes a lot more time to find my happy place each day in the winter.

How (and why) be a Makelangelo Tester

Not too long ago, with the help of the Marlin 3D printer firmware team, I managed to switch to Marlin. This was a huge time savings for me as I can now focus on making the software better. To make it great – for me, for you, for everyone – as fast as possible I need to shorten the cycle time – the time it takes to check a new feature works right.

Maybe you’ve noticed the app is missing something you need. Maybe you found a bug. Now for a lot of programs out there the way to tell them about a bug is not obvious, hard to achieve, and the turnaround time is … who knows.

I want to make a great app and put new issues to bed quick-fast. To me, the report-fix-test loop should be as short and fast as can be. I hope you agree! That is why I’m asking you to help me help you. Become a tester: to shorten the loop.

Report

With our without being a tester, the process starts by going to the Makelangelo code project and filing a good bug report. The bug report comes with a template to fill out that should make writing your report painless.

Fix

Then I or some other brave soul will (maybe) ask follow up question and (definitely) work to make the thing happen. Some are easier than others in surprising ways.

Test

Now this is the sticky part of the loop. When I write code I bang away in the magic language of the drow elves, cursed to roam the underdark. When the machine says I have atoned enough, it produces a jar file. This is then packaged with other essentials like the README file and somehow delivered to you to give it a little run-see, a little double sanity check, a thumbs up or down.

The packaging and delivery process is slow. So slow. In a more perfect world you should be able to say “get me the latest update from Dan!” and moments later be able to run it. Two clicks, right? Well friends, read on.

Thank you

Making it easy to make you happy is … it’s the greatest gift. A win/win. Thank you. It’s very easy to get lost in the weeds with code, and your input gives me clear focus and direction.

Special shout out to CaptFuture, Headly, and OopsHeIsDead for being awesome contributors this week.

Final thoughts

Here’s a gallery of recent Makelangelo Software updates to the app. Many of these changes were brought about by you and yours. I’ll continue to write, you continue to stay awesome. Until next week, be well!

News

Friday Facts 4: How to Marlin Polargraph

Assuming you have two stepper motors, two limit switches, some timing belt, a 3D printer control board, and a hobby servo then you have everything you need to make a wall hanging plotter of your own that will work with Makelangelo Software. Read on for firmware configuration.

All the changes described herein have been applied to the fork of Marlin we maintain on Github. Make sure you are working with the branch called 2.1.x-polargraph which should match this blog post. You can modify this setup for your custom board. Many people have successfully built RAMPS+mega derivatives and shared their success stories in the Discord channel.

You’ll need to open the firmware in an Integrated Development Environment like Visual Studio Code and install the PlatformIO plugin.

The main files we’ll touch are Marlin\Configuration.h and Marlin\Configuration_adv.h. First I will show the line to find and then explain what is changed and why.

Marlin\Configuration.h

#define MOTHERBOARD BOARD_RAMPS_14_EFB

This sets the type of brain board you are using. The full list can be found in Marlin\src\pins\pins.h. In my case I change BOARD_RAMPS_14_EFB to BOARD_RUMBA.

#define CUSTOM_MACHINE_NAME "3D Printer"

Change 3D Printer to Polargraph. It’s aesthetic and non-essential.

#define EXTRUDERS 1

Polargraphs have no extruders. Change 1 to 0.

//#define POLARGRAPH

I remove the // part in front of # so that it becomes defined.

#define HYPOTENEUSE_LENGTH_AT_HOME_POSITION 1035.0

Makleangelo uses 1m belts. The pen holder adds a small amount to that and so my length for both belts is 1035. Correct belt length is essential to getting square drawings. While this is the default number in Marlin, you may have to change it – especially if you are making a huge machine.

Image
Image

100mm (radius of pen holder) – 14.466 (curved part of belt over pulley) – 50 (straight part of belt from switch to pulley) = 35.53400. That’s how a 1m belt becomes a hypoteneuse of 1035.

For Makelangelo huge 2035 worked great on 2m belt. From this I conclude that (the length of the pen holder arms) – (the part of the belt lost inside the motor mount) = +35mm. If you make a custom pen holder or different motor mounts your 35 will change.

#if MOTHERBOARD == BOARD_RUMBA
  #define X_MAX_PIN       35
  #define Y_MAX_PIN       34
#endif

These are the digital pins that are connected to your limit switches, uses for homing. When homing the machine will move the pen down and the counterweights up until the weights touch the switches. That is the maximum reach of each belt, and thus the max limit switch. For most boards, including RAMPS, you can ignore these lines so long as your switches are wired to x max and y max, respectively. These are here because RUMBA usage for polargraph predates Marlin adoption and Marlin needed to be made backward compatible for all existing customers.

#define USE_XMIN_PLUG
#define USE_YMIN_PLUG
#define USE_ZMIN_PLUG

I disable using minimum limit switch by adding // at the start of these lines.

//#define USE_XMAX_PLUG
//#define USE_YMAX_PLUG
//#define USE_ZMAX_PLUG

I enable using maximum limit switch by removing the // at the start of these lines.

#define X_MAX_ENDSTOP_INVERTING true // Set to true to invert the logic of the endstop.
#define Y_MAX_ENDSTOP_INVERTING true // Set to true to invert the logic of the endstop.
#define Z_MAX_ENDSTOP_INVERTING true // Set to true to invert the logic of the endstop.

I have switches wired to go LOW when they are clicked. If you have it the opposite then you’ll want to leave these set to false.

#define E0_DRIVER_TYPE A4988

There is no E0 Driver and the sanity checks in Marlin will get mad if this is defined. Put another // at the start of the line.

#define X_DRIVER_TYPE  A4988
#define Y_DRIVER_TYPE  A4988

If you are using something other than an A4988 stepper driver for your motor… this is where you’d list it.

#define DEFAULT_AXIS_STEPS_PER_UNIT   { 80, 80, 400, 500 }

There are only three axies of motion on this system, so we have to change it from { 80, 80, 400, 500 } to { 80, 80, 80 }. That assumes 200 step-per-turn motors and a 20 tooth GT2 pulley at 1/16 microstepping. (200*16) / (20*2)=80. Adjust your numbers accordingly. a 400-step motor would be 160 for the first two. The third is not really important because we don’t use a third stepper motor. Marlin won’t let me set two axies so it dangles on the end there like a vestigial tail.

#define DEFAULT_MAX_FEEDRATE          { 300, 300, 5, 25 }

I have changed these to { 90*60, 90*60, 90*60 }. Experiment with this number and see what kind of speeds you can get!

#define DEFAULT_MAX_ACCELERATION      { 3000, 3000, 100, 10000 }

I set mine to { 40*60, 40*60, 40*60 }. Another area I encourage you to experiment.

//#define CLASSIC_JERK

I don’t remember why I had to remove the // part but I did to appease the sanity checks.

#define INVERT_X_DIR false

By default Makelangelos are built with the left motor physically wired backwards so that “pull in” and “push out” was the same for both. So I have to change false to true. Discord user CaptFuture pointed out if you are building a DIY machine be aware mixing the wiring and the inversion might make some motors behave backwards.

//#define NO_MOTION_BEFORE_HOMING // Inhibit movement until all axes have been homed.
//#define HOME_AFTER_DEACTIVATE   // Require rehoming after steppers are deactivated.

I removed // from both. Safety third, right after chainsaws and LSD.

#define X_HOME_DIR -1
#define Y_HOME_DIR -1
#define Z_HOME_DIR -1

I changed these to 1 so that it homes to the maximum limits.

#define X_BED_SIZE 200
#define Y_BED_SIZE 200

Here I set the X_BED_SIZE to the width of a Makelangelo. The width is measured from one motor shaft center to the other motor shaft center. Makelangelo 5 is 650mm. For the Makelangelo height I used 1000mm (1m). More on this in a minute. Note: this number cannot be an odd number.

#define X_MIN_POS (-X_BED_SIZE/2)
#define Y_MIN_POS (-Y_BED_SIZE/2)

The bottom-left corner of the drawing area would then be – X_BED_SIZE/2 and -Y_BED_SIZE/2, or -325 and -500, respectively.

#define X_MAX_POS (X_BED_SIZE/2)
#define Y_MAX_POS (Y_BED_SIZE/2)

The top-right corner of the drawing area would then be X_BED_SIZE/2 and Y_BED_SIZE/2, or 325 and 500, respectively.

//#define BED_CENTER_AT_0_0

I removed the //. You can tell from the math that it should be true.

//#define MANUAL_X_HOME_POS 0
//#define MANUAL_Y_HOME_POS 0

First I remove the //. Then the MANUAL_Y_HOME_POS is equal to -482.65. I get that number from

Y_MAX_POS - ( sqrt( sq(POLARGRAPH_MAX_BELT_LEN) - sq(X_BED_SIZE/2) ) )

Remember using the triangle adjacent and the opposite to get the hypoteneuse? well here we use the opposite (machine bed size) and the hypoteneuse (the belt length) to get the adjacent, and then adjust by the Y_MAX_POS.

Image courtesy of Discord user PO

Note that the final value has to be inside the allowable drawing area of the machine – you can’t home to a spot that’s outside the printable area. That means the -Y_BED_SIZE/2 has to be a larger negative number than the MANUAL_Y_HOME_POS. With my settings -Y_BED_SIZE/2 is -500 and everything is fine.

//#define EEPROM_SETTINGS

remove the //. EEPROM_SETTINGS will allow you to tweak some firmware settings like acceleration and steps/mm from the LCD panel and then save them to the printer’s (very tiny) memory. Worth it!

//#define SDSUPPORT

If you have an SD card slot, remove the //.

//#define NUM_SERVOS 3

I set this to 1. As Jack Black said, one’s all you need.

//#define DEACTIVATE_SERVOS_AFTER_MOVE

Remove the //. This keeps the servo from jittering when not being used, which makes for a more pleasant sounding machine. It is reactivated every time it is used, don’t worry.

Marlin\Configuration_adv.h

#define AXIS_RELATIVE_MODES { false, false, false, false }

Change to { false, false, false } because there are three axies and zero extruders. Keeps the sanity check happy.

#define MICROSTEP_MODES { 16, 16, 16, 16, 16, 16 } // [1,2,4,8,16]

Change to { 16, 16, 16 } to keep the sanity check happy. Same reason. This is where you’d set your microstepping values.

#define MANUAL_FEEDRATE { 50*60, 50*60, 4*60, 2*60 }

I changed to { 50*60, 50*60, 4*60 }. Three axis! THREE.

#define G0_FEEDRATE 3000 // (mm/min)

I changed the number to 12000. What can I say? I like to go fast.

LCD panels

Discord member Headly pointed out that there’s no mention of LCD control panels. Search Configuration.h for “LCD / Controller Selection” and then start reading. There are many choices from which to choose. For Makelangelo I use

#define REPRAP_DISCOUNT_SMART_CONTROLLER

If your Makelangelo has no LCD panel you must DISABLE this feature. When the robot is told to change pens (Gcode M0) it will wait for the user to click the dial. With no dial and no LCD, the user will be confused while the robot patiently waits forever.

While the previous Makelangelo-firmware talked at 57600 Baud, Marlin defaults to 250000. If you connect the app to your firmware and nothing is “heard” from the robot then the app and the robot are on two different baud rates.

Discord member Mesut asked about the minimum temperature settings in Marlin. There is no extruder so minimum temp settings are ignored by Marlin.

Help! Every G0 move goes to center!

Most motherboards that run Marlin have a small amount of EEPROM memory that needs to be initialized once to hold tweakable settings like top speed and machine dimensions. By default they are all zero, which makes math fail in the firmware and sends the pen holder to 0,0 on every move.

If you have an LCD panel connected to your machine the firmware should request a firmware reset at startup.

Another way is to connect over serial and send two commands: Reinitialize your EEPROM with an M502 factory reset, then save your EEPROM changes with an M500. Recheck that your machine width and height is not zero with an M503.

Custom hardware and DEFAULT_AXIS_STEPS_PER_UNIT

If you are building a custom machine, be aware that there are more settings to check. The DEFAULT_AXIS_STEPS_PER_UNIT is calculated this way:

( motor total steps per turn * microstepping ) / ( pulley pitch circumference )

Makelangelo uses 200 steps-per-turn motors and 16 microsteps. The pulleys are 20 tooth GT2 pulleys, or 40mm pitch circumference. That means our math is 200 * 16 / 20 or 80 steps per unit.

Be sure to check that your microstepping switches/jumpers match your math!

Final thoughts

After all these changes you should be able to upload the firmware and start running your polargraph drawing robot. Take it in small steps – try homing your machine with no belts on and then touch the switches to see if it behaves. Also check the pulleys turn the correct direction before putting the belts on.

By default Makelangelo software uses a servo position of 90 (middle of the range) for pen up and 40 for pen down. Keep that in mind when you install the servo horn (the finger thing that lifts).

If you have any trouble with this, please join me and other polagraph fans on the Discord channel. It may be you’re doing something exotic; maybe this document needs a refresh; or you just want to find people with similar tastes. Join us!

Further Reading

The Marlin Configuration guide online

You can find more serial commands at https://marlinfw.org/meta/gcode/

News

Friday Facts 3: Sixi 3 Java GUI

This week I’ve done a lot to make driving the Sixi 3 arm easier.

You’ll recall from FF1 that I had build a Panel to talk to a robot in Javax Swing.

TextInterfaceToListeners (at the bottom) was the starting point. Then I made a ConversationHistoryList (in the middle). The two are tied togeter in a TextInterfaceWithHistory, such that hitting send copies the message to the history and clicking a line in the history copies it to the input field. Next I made a ChooseConnectionPanel (at the top) and attached that to the TextInterfaceWithHistory inside a TextInterfaceToNetworkSession. Sure, it could have all been in one giant class… but that’s hard to manage, debug, or reuse.

Having made all that, I found it was no better than the existing Arduino serial interface for talking to the robot. My biggest worry is that I make a typo and send the robot crashing through the table before I can hit the emergency stop. So to address this pain point, I needed a way to drive more intuitively.

The Dial

The Dial is drawn to scale whatever size you need. It listens for scrolling of the mouse wheel. Other classes can subscribe to get ActionEvents when the dial moves. This way the dial is loosely coupled and can be reused all over the place. For example,

Angle Driving

Using the dial I built a panel that is initialized with a virtual sixi3 robot.

The radio buttons on the left are pulled from the robot model. The AngleDriving system listens to the dial. When the Dial moves then AngleDriving looks at the selected button, finds the robot joint, and tweaks it by 1 degree.

Cartesian Driving

Moving the arm one joint at a time is fine some of the time, but sometimes I need to move in a straight line. I improved the look of the Dial a little bit and made this tool to move the end effector (finger tip) of the robot arm.

XYZ are straight line moves. Roll is a twist around Z, pitch a twist around X, and yaw a twist around Y. Each of these moves happens relative to the reference frame. The options for now are world, the first joint of the robot, and the end effector itself.

Read-only panels

Once I had that I needed more ways to visualize what the system was doing. The two types I made are the AngleReportPanel,

And the various matrix reports.

Each of these listens to the robot reporting a change to the end effector position.

Cartesian Driving with Jacobians

Big shout out to https://akintokinematics.com/ for the excellent Jupyter notebooks that helped me improve cartesian driving to work. For some time now I’ve been telling everyone how much I love Gradient Descent for moving the robot arm. Well… it turns out Gradient Descent is hard to tune and slow AF to converge on a solution, sometimes taking 30 seconds per millimeter. So, instead, based on Greer’s notes, I used the approximate Jacobian.

The approximate Jacobian is a matrix describing the relationship between joint velocity and cartesian velocity at a position. So from position A to position B have the cartesian difference {x,y,z,roll,pitch,yaw}, dAB.

  • I get the approximate Jacobian at A, aj.
  • I get the inverse or pseudoinverse of the Jacobian, aji,
  • Multiply aji * dAB to get is the amount to move each joint in the arm.
  • Apply the joint change and measure the error term.

I set up a loop to run (at most) 20 times. In practical terms it never seems to run more than 2 or 3 per step, and feels blazing fast.

Putting it all together

If you run the development version of Robot Overlord today and use Demos > Sixi 3 you’ll get this view and be able to drive the virtual robot by playing with the controls. Tweaking the dials moves the virtual robot. Sixi 3 UI listens for those changes and sends them through the RobotUI.chatInterface so they show up in the history and they move the real machine (if connected).

My next Thing is figuring out a nice way to run programs: loops, sequences, patterns, wait for signal, send signal, conditionals, and so on. The virtual robot does not know anything about gcode and my gut says it would be a really big mess to spread gcode around the app. I would love to jazz with you about this and find a Good Way to achieve the Thing.