My Overengineered Marble Sorter

Hey everyone. I just finished up a CIM class that featured a lot of VEX. Our final project was a marble sorter for wood, acrylic, and steel 1/2" marbles. I kind of took our team overboard by coming up with several design challenges for us to tackle on top of the normal “21 marbles in 2 minutes with no teeter-totters”.

My personal goals:
1: I wanted to run two independent sorting processes off of the same vex program while remaining as best as possible on the footprint of a single baseplate.
2: I wanted to include several interesting bits of code in the program
3: I wanted a continuous motion scanning instead of an intermittent motion.

This lead to the creation of the Gemini Kraken Leviathan Behemoth M1 Abrahms blow Jeff’s mind completely overengineered marble sorter:

I’m the one giving the explanation. It’s difficult to tell from the video, but everyone, including the teacher, was laughing their butts off XD Jeff (the head instructor) got a mind blown moment, so my official tally is now up to two. Huzzah!

Jeff actually came over and threw a bunch of extra marbles into the hopper as we were starting, which were a different kind of acrylic than the ones we tested with, which threw off a lot of the accuracy and added quite a bit to the time, but out of the 21 marbles of the correct types, we got about 80-90% accuracy. In a 21 marble test prior to presentation day, I did the 21 marbles in just under a minute with the same accuracy.

This is a video of earlier testing which shows the mechanisms in a lot more detail:

[/4095 (i.e. it solves the proportion for a motor speed value given a reading from the pot). The motor speed gets updated at the start of each run through the infinite loop with the sorting code. This feature was absolutely critical to “tuning” the sorter. By allowing for immediate adjustment of the feeder speed, one can run the tricky marbles through (acrylic, the mid range of the three marbles) until they sort properly, and then you can run the mix of marbles through with fairly good accuracy.
3: The start and E-stop functions are tied to one button by using a simple boolean variable and if else block that switches the state.

All in all, it was a great project and it provided a great way to transition into summer. I actually ordered a VEX kit for myself at home. There will be madness soon enough…](https://www.youtube.com/watch?v=pizMUmvKK64)

I have never seen anyone so excited about a marble sorter! Honestly though, that is a very neat machine…nice work.

Two questions:
1.) What program did you code with? EasyC, RobotC?
2.) Would you consider sharing your code? I am not a code expert and would love to see how you went about coding for this project.

The overly dramatic explanation was a joke of sorts. The idea being that I went super crazy with how much our team did to the point of it just being funny, so I decided to reward the people who showed up with a comedic presentation.

I used RobotC for the code, and I’m happy to share it. note that some of the comments stating specific values are outdated, as they had to be changed a bit.

#pragma config(Sensor, in1,    lineFollowerOne, sensorLineFollower)
#pragma config(Sensor, in2,    lineFollowerTwo, sensorLineFollower)
#pragma config(Sensor, in3,    potOne,         sensorPotentiometer)
#pragma config(Sensor, in4,    potTwo,         sensorPotentiometer)
#pragma config(Sensor, dgtl1,  startButton,    sensorTouch)
#pragma config(Motor,  port2,           feederOne,     tmotorVex393_MC29, openLoop)
#pragma config(Motor,  port3,           servoOne,      tmotorServoStandard, openLoop)
#pragma config(Motor,  port4,           feederTwo,     tmotorVex393_MC29, openLoop)
#pragma config(Motor,  port5,           servoTwo,      tmotorServoStandard, openLoop)
//*!!Code automatically generated by 'ROBOTC' configuration wizard               !!*//

task sorterOne();
task sorterTwo();
task startStop();

task main()
{
	startTask(startStop);

	while(1==1)
	{
		wait1Msec(1);
	}//while

}//main

task startStop()
{
	bool motorsRunning = false; //if false, motors are not running. If true, motors are running.
	while(1==1)
	{
		if(SensorValue[startButton]==1)//if start button pressed
		{
			if(motorsRunning==false) //check if motors are running
			{ //if motors are not running, start the motors
				startTask(sorterOne);
				startTask(sorterTwo);
				motorsRunning = true;
			}//if
			else //if motors ARE running
			{ //stop the tasks, motors, and reset the servos
				stopTask(sorterOne);
				stopTask(sorterTwo);
				stopMotor(feederOne);
				stopMotor(feederTwo);
				setServo(servoOne, 0);
				setServo(servoTwo, 0);
				wait(1);
				motorsRunning = false;
			}//else
			wait1Msec(200);
		}//if start button pressed
	}//while

}//startStop

task sorterOne()
{

	while(true)
	{
		int feederOneSpeed = ((127*SensorValue[potOne])/4095); //converts potentiometer value to a motor value

		startMotor(feederOne, feederOneSpeed);
			wait1Msec(45);
		if(SensorValue[lineFollowerOne] <= 1900) //if line follower less than or equal to threshold
		{
			setServo(servoOne, 127); //set servo to 127 (WOOD)
			wait1Msec(750);
		}//if LFO <= 200
		else
		{
			if(SensorValue[lineFollowerOne] <= 2480) //if line follow less than or equal to threshold
			{
				setServo(servoOne, 50); //set servo to 50 (ACRYLIC)
				wait1Msec(750);
			}//if LFO <= 2300
			else
			{
				if(SensorValue[lineFollowerOne] <= 2700) //if line follower less than or equal to threshhold
				{
					setServo(servoOne, 10); //set servo to 10 (STEEL)
					wait1Msec(500);
				}//if
			}//else
		}//else
	}//infinite while

}//sorterOne

task sorterTwo()
{

	while(true)
	{
		int feederTwoSpeed = ((127*SensorValue[potTwo])/4095); //converts potentiometer value to a motor value

		startMotor(feederTwo, feederTwoSpeed);
			wait1Msec(30);
		if(SensorValue[lineFollowerTwo] <= 1900) //if line follower less than or equal to threshold
		{
			setServo(servoTwo, -127); //set servo to 127 (WOOD)
			wait1Msec(600);
		}//if LFO <= 200
		else
		{
			if(SensorValue[lineFollowerTwo] <= 2450) //if line follow less than or equal to threshold
			{
				setServo(servoTwo, -70); //set servo to 50 (ACRYLIC)
				wait1Msec(600);
			}//if LFO <= 2300
			else
			{
				if(SensorValue[lineFollowerTwo] <= 2800) //if line follower less than or equal to threshhold
				{
					setServo(servoTwo, -20); //set servo to 10 (STEEL)
					wait1Msec(600);
				}//if
			}//else
		}//else
	}//infinite while

}//sorterTwo