My own project (TCG sorter)

Hi all,

Just wanted to share what I built with my Lynxmotion arm.

I’m collecting Magic The Gathering cards and I have a lot of them. One of my challenges was to sort them. It takes a while. When I buy a collection of thousands of cards, I need to sort that by set, by color, by name, etc. Like many of us, on the day, I have to work. And I have family duties on the other shifts. Therefore little time to spend on that. So I decided to use the robot to help me sorting the cards!

After many iterations, I think I now have something working nicely, able to take a pile of cards and split that into 10 other packs, based on different information. I wrote all the code myself, and therefore it’s VERY dirty. So I’m sharing here only the pieces that can be re-used, but I will be very happy to share whatever someone might need.

Hardware:

Logic:

  • Take a picture of the source box and process it with AI inference to retrieve the details (Collection, title, etc.)
  • The arm is moved in the source box.
  • Lower the arm slowly while pumping until a vacuum is detected in the pipe, which mean a card has been grabbed
  • Ensure no other card is stuck under the grabbed one.
  • Move to destination.
  • Revert the pump until the vacuum in the pipe is gone.
  • Take a 5 minutes break if working for more than 10 minutes.
  • Repeat.

Challenges:

  • Took me some time to figure how to confirm that a card got grab. The camera option was doable but detecting the vacuum in the pipe ended up behind way easier, fast and very accurate!
  • Detecting that a card (a many!) is stuck under the grabbed one is hard. That’s why I just shake the card for some time. I’m still searching for a better way (Measure the current in the motor to guess the weight?)
  • Calculating the right angles to reach the right coordinates. Took some math and some trials/errors before having something good.

Here are some videos of the project in action.

Here are some extract of the code for those who want to save some time.

This is what I use to calculate the angles of each motor. It takes the distance of the wrist from the center of the base, and the height of it. And it returns the required angles for the motors.

	public static final double ARM_A = 5.75 * 25.4; // Length shoulder to elbow
	public static final double ARM_B = 7.375 * 25.4; // Length elbow to wrist

	public static Angles calculateAngles(int distance, int altitude) {
		Angles result = new Angles();
		// First we need to adjust the distance between the should and the hand based on
		// the altitude.
		double newDistance = Math.sqrt(distance * distance + altitude * altitude);
		double cosOffset = distance / newDistance;
		// Then we need to calcul the additional angle of the should to reach the
		// altitude.
		double offsetAngle = Math.acos(cosOffset);

		if (altitude < 0) {
			offsetAngle = -offsetAngle;
		}
		result.angleA = Math.toDegrees(Math.acos((newDistance * newDistance + ARM_A * ARM_A - ARM_B * ARM_B) / (2 * newDistance * ARM_A)) + offsetAngle);
		result.angleB = Math.toDegrees(Math.acos((ARM_B * ARM_B + ARM_A * ARM_A - newDistance * newDistance) / (2 * ARM_A * ARM_B)));
		result.angleC = -90 + result.angleA + result.angleB;
		return result;
	}

This piece of code is translating angles into motor pulses.

	public static Angles anglesToPulses(Angles angles) {
		Angles result = new Angles();
		final int RANGEA = (MID[1] - ZERO[1]) * 2;
		final int RANGEB = (MID[2] - ZERO[2]) * 2;
		result.angleA = ZERO[1] + (angles.angleA / 180) * RANGEA;
		result.angleB = (MID[2] + (MID[2] - ZERO[2])) - angles.angleB / 180 * RANGEB;
		result.angleC = MID[3] - ((angles.angleC) / 90) * (MID[3] - ZERO[3]) + 50;
		return result;
	}

Next steps:

  • Modify a bit the brackets on the arm to allow it to work on the other side of the “table”. Since the base motor can only do 180°, I want to try to have the arm going over its head to use the other side of the board to have more boxes and therefore a more accurate sorting.
  • Find a solution to detect faster if cards are stuck and just initiate the move if there is none. That will safe time for each iteration.
  • Detect the bottom of the input box. (Will probably do that with the camera).

Honestly, I spent a year on that project! But I’m happy with the result. Maybe I spent more time than I will ever save, but the amount of fun and thinking I had is priceless.

1 Like

Always nice to see what users do with Lynxmotion products!

When I buy a collection of thousands of cards

… wow. Just… wow.

Honestly, I spent a year on that project! But I’m happy with the result. Maybe I spent more time than I will ever save, but the amount of fun and thinking I had is priceless.

Absolutely!

Any idea what’s up with the wrist “vibrating” or “wiggling” several times?

1 Like

It is on purpose, to make sure the cards are detaching from each other. The challenge is that some times I just need to shake that for a second or two, but some times it takes 5 or 6 seconds before they really detach. So it’s a required step, but I’m not sure yet how to detect when I can stop shaking because all cards are detached. That will make the entire process way faster! I was thinking about “rubbing” the card against the box, but I have not been able to control the result nicely. On the 2nd video you can see why it shakes, and the result.

1 Like