Monthly Archives: February 2021

LEGO MindStorms – Spinner Factory

When we built the factory, we thought that the EV3 Home (Scratch base) can support two bricks. However, no ever how much information we read, it is not what we expected. We were trying to modify factory by adding additional color sensor, so that we can use two separated program to control this, we really don’t want to deal with EV3-G (LabView) even it support EV3 daisy chain. Finally, we decided to go for EV3dev and it opened our eyes.

Go ahead to try EV3DEV2, Python is easy if you already know Scratch based programming. Don’t hesitating, start from PyBricks, the official one.

Features of the factory

Head control – The first function is moving the head up and down getting the spinner parts. The second function is switching the tool for the head, one is to pickup the spinner parts and place it on the spinner holder, the other one is the spinning tool which will spin the finished product.

Color Sensor – This Color sensor is used for detecting the color, so that we can make the bridge go in the sequence you picked. For example, if you pick blue, green, yellow, and red, then the bridge will go in the order you have picked. We have also changed the color tags location, so that it will be easier to program the movement part and pickup the spinner part right at the spot where the bridge stops. The original design by LEGO will make it harder because you have to calculate how far the bridge need to travel after detecting the color tag. But, it is easier for operator to identify the part position.

Spinner control – This is used to release the spinner after it was spun and it also controls the spin lock which lets the spinner lock it in place prior it can be spun. It works by using the motor to turn the red handle up to unlock the spin lock and let it spin. The second step is turning the handle to it’s maximum to release the spinner after it is spun.

However, we made some improvement by moving the bridge ahead to push the handle to maximum instead of using the spinner control. So that the spinner will not hit the the bridge wheels.

Calibration

The Bridge

def bridge_position():
    bridge_move(-180)
    
    while True:
        if rail_color_detect() == 1:
            bridge_move(0)
            ev3.speaker.beep()
            ev3.speaker.beep()
            break
    bridge_move(180) # Prepare a position to call for head calibration
    wait(600)
    bridge_move(0)
    mbox.send('Calibration')
    mbox.wait()
    bridge_move(-180)
    while True:
        if rail_color_detect() == 1:
            bridge_move(0)
            ev3.speaker.beep()
            ev3.speaker.beep()
            break    

The Head

def calibration():
    # Height Control Calibration, max. drive = -526, best pickup position = -490
    height_control.dc(10)
    height_control.run_until_stalled(500,Stop.HOLD,50)
    height_control.reset_angle(0)
    
    # Switch tool : 200 is spinning tool 0 is pickup tool
    # Use 300 to hold the spinner, -300 to release, i.e. pickup tool
    switch_tools.run_until_stalled(-100,Stop.HOLD)
    spinning_tool.run_angle(500,-300,Stop.HOLD)

In the bridge program we made the bridge go back to the first color which is white (we added white ourselves), when the color sensor detects white, it will stop the bridge and move half a step forward whilst communicating with another program that controls the head. When the head received a message saying “calibration” the program will call the calibration program that we have defined as a function. In the function “calibration” we made the height of the head reset to the max which we made it go up to the top, after resetting the height of the head, we switched the tool back to the pickup tool, then we reset the pickup tool by opening the claw so that it can pick up the spinner. Then, the bridge will return the zero position, i.e. the white tag.

How does the program work?

It is not difficult to create the program from moving the bridge, control the head. However, it took us hours to fine tune all the parameters and settings.

Communication

Since this factory using two EV3 Bricks. Using EV3-G (LabView) can support Daisy Chain, i.e. one program to control multiple devices. However, we don’t want to deal with EV3-G anymore and EV3 Classroom just support one device. So, we go for EV3DEV, we pair two EV3 Bricks via Bluetooth and communicate by messaging each others. You can refer to these link for EV3DEV Bluetooth messaging.

Color Detection

# Define the functions
def rail_color_detect():# 1 - White, 2 - Yellow, 3 - Blue, 4 - Green, 5 - Red, 0 - unstable, 99 - others
    for i in range(0,300):
        if i == 0:
            first_color = rail_detector.color()
        if rail_detector.color() != first_color:
            return 0
    if first_color == Color.WHITE:
        return 1
    if first_color == Color.YELLOW:
        return 2
    if first_color == Color.BLUE:
        return 3
    if first_color == Color.GREEN:
        return 4
    if first_color == Color.RED:
        return 5
    return 99

When we developed the program, we found that LEGO color sensor is running unstable, it would provide incorrect color (i.e. noise) occasionally and make our program actioning wrongly. To fix the color sensor misjudgment, we created a color detect function to detect the color 300 times. If all 300 detections are the same, then we can confirm the color detect correctly and return the color code – 1. White, 2. Yellow, 3. Blue, 4. Green and 5. Red. For wrong color detect, it will be 0. 99 for others.

The Bridge

# Start of the main program            
ev3.speaker.beep()
bridge_position()

ev3.speaker.set_volume(100)
ev3.speaker.say("Scan the color now")
color_seq = []
color_selection()

ev3.speaker.beep()

for i in range(0,4):
    bridge_move(180)

    while True:        
        if rail_color_detect() == color_seq[i]:
            bridge_move(0)
            mbox.send('Pickup')
            mbox.wait()
            
            bridge_move(-180)
            while True:
                if rail_color_detect() == 1:
                    bridge_move(0)
                    break
                        
            mbox.send('Release')
            mbox.wait()
            break

mbox.send('Spin')
mbox.wait()
bridge_move(1500)
wait(1000)
bridge_move(0)
mbox.send('All Done')

In this program we reset the bridge to the starting point at “the white tag”, then we scan the color sequence that we want to pickup the spinner part in. The next part we make the bridge go to the color tag in the sequence, then call the head to pickup the spinner part. After it picks up the spinner part, the head will send a message back to the bridge and it will go back to the first tag “white” and again calls the head to releases the spinner part. These steps will be repeated until last part is placed.

The Head

while True:
    mbox.wait()
    message = mbox.read()    
    if message == 'Calibration':
        calibration()
    if message == 'Pickup':
        pickup_parts() 
    if message == 'Release':
        release_parts()
    if message == 'Spin':
        spin_spinner()
    if message == 'All Done':
        break    
    mbox.send('Done')

The head receive a message from the bridge, if the message matches one of the defined message, it will do the corresponding function, such as Pickup – pickup the spinner part. Once the action is done, a message ‘Done’ will send back to the head to confirm that it’s finished.

Pickup Part

def pickup_parts():
    height_control.run_angle(500,-460)
    spinning_tool.run_angle(1000,300,Stop.HOLD)
    height_control.run_angle(500,460)

That’s pretty simple, makes the head go down, pickup the spinner, then go up.

Release Part

def release_parts():
    height_control.run_angle(500,-150)
    spinning_tool.stop()
    wait(300)
    switch_tools.run_angle(500,20,Stop.HOLD,wait=True)
    spinning_tool.run_angle(500,-300)
    switch_tools.run_angle(500,-20)
    height_control.run_angle(500,150)

In this function we made the head go down, adjust the pickup tool angle, release the part , then go up. Why do we need to adjust the tool angle? It is because when the bridge moves on the rail, the vibration will tilt the spinner holder a bit and causing the positioning to be wrong for the part placement, so we adjust the tool angle to compensate this.

Start the spinner and release it

def spin_spinner():
    switch_tools.run_until_stalled(1000)
    switch_tools.hold()
    height_control.run_angle(50,-130,Stop.HOLD,wait=False)
            
    for i in range(0,6):
        spinning_tool.run_angle(100,-30)
        spinning_tool.run_angle(100, 30)
    
    release_tool.run_angle(500,170)
    switch_tools.stop()
    spinning_tool.dc(-100) # Must rotate in Clockwise Direction, otherwise the head will be mis-aligned
    wait(5000)
    height_control.run_angle(1500,130,Stop.HOLD,wait=True)
    # release_tool.run_angle(1500,60)
    mbox.send('Move!')
    spinning_tool.dc(0) 

It switch the tool switcher to the spinning tool. Then we make the head go down to a height that is considerable for the spinner to spin perfectly. While the head goes down the spinning tool will turn left & right for 10 times ( this is for locking in the angle so we get a better spinning angle). After the spinning tool locks on the spinner, it will spin in 1500 rotation per seconds for 5 seconds, then the bridge will move back quickly. When the bridge move back it will trigger the spinner controller to release the spinner. Originally, the spinner controller should be trigger by the handle. However, the spinner will hit the bridge wheel and failed the mission. So, we move the bridge front to avoid it.

Build instruction and the program

We created the program from scratch without referring any example, you can download from below.

LEGO official build instruction

LEGO MindStorms – Stair Climber

This project is so funny and cool, we are controlling a robot which contain the cart and the lifting arm, so that it can climb stairs. Looks like a Mars rover!!

Features of the robot

Gyro Sensor – It is used to detect or reference the degrees that the project is tilting towards. If the object is tilting forward, then the numbers will be positive, it will be negative if it is tilting backwards. How do we use this gyro sensor in our robot? It can be used to set a limit on how much you should tilt. For example, you want your cart to tilt to -15 then stop and reset degrees counter, then the gyro sensor will come in handy because it detects how much the robot tilts.

Touch sensor – It is used to send signals when something goes in contact with it. In this stair climbing project, the touch sensor is used as a calibration. When the top part come in contact with the touch sensor, then it will reset the degrees counter and it will return to the straight form. Why is the calibration important? The calibration is used to limit how much the belt should go. If the belt goes over the limit, then the motor will malfunction or in worst scenario, even break the motor.

‘Little Fella’ – This little guy’s function is kind of confusing, I thought it was just a noise maker at first. This little guy’s function was unknown until we tested the project. When we tried our first run, we realize that the little guy has the function to stop the middle wheel from moving backwards. What a powerful little fella…

Calibration

This program is the calibration part. It is the most important part of the whole program, because we always need to check the limit and identify the zero point, so that it will not mess up the motor movement because of wrong degree number.

Moreover, we also identify the gyro sensor horizontal level and rest to zero when it sitting on the floor.

So what I did in this program is that I made the lifting arm go up until it presses the button, when it presses the button it will reset the degrees counted so that the top will be the zero point, then the lifting arm goes down by moving the motor clockwise by 2900 degrees. (we got it manually) then we reset the Gyro sensor since it is horizontal to the floor.

Stair Climber Movement concept

When the stair climber moves forward and hit the wall, the front wheel will make the cart going upward and result as tiling up. Once we detect tiling for a certain degree, we will activate the lifting arm to push the cart upwards until it reach the top of stair, we call this landing. Once the cart landed, it will be no longer tilting upward, i.e. no tilting or very small tilting. Then, we will collect the lifting arm to the top of stair and moving forward for the next climbing.

IMPORTANT! When we doing above action, we need to control the back wheel action carefully. If back wheel pushing too much, the cart will flip over because of the center of gravity changed.

How’s the program working?

  1. Check whether the gyro sensor detects tiling and if it is more than 15 degree, i.e. the forward wheel rotate against the wall and the head tilt up. If yes, it will start the lifting action 2.
  2. Determine if the cart landed or the lifting arm reach the max. Otherwise, keep the arm lifting action.
  3. We need to balance the speed of the wheels. If we make the back wheel too fast, the cart will flip over while going up the stairs. If the back wheel goes too slow, the cart will be too slow for the landing and it will be stuck at the edge of the stairs. We also need to make the front wheel rotating speed synchronized to the lifting arm speed.
  4. We have to balance the cart if it is tilting so much like it is going to fall. We have to stop the back wheel so that the cart will not keep moving forward, i.e. change the center of gravity. So, we stop the back wheel for a certain tilting angle that the cart may flip over.
  5. We need to stop the wheels before the lifting arm move up or else the lifting arm is going to snap. After stopping the wheels, we pull the lifting arm back up to the original place. Then, the stair climber keep going for next stair.

Build instruction and the program

We created the program from scratch without referring any example, you can download from below.

LEGO Offical build instruction

I also attached the link for LEGO EV3 Classroom for your quick reference, click here.

LEGO MindStorms – Elephant

https://www.youtube.com/watch?v=tW2K-LxkUUQ

Calibration

The best part for this elephant is installed two sensors to detect the trunk and the head movement, so that we can program this to avoid the motor over-driving the head and trunk to induce unnecessary damaged. Calibration is very important for machine and robot, identify the zero (or required) position, so that they can be working within the expected range and accuracy. The calibration will run every time when the elephant start because we got unknown starting position of the head and trunk. Once, it dance, it will be always the same.

As you can see above, there are two sensors installed – color sensor and touch sensor.

During the head is moving up, the color sensor is detecting the color in it’s front. When the elephant raises it’s head up to the limit, a red color should be detected. So, we did the coding as below.

When we setup a robot, we actually need to do some manual work to understanding your robot. Prior we wrote this calibration program, we analysis the movement of the head to understand the moving direction and the stroke of the head, keep those as preset ‘parameter’ – we got ‘head (D) down’ is ‘-800’.

Then, we start the program in a loop by detecting the color sensor until it detect ‘red’. Before the red color being detect, the motor controlling the head keep moving up for every 10 degree, so that the head will not be crushed.

Once red color detected, the movement will stop and the motor degree count reset to the ‘zero’ position, so that we can control the elephant with a range of 0 to -800.


Same as what we done for the head calibration, we also need to do some manual work to understand the moving direction and the stroke of the trunk, we got ‘trunk (B) down’ is ‘900’.

Using exactly the same coding for the calibration but change the detective sensor from color sensor to touch sensor because touch sensor was installed when the trunk move up and it will hit the touch sensor.

Again, once the touch sensor is touched, stop the raising trunk and reset the degrees count, set this as ‘zero’ position.

Build instruction and the program

We created the program from scratch without referring any example, you can download from below.

Water Level Sensor

We tried the water level sensor today and using a RGB to indicate different water level, let us show you how to do this.

How does water level sensor work

When we use the water level sensor, we need to connect to 5V, GND and Signal to the Arduino board. It contains ten copper strips in the sensor area that are actually connected to the 5V and signal, they interlace to each others. When we immerse the sensor into water (or solution), it induces conductivity, i.e. current. The more the sensor immerse into the water, the higher conductivity will be resulted. It gives a higher signal back to the analog input in the Arduino board or what board you are using.

 

 

 

 

 

Measurement and calibration

Since the water level senor will give the signal in an analog number, but not the actual water level. We need to correlate the analog number to the water level. For example, when we immerse the water sensor into 20mm of the water it will give a signal of 600. So, we wrote a function to measure the analog number for each water level we need.

void calibration(){
  int i;
  
  digitalWrite(2,HIGH);

  for (i=0;i<=4;i++){
    Serial.print("put your sensor in the '");
    Serial.print(i);
    Serial.print("' mark");
    delay(2000);
    water_mark[i] = analogRead(A2);
    Serial.print(" ");
    Serial.println(water_mark[i]);
  
  }

  Serial.println("Calibration Complete");
  delay(3000);
}

We created a function – calibration() to record the analog number for each different water levels, we defined an array water_mark[] to record them. We needed to record 4 different levels, using a for loop to read the levels one by one from analogRead(A2) as we connected the water level sensor to analog input pin – A2. We also used the Serial.print to communicate with the user so that the user knows where he has to put the water level sensor in order for the program to read the water level accurately.

void RGB_water_sensor(int vol){
  digitalWrite(12,HIGH);

  if (vol < water_mark[1]){
    analogWrite(Red,255);
    analogWrite(Blue,255);
    analogWrite(Green,255);
  }
  if (vol >= water_mark[1] && vol < water_mark[2]){
    analogWrite(Red,0);
    analogWrite(Blue,0);
    analogWrite(Green,0);
  }
  if (vol >= water_mark[2] && vol < water_mark[3]){
    analogWrite(Red,255);
    analogWrite(Blue,255);
    analogWrite(Green,0);    
  }
  if (vol >= water_mark[3] && vol < water_mark[4]){
    analogWrite(Red,255);
    analogWrite(Blue,0);
    analogWrite(Green,255);
  }
    if (vol >= water_mark[4]){
    analogWrite(Red,0);
    analogWrite(Blue,255);
    analogWrite(Green,255);
  }  
}

Then, we used the information from the calibration() function to define which water level we use to make the RGB light change. When we call this function – RGB_water_sensor(int vol), we need to provide the existing water level value. It will put into variable vol and compare with different water_mark[] we captured in the calibration() function. If vol (the existing water level) below the water_mark[1], it will be no display. If vol between water_mark[1] and water_mark[2], the color is white. It will be green when between water_mark[2] and water_mark[3]. Then, will be blue and red colors for between 3 & 4 and over 4.

See our separated post for how RGB working.

Conductivity of different liquid

We conducted a small experiment by comparing the measuring value between Water, Coca Cola, Perrier, Energy Drink and Vinegar, took 10 set data of each and compared the average value. Do you know which one get the best conductivity?

WaterCoke ColaPerrierLucozadeVinegar
5mm454543467552562
20mm597571532580606
40mm618584551589640
Conductitivity24531

We thought that Lucozade has the best conductivity because it is ‘energy drink’. However, based on the experiment, the best liquid conductivity level is vinegar, and the Perrier is the worst. It is because vinegar contains acid ions but surprised us that Perrier is the worst, it should contain minerals which help conductivity. Moreover, what we observed is that when we put water in the 5mm mark of the water sensor it is the lowest conductivity out of all the liquid we used.