# 6. Secondary Development
## 6.1 Arduino Development
### 6.1.1 What is the Inverse Kinematics
This lesson aims at helping users basically learning about the principle of inverse kinematics. The further learning and practical application of the inverse kinematics of robotic arm is available in the folder "**7. Inverse Kinematics Lesson**"
* **What is it?**
Forward kinematics refers to process of obtaining position and velocity of end effector, given the known joint angles and angular velocities. In other word, the position information of end effector can be obtained when then joint angle and linkages parameters are known.
Inverse Kinematics is the inverse function or algorithm of Forward Kinematics. According to the position and post of the end effector along with linkages parameters, the joint position can be calculated, i.e., Given the robot’s end-effector positions, inverse kinematics can determine an appropriate joint configuration.
(1) Establish Coordinate System
A coordinate system must be established to describe the motion of an object. MaxArm uses x-y-z axes coordinate system (unit:mm) and takes the the base centre of robotic arm as original point (0,0,0), as the figure shown below.
The correspondence relationship between the movement orientation of end effector and the values of x-y-z axes is shown below (user per se as reference):
| **Coordinate axis** | **control orientation** |
| :---: | :---: |
| x | Control the end effector of robotic arm to move left or right (As the x value is positive, it moves to the right. As the x value is negative, it moves to the left. ) |
| y | Control the end effector of robotic arm to move forward and backward. (As the y value is negative,it moves backward. As the y value is positive, it moves forward.) |
| z | Control the end effector of robotic arm to move up and down (As the z value is negative, it moves up. As the z value is positive, it moves down.) |
(2) Project Operation
After learning about the principle and spatial concept of inverse kinematics, the control method of inverse kinematics can be mastered by a simple routine. You can follow the steps below to run the game.
① Install and connect Arduino. (Please refer to the tutorial in folder ["**4. Underlying Files Learning--Arduino Development--Lesson 1 Set Development Environment**"](4.Underlying_Program_Learning_checked.md#set-arduino-development-environment))
② Double click to open **"Arduino IDE"**
.
③ Click **"File"--"Open".**
④ Select the program "**kinematics_demo.ino**" in the folder ["**5.MaxArm Hardware Basics Learning--Arduino Development--Game Programs--Program Files--kinematics_demo**"](Appendix.md), and click "**Open**".
⑤ Check the board model. Click **"Tools"**--**"Board"** and select **"ESP 32 Dev Module"**. (If the model of development board has been configured when setting the development environment, you can skip this step.)
⑥ Select the corresponding port of ESP32 controller in **"Tools"** -- **"Port"**. (Here take the port **"COM5"** as example. Please select the port based on your computer. If COM1 appears, please do not select because it is the system communication port but not the actual port of the development port.)
⑦ If you are not sure the port number, please open the "**This PC**" and click "**Properties**"--"**Device Manger**" in turns to check the corresponding port number (the device is with CH340).
⑧ After selecting, confirm the board "**ESP32 Dev Module**" in the lower right corner and the port number "**COM5**" (it is an example here, please refer to the actual situation).
⑨ Then click on
icon to verify the program. If no error, the status area will display **"Compiling"**--**"Compile complete"** in turn. After compiling, the information such as the current used bytes, and occupied program storage space will be displayed.
⑩ After compiling, click on
icon to upload the program to the development board. The status area will display **"Compiling"**--**"Uploading"**--**"Complete"** in turn. After uploading, the status area will stop printing the uploading information.
(3) Project Analysis
[Source Code](../_static/source_code/Secondary_Development.zip)
The complete program is as follow:
{lineno-start=1}
```python
#include "ESPMax.h"
#include "_espmax.h"
// Inverse kinematics basic example
void setup(){
ESPMax_init();
go_home(2000); // Move the robotic arm back to the initial position
Serial.begin(9600);
Serial.println("start...");
}
bool start_en = true;
void loop(){
if(start_en){
float x,y,z;
float pos[3];
// XYZ position of the robotic arm’s initial pose
x = 0;
y = -(L1 + L3 + L4);
z = (L0 + L2);
// Print XYZ position via serial, unit: millimeter
Serial.print(x);
Serial.print("; ");
Serial.print(y);
Serial.print("; ");
Serial.println(z);
// Since the initial position of the robotic arm is already at the edge of its reachable workspace, it must first move downward along the Z-axis. Otherwise, the arm will not be able to
// move along the X or Y axes.
// set_position(pos,t), pos={x,y,z}; x: X-axis coordinate, y: Y-axis coordinate, z: Z-axis coordinate, t: total movement time (the longer the time, the slower the speed)
pos[0] = x; pos[1] = y; pos[2] = z-100;
set_position(pos,2000); // Move Z-axis 100mm down relative to the initial position
delay(2000);
pos[0] = x; pos[1] = y; pos[2] = z;
set_position(pos,2000); // Reset robotic arm to initial pose
delay(1000);
start_en = false;
}
else{
delay(500); // Delay 500 ms
}
```
① Import function library
Before the robotic arm starts to move, the encapsulation library and underlying library of inverse kinematics need to be imported.
{lineno-start=1}
```C++
#include "ESPMax.h"
#include "_espmax.h"
```
② Calculate the initial position of robotic arm
According to the linkage parameters of L0-L4 defined in kinematics underlying library.
{lineno-start=1}
```C++
#ifndef _ESPMAX_H
#define _ESPMAX_H
#define L0 84.4
#define L1 8.14
#define L2 128.4
#define L3 138.0
#define L4 16.8
```
Calculate the initial position of the end effector. (Use the L0-L4 values to get x=0, y=162.94, z=212.8)
{lineno-start=18}
```C++
// XYZ position of the robotic arm’s initial pose
x = 0;
y = -(L1 + L3 + L4);
z = (L0 + L2);
```
③ Control robotic arm
Use the function `set_position()` to control the end effector to move.
Take the code `set_position(pos,2000)` as example.
{lineno-start=34}
```C++
pos[0] = x; pos[1] = y; pos[2] = z-100;
set_position(pos,2000); // Move Z-axis 100mm down relative to the initial position
delay(2000);
pos[0] = x; pos[1] = y; pos[2] = z;
set_position(pos,2000); // Reset robotic arm to initial pose
delay(1000);
```
The first parameter "**pos**" is a set of valuea representing the position values of the end effector on x-y-z axis.
Among them, `pos[0]` represents the x-axis value of the initial position of the end-effector.
`pos[1]` represents the the y-axis value of the initial position of the end-effector.
**"pos[2]"** represents the end-effector moves down to 100mm. And the position of the end effector can be set by modifying the x,y and z values.
For example, if want to control the end-effector to move 200mm to the left. (its position relative to the original moves to 200mm to the left), set x value plus 200. If want to move to 200 to the right, set x-200.
If want to directly move to the set position, for example, move to 200mm on x axis, you just need to set x=200.
The second parameter **"2000"** is the running time and the unit is ms.
(4) Inverse kinematics library analysis
The path to the inverse kinematics library: [Appendix--8. Controller Underlying Files--Arduino Development--ESPMax.cpp](Appendix.md)
① Import head file and define pin
{lineno-start=1}
```c++
#include "ESPMax.h"
#include "_espmax.h"
#include "LobotSerialServoControl.h"
```
Import the inverse kinematics and servo head files.
{lineno-start=5}
```c++
#define SERVO_SERIAL_RX 35
#define SERVO_SERIAL_TX 12
#define receiveEnablePin 13
#define transmitEnablePin 14
HardwareSerial HardwareSerial(2);
LobotSerialServoControl BusServo(HardwareSerial,receiveEnablePin,transmitEnablePin);
```
Define the serial communication pin.
② Initialization
{lineno-start=12}
```c++
float ORIGIN[3] ={ 0, -(L1 + L3 + L4), (L0 + L2)};
float positions[3];
void ESPMax_init(){
BusServo.OnInit();
HardwareSerial.begin(115200,SERIAL_8N1,SERVO_SERIAL_RX,SERVO_SERIAL_TX);
}
```
`ORIGIN[3]` is the initial position of the end effector calculating from the linkage length.
The function `ESPMax_init()` is used for initialization
The function `BusServo.OnInit()` is the servo configuration initialization. `HardwareSerial.begin()` is serial communication configuration. "**115200**" is the baud rate. "**SERIAL_8N1**" refers to the working mode. `SERVO_SERIAL_RX` is the pin number of RX port. `SERVO_SERIAL_TX` is the pin number of TX port.
③ Control a single servo
{lineno-start=20}
```c++
int set_servo_in_range(int servo_id, int p, int duration){
if(servo_id == 3 & p < 470) p = 470;
if(servo_id == 2 & p > 700) p = 700;
BusServo.LobotSerialServoMove(servo_id, p, duration);
return int(1);
}
```
The function `set_servo_in_range()` is used to control the movement of a single servo, and limit the position of servo ID2 and ID3. The ID3 Servo can not be less than 470 impulse and the No.4 can not be less than 700. The parameter `servo_id` is servo ID number and the parameter **"p"** is servo impulse. The parameter **"duration"** is the running time.
The function `BusServo.LobotSerialServoMove()` in BusServo library controls a single servo to move.
④ Calculate servo pulse
{lineno-start=27}
```c++
float* position_to_pulses(float pos[3], float* pul){
float angles[3];
inverse(pos,angles);
deg_to_pulse(angles,pul);
return pul;
}
```
The function `position_to_pulses()` is used to calculate the servo pulse. The parameter "**position**" is position coordinate. "**angles**" is servo angle. "**pulse**" is servo pulse. Then the value of servo pulse will be returned.
The function `inverse()` is used to calculate the servo angle according to the coordinates.
The function `deg_to_pulse()` is used to calculate the servo pulse according to the servo angle.
⑤ Calculate robotic arm position
{lineno-start=34}
```c++
float* pulses_to_position(float pul[3], float* pos){
float joints[3];
pulse_to_deg(pul,joints);
forward(joints,pos);
return pos;
}
```
The function `pulses_to_position()` is used to calculate the coordinate of robotic arm position. The parameter `pul[3]` is servo pulse. The coordinate of robotic arm is calculated according to the servo pulses, and then the coordinate value is returned.
⑥ The movement of robotic arm
{lineno-start=41}
```c++
int set_position(float pos[3], int duration){
float x = pos[0];
float y = pos[1];
float z = pos[2];
if(z > 255) z = 255;
if(sqrt(x*x + y*y) < 50) return int(0);
float angles[3];
inverse(pos,angles);
float pul[3];
deg_to_pulse(angles,pul);
for(int i=0; i<3; i++){
positions[i] = pul[i];
BusServo.LobotSerialServoMove(i+1,pul[i],duration);
delay(2);
}
return int(1);
}
```
The function `set_position()` is used to control the robotic arm to move, and add the position limit. The parameter "**position**" is the position coordinate and the "**duration**" is the running time.
Use judgement statement to limit the robotic arm position. The coordinate of z-axis can not be greater than 225. The root of the sum of the squares of the x and y axes coordinates should be greater than 50, which means the end effector should be outside the circle with the coordinate origin as the center and the radius of 50. The unit is millimeter.
Then use **"for"** to control the ID1, ID2 and ID3 servos to rotate.
⑦ Back to the initial position
{lineno-start=83}
```c++
void go_home(int duration){
set_position(ORIGIN, duration);
}
```
The function `go_home()` is used to get robotic arm back to the initial position. The parameter **"duration"** is the running time and the parameter `self.set_position()` is to control robotic arm to move. The parameter `ORIGIN` is the coordinate of the initial position set in program.
⑧ Read position coordinate
{lineno-start=93}
```c++
float* read_position(float* pos){
float pul[3];
for(int i=0; i<3; i++){
pul[i] = BusServo.LobotSerialServoReadPosition(i+1);
}
pulses_to_position(pul,pos);
}
```
Use the function `self.bus_servo.get_position()` to get the pulse value of servo ID1, ID2, and ID3.
Get the x,y,z position coordinate by calculating the robotic arm position function `pulses_to_position()`. Then the x, y and z values are obtained.
* **Project Principle**
In this lesson, ultrasonic sensor will be used to detect object and the detection result will be displayed on digital tube.
The used glowing ultrasonic ranging module integrates ultrasonic transmitting circuits, ultrasonic receiving circuits, digital processing circuits, etc. inside the ranging chip. The module adopts IIC communication interface, and can read the measured distance through IIC communication.
Ultrasonic sensors have two main components: the transmitter and the receiver.
The module will automatically send eight 40khz square waves and detect if there are signals are sent back. If there are signals back, output a high level. Then the duration time is time when the ultrasonic waves are sent and returns.
Measured distance(L) =(high level time* the speed of time(340M/S))/2.
The ultrasonic probes integrates two RGB lights, not only can adjust the light brightness, but also through the red (R), green (G), blue (B) three color channel changes and their superposition on each other to achieve colorful color changes.
The digital tube has a 4-digit red LED for displaying numbers, decimal points and some special characters. This module is compact and easy to use, you can apply this module in robotics projects for displaying sensor values such as speed, time, fraction, temperature, distance, etc.
Firstly, import corresponding libraries and initialize ultrasonic sensor, buzzer, servo and digital tube module.
Then set the distance measurement conditions,three threshold intervals are set in program. Different intervals is distinguished with different colors.
(1) Preparation
① Hardware
Please assemble ultrasonic sensor and digital tube to the corresponding position on MaxArm according to the tutorial in folder ["Lesson 1 Module Assembly"](https://drive.google.com/drive/folders/163jyDz9PPCgfqxb5LVVTDQdGs1Vb1gCu?usp=sharing) under the same directory.
② Software
Please connect MaxArm to **"Arduino IDE"** according to the tutorial in folder ["**4. MaxArm Underlying Program Learning--Arduino Development--Lesson 1 Set Development Environment**"](4.Underlying_Program_Learning_checked.md#anchor_4_2).
(2) Program Download
[Source Code](../_static/source_code/Secondary_Development.zip)
① Click on
icon to open **"Arduino IDE"**.
② Click **"File"--"Open"** in turn.
③ Open the program **"Ultrasound_display.ino"** in the folder ["**6.Secondary Development--Arduino Development--Sensor-extension Game--Program Files--Ultrasonic Detection and Digital Tube Disply--Ultrasound_display**"](../_static/source_code/Secondary_Development.zip).
④ Select the corresponding port of Arduino controller in **"Tools"--"Port"**. (Here take the port **"COM5"** as example. Please select the port based on your computer. If COM1 appears, please do not select because it is the system communication port but not the actual port of the development port.)
⑤ If you’re not sure about the port number, please open the **"This PC"** and click **"Properties"--"Device Manger"** in turns to check the corresponding port number (the device is with CH340). Then select the correct port on **"Arduino IDE"**.
⑥ After selecting, confirm the board **"ESP32 Dev Module"** in the lower right corner and the port number **"COM5"** (it is an example here, please refer to the actual situation).
⑦ Then click on
icon to verify the program. If no error, the status area will display **"Compiling"**--**"Compile complete"** in turn. After compiling, the information such as the current used bytes, and occupied program storage space will be displayed.
⑧ After compiling, click on
icon to upload the program to the development board. The status area will display **"Compiling"**--**"Uploading"**--**"Complete"** in turn. After uploading, the status area will stop printing the uploading information.
(3) Project Outcome
Place a block or other objects in front of ultrasonic sensor, and then the corresponding distance will be displayed on digital tube. If the distance between sensor and object is less than 50cm, red light is on. If the distant is between 50cm and 100cm, green light is on. When the distance is farther than 100cm, blue light is on.
(4) Program Instruction
① Import Function Library
Firstly, call ultrasonic sensor library, PWM servo library, buzzer library and other related libraries.
{lineno-start=1}
```c++
#include "ESPMax.h"
#include "Buzzer.h"
#include "TM1640.h"
#include "Ultrasound.h"
#include "SuctionNozzle.h"
```
② Ultrasonic Detection
Then set variables to read the measured distance.
{lineno-start=32}
```c++
void loop() {
char text[6];
int distance = ultrasound.GetDistance(); // Read distance from ultrasound
Serial.println(distance); // Print distance in mm to Serial
sprintf(text, "%4d", distance); // Convert distance to string
```
③ LED Display
Display the distance value on digital tube.
{lineno-start=37}
```c++
module.setDisplayToString(text); // Display distance on digital display
```
④ Light color setting
If the distance between sensor and object is less than 50cm, green light is on.
If the distant is between 50cm and 100cm, red light is on.
When the distance is farther than 100cm, blue light is on.
{lineno-start=32}
```c++
void loop() {
char text[6];
int distance = ultrasound.GetDistance(); // Read distance from ultrasound
Serial.println(distance); // Print distance in mm to Serial
sprintf(text, "%4d", distance); // Convert distance to string
module.setDisplayToString(text); // Display distance on digital display
if (distance > 0 && distance <= 50)
ultrasound.Color(0, 255, 0, 0, 255, 0); //Green
else if (distance > 50 && distance <= 100)
ultrasound.Color(255, 0, 0, 255, 0, 0); //Red
else if (distance > 100)
ultrasound.Color(0, 0, 255, 0, 0, 255); //Blue
delay(300); // Delay 300 ms
```
### 6.1.3 Ultrasonic Detection and Sucking
* #### Ultrasonic Sensor Assembly
* **Working Principle**
Ultrasonic sensors is a sensor that converts ultrasonic signals into other energy signals (usually electrical signals). There are two probes on ultrasonic sensor for receiving and transmitting ultrasound.
Firstly, import the corresponding library and initialize ultrasonic sensor, buzzer, servo and action groups.
Next, the object is detected by ultrasonic sensor and the measured distance is read by I2C protocol. After determining the distance, MaxArm will perform the corresponding action based on the determined result.
Then, execute the functions for controlling action group, starting buzzer and air pump to suck the object to the side.
The path to the source code of the program is [6.Secondary Development--Arduino Development--Sensor Development--Program Files--Ultrasonic Detection and Suction--Ultrasound_clamp--Ultrasound_clamp.ino](../_static/source_code/Secondary_Development.zip)
{lineno-start=8}
```c++
Ultrasound ultrasound; //Instantiate Ultrasound class
void setup(){
Buzzer_init();
ESPMax_init();
Nozzle_init();
Valve_on();
go_home(2000);
delay(2000);
Valve_off();
Serial.begin(115200);
Serial.println("start...");
ultrasound.Breathing(30, 50, 60, 20, 30, 50); // Ultrasound RGB breathing mode
```
(1) Preparation
① Hardware
Please assemble the ultrasonic sensor to the corresponding position on MaxArm according to the tutorial in folder ["**Lesson 1 Sensor Assembly**"](https://drive.google.com/drive/folders/1POUNWLcJIw78PuDaLR4BYaeipkhMTGSK?usp=sharing) under the same directory.
② Software
Please connect MaxArm to **"Arduino IDE"** according to the tutorial in folder ["**4. Underlying Program Learning--Arduino Development--Lesson 1 Set Development Environment**"](4.Underlying_Program_Learning_checked.md#anchor_4_2).
(2) Program Download
[Source Code](../_static/source_code/Secondary_Development.zip)
① Click on
icon to open **"Arduino IDE"**.
② Click **"File"--"Open"** in turn.
③ Select the program **"Ultrasound_clamp.ino"** in the folder ["**6.Secondary Development--Arduino Development--Sensor-extension Game--Program Files--Ultrasonic Detection and Suction--Ultrasound_clamp**"](../_static/source_code/Secondary_Development.zip).
④ Select the corresponding port of Arduino controller in **"Tools"--"Port"**. (Here take the port **"COM5"** as example. Please select the port based on your computer. If COM1 appears, please do not select because it is the system communication port but not the actual port of the development port.)
⑤ If you’re not sure about the port number, please open the **"This PC"** and click **"Properties"--"Device Manger"** in turns to check the corresponding port number (the device is with CH340). Then select the correct port on **"Arduino IDE"**.
⑥ After selecting, confirm the board **"ESP32 Dev Module"** in the lower right corner and the port number **"COM5"** (it is an example here, please refer to the actual situation).
⑦ Then click on
icon to verify the program. If no error, the status area will display **"Compiling"--"Compile complete"** in turn. After compiling, the information such as the current used bytes, and occupied program storage space will be displayed.
⑧ After compiling, click on
icon to upload the program to the development board. The status area will display **"Compiling"--"Uploading"--"Complete"** in turn. After uploading, the status area will stop printing the uploading information.
(3) Project Outcome
After putting the block on the fixed detection position, the buzzer will beep after the block is detected by the ultrasonic sensor. MaxArm will move to the front of the block and start the air pump to suck it, and moves to the left. Then placing the block and stopping the air pump. Finally, MaxArm is reset.
(4) Program Instruction
① Import Library File
Firstly, the ultrasonic sensor, PWM servo, buzzer and other related library files are called.
{lineno-start=1}
```c++
#include "ESPMax.h"
#include "Buzzer.h"
#include "Ultrasound.h"
#include "SuctionNozzle.h"
```
② Ultrasonic Detection
Then read the measured distance by setting the variable. To reduce errors, take the average.
{lineno-start=25}
```c++
void loop(){
float pos[3];
int distance = 0;
for(int i=0; i<5; i++){
distance += ultrasound.GetDistance(); //Read distance from ultrasound
delay(200);
}
int dis = int(distance/5); //Take average value
```
③ Detection Feedback
Set a distance range with another if judgement statement. When the measured distance meets the set conditions, the buzzer will sound for 100ms.
{lineno-start=33}
```c++
if(60 < dis & dis < 80){ //Check if distance is within 60~80mm
setBuzzer(100); //Set buzzer to sound for 100ms
```
④ Control Robotic Arm
By setting the position parameter, MaxArm will carry the block to the corresponding position.
{lineno-start=35}
```c++
pos[0] = 0;pos[1] = -160;pos[2] = 100;
set_position(pos,1500); //Move above the color block
delay(1500);
pos[0] = 0;pos[1] = -160;pos[2] = 85;
set_position(pos,800); //Suction the color block
Pump_on(); //Turn on pump
delay(1000);
pos[0] = 0;pos[1] = -160;pos[2] = 200;
set_position(pos,1000); //Lift robot arm
delay(1000);
pos[0] = 160;pos[1] = 0;pos[2] = 200;
set_position(pos,1500); //Move above placement area
delay(1500);
pos[0] = 160;pos[1] = 0;pos[2] = 90+overlay*40;
set_position(pos,1000); //Move to placement area
delay(1000);
Valve_on(); //Close pump and open valve
pos[0] = 160;pos[1] = 0;pos[2] = 200;
set_position(pos,1000); //Lift robot arm
delay(1000);
Valve_off(); //Close valve
```
This section uses `set_position()` function to control the robotic arm. Take the code `set_position(pos,1500)` as example.
The first parameter "pos" represents the position of the robotic arm on x, y and z axes. Among them, `pos[0]` represents the coordinate of x axis, `pos[1]` represents the coordinate of y axis, and `pos[2]` represents the coordinate of z-axis.
The second parameter "1500" represents the running time and its unit is ms.
Use `Pump_on()` function to turn on the air pump, `Valve_on()` function to turn off the air pump and turn on the solenoid valve, and `Valve_off()` function to turn off the solenoid valve.
### 6.1.4 Ultrasonic Detection and Stacking
* #### Touch Sensor Assembly
Please connect the touch sensor to IO23 IO22 port on controller with 20cm 4Pin cable,as shown in the figure below.
* **Working Principle**
Ultrasonic sensor can convert ultrasonic signals into other energy signals (usually electrical signals). There are two probes on ultrasonic sensor for receiving and transmitting ultrasound.
The path to the source code of the program is [6.Secondary Development--Arduino Development--Program Files--Ultrasonic Detection and Stacking--Ultrasound_palletize--Ultrasound_palletize.ino](../_static/source_code/Secondary_Development.zip).
{lineno-start=33}
```c++
if(60 < dis & dis < 80){ //Check if distance is within 60~80mm
setBuzzer(100); //Set buzzer to sound for 100ms
pos[0] = 0;pos[1] = -160;pos[2] = 100;
set_position(pos,1500); //Move above the color block
delay(1500);
pos[0] = 0;pos[1] = -160;pos[2] = 85;
set_position(pos,800); //Suction the color block
Pump_on(); //Turn on pump
delay(1000);
pos[0] = 0;pos[1] = -160;pos[2] = 200;
set_position(pos,1000); //Lift robot arm
delay(1000);
pos[0] = 160;pos[1] = 0;pos[2] = 200;
set_position(pos,1500); //Move above placement area
delay(1500);
pos[0] = 160;pos[1] = 0;pos[2] = 90+overlay*40;
set_position(pos,1000); //Move to placement area
delay(1000);
Valve_on(); //Close pump and open valve
pos[0] = 160;pos[1] = 0;pos[2] = 200;
set_position(pos,1000); //Lift robot arm
delay(1000);
Valve_off(); //Close valve
go_home(1500); //Reset robotic arm
delay(1500);
```
Firstly, import the corresponding library and initialize ultrasonic sensor, buzzer, servo and action groups.
Next, the object is detected by ultrasonic sensor and the measured distance is read by I2C protocol. After determining the distance, MaxArm will perform the corresponding action based on the determined result.
Then, execute the functions for controlling action group, buzzer and air pump to suck the detected object to the side and stack it.
(1) Preparation
① Hardware
Please assemble the ultrasonic sensor to the corresponding position on MaxArm according to the tutorial in folder ["**Lesson 1 Sensor Assembly**"](https://drive.google.com/drive/folders/1VBOyzV1UHNolWDobSpLVHHroOgz4vAZ1?usp=sharing) under the same directory.
② Software
Please connect MaxArm to **"Arduino IDE"** according to the tutorial in folder ["**4. Underlying Program Learning--Arduino Development--Lesson 1 Set Development Environment**"](4.Underlying_Program_Learning_checked.md#anchor_4_2).
(2) Program Download
[Source Code](../_static/source_code/Secondary_Development.zip)
① Click on
icon to open **"Arduino IDE"**.
② Click **"File"--"Open"** in turn.
③ Select the program **"Ultrasound_palletize.ino"** in the folder ["6.Secondary Development--Arduino Development--Sensor-extension Game--Program Files--Ultrasonic Detection and Suction--Ultrasound_clamp"](../_static/source_code/Secondary_Development.zip).
④ Select the model of the development board. Click **"Tools"--" Board"** and select **"ESP 32 Dev Module"** (If the model of the development board has been configured when setting the development environment, you can skip this step).
⑤ Select the corresponding port of Arduino controller in **"Tools"--"Port"**. (Here take the port **"COM5"** as example. Please select the port based on your computer. If COM1 appears, please do not select because it is the system communication port but not the actual port of the development port.)
⑥ If you’re not sure about the port number, please open the **"This PC"** and click **"Properties"--"Device Manger"** in turns to check the corresponding port number (the device is with CH340). Then select the correct port on **"Arduino IDE"**.
⑦ After selecting, confirm the board **"ESP32 Dev Module"** in the lower right corner and the port number **"COM5"** (it is an example here, please refer to the actual situation).
⑧ Then click on
icon to verify the program. If no error, the status area will display **"Compiling"--"Compile complete"** in turn. After compiling, the information such as the current used bytes, and occupied program storage space will be displayed.
⑨ After compiling, click on
icon to upload the program to the development board. The status area will display **"Compiling"--"Uploading"--"Complete"** in turn. After uploading, the status area will stop printing the uploading information.
(3) Project Outcome
After the block is detected by the ultrasonic sensor, the buzzer will beep once. Then, the suction nozzle will move to the block and suck it after turning on the air pump, and carry the block to the stacking area for stacking. After performing the stacking action three times, MaxArm will return to the initial posture.
(4) Program Instruction
① Import library file
The path to the source code of the program is [6.Secondary Development--Arduino Development--Sensor-extension Game--Program Files--Ultrasonic Detection and Stacking--Ultrasound_palletize--Ultrasound_palletize.ino](../_static/source_code/Secondary_Development.zip)
Before running program, the ultrasonic sensor, buzzer, PWM servo, bus servo and air pump and other related library files are called.
{lineno-start=1}
```c++
#include "ESPMax.h"
#include "Buzzer.h"
#include "Ultrasound.h"
#include "SuctionNozzle.h"
```
② Ultrasonic Detection
Use the `ultrasound.getDistance()` function to measure the distance, and then take the average of five detected distance values.
{lineno-start=27}
```c++
for(int i=0; i<5; i++){
distance += ultrasound.GetDistance(); //Read distance from ultrasound
delay(200);
}
int dis = int(distance/5); //Take average value
```
③ Control Robotic Arm
Determine the distance of the front object first. If the object is between 60 and 80mm, MaxArm will perform the corresponding action.
{lineno-start=33}
```c++
if(60 < dis & dis < 80){ //Check if distance is within 60~80mm
setBuzzer(100); //Set buzzer to sound for 100ms
pos[0] = 0;pos[1] = -160;pos[2] = 100;
set_position(pos,1500); //Move above the color block
delay(1500);
pos[0] = 0;pos[1] = -160;pos[2] = 85;
set_position(pos,800); //Suction the color block
Pump_on(); //Turn on pump
delay(1000);
pos[0] = 0;pos[1] = -160;pos[2] = 200;
set_position(pos,1000); //Lift robot arm
delay(1000);
pos[0] = 160;pos[1] = 0;pos[2] = 200;
set_position(pos,1500); //Move above placement area
delay(1500);
pos[0] = 160;pos[1] = 0;pos[2] = 90+overlay*40;
set_position(pos,1000); //Move to placement area
delay(1000);
Valve_on(); //Close pump and open valve
pos[0] = 160;pos[1] = 0;pos[2] = 200;
set_position(pos,1000); //Lift robot arm
delay(1000);
Valve_off(); //Close valve
go_home(1500); //Reset robotic arm
delay(1500);
```
The buzzer is controlled by using the `setBuzze()` function. Take the code `setBuzzer(100)` as example.
The first parameter "100" is the sounding time of buzzer and the unit is ms.
The robotic arm is controlled by `set_position()` function. Take the code `set_position(pos,1000)` as example.
The first parameter "pos" represents the position of the robotic arm on x, y and z axes. Among them, `pos[0]` represents the coordinate of x axis, `pos[1]` represents the coordinate of y axis, and `pos[2]` represents the coordinate of z-axis.
The second parameter "1000" represents the running time and its unit is ms.
### 6.1.5 Touch Detection and Placement
* **Working Principle**
This lesson uses touch sensor based on the principle of capacitive sensing. After supplying the touch sensor power, the touching will be sensed when our fingers or metal touch the metal sensing plate. In the meantime, the signal terminal OUT will output low level signal, vice verse. According to this characteristics, the robotic arm can be controlled to carry out the corresponding action.
The path to the source code of the program is [6.Secondary Development--Arduino Development--Sensor Development--Program Files--Touch Detection and Placement--TouchSensor_put--TouchSensor_put.ino](../_static/source_code/Secondary_Development.zip).
{lineno-start=6}
```c++
#include "LobotSerialServoControl.h"
// Touch placement
#define sensor_pin 23 // Define touch sensor pin
void setup(){
// Initialize libraries
Buzzer_init();
ESPMax_init();
Nozzle_init();
PWMServo_init();
pinMode(sensor_pin, INPUT_PULLUP); // Set sensor pin to internal pull-up mode
Serial.begin(9600);
Serial.println("start...");
setBuzzer(100); // Set buzzer to sound for 100 ms
go_home(2000); // Move robotic arm to initial position
SetPWMServo(1,1500,2000); // Set suction nozzle servo to initial position
```
Firstly, import the corresponding libraries and initialize buzzer, servo and action group.
Next, create the functions of buzzer and touch control. Set the buzzer to make sound feedback and the robotic arm to perform the corresponding action when short press the touch sensor.
Then, execute the function for controlling action, buzzer, and air pump to suck the detected object to the side and place it.
(1) Preparation
① Hardware
Please assemble the touch sensor to the corresponding position on MaxArm according to the tutorial in folder ["**Lesson 1 Sensor Assembly**"](https://drive.google.com/drive/folders/1S33PUmc7MYvAOPMxJzt9IelzsKt9nBYn?usp=sharing) under the same directory.
② Software
Please connect MaxArm to **"Arduino IDE"** according to the tutorial in folder ["**4. Underlying Program Learning--Arduino Development--Lesson 1 Set Development Environment**"](4.Underlying_Program_Learning_checked.md#anchor_4_2).
(2) Program Download
[Source Code](****)
① Click on
icon to open **"Arduino IDE"**.
② Click **"File"--"Open"** in turn.
③ Select the program **"TouchSensor_put.ino"** in the folder ["6.Secondary Development--Arduino Development--Sensor-extension Game--Program Files--Button Detection and Placement--TouchSensor_put"](../_static/source_code/Secondary_Development.zip).
④ Select the model of the development board. Click **"Tools"--" Board"** and select **"ESP 32 Dev Module"** (If the model of the development board has been configured when setting the development environment, you can skip this step).
⑤ Select the corresponding port of Arduino controller in **"Tools"--"Port"**. (Here take the port **"COM5"** as example. Please select the port based on your computer. If COM1 appears, please do not select because it is the system communication port but not the actual port of the development port.)
⑥ If you’re not sure about the port number, please open the **"This PC"** and click **"Properties"--"Device Manger"** in turns to check the corresponding port number (the device is with CH340). Then select the correct port on **"Arduino IDE"**.
⑦ After selecting, confirm the board **"ESP32 Dev Module"** in the lower right corner and the port number **"COM5"** (it is an example here, please refer to the actual situation).
⑧ Then click on
icon to verify the program. If no error, the status area will display **"Compiling"--"Compile complete"** in turn. After compiling, the information such as the current used bytes, and occupied program storage space will be displayed.
⑨ After compiling, click on
icon to upload the program to the development board. The status area will display **"Compiling"--"Uploading"--"Complete"** in turn. After uploading, the status area will stop printing the uploading information.
(3) Project Outcome
After the buzzer beeps once, the robotic arm will suck and place the blocks in a line. When three blocks are placed completely, the buzzer will make **"DiDi"** sound as a feedback, and then a round of placement is finished.
(4) Program Instruction
The path to the source code of the program is [6.Secondary Development--Arduino Development--Sensor-extension Game--Program Files--Touch Detection and Placement--TouchSensor_put--TouchSensor_put.ino](../_static/source_code/Secondary_Development.zip) (The source code of the library files can be found under the same path).
If the program is modified, you can find the backup files in Appendix.
① Import Function library
Before executing the program, the Python function libraries related to the buzzer, PWM servo, bus servo and air pump need to be imported.
{lineno-start=1}
```c++
#include "Buzzer.h"
#include "ESPMax.h"
#include "_espmax.h"
#include "ESP32PWMServo.h"
#include "SuctionNozzle.h"
#include "LobotSerialServoControl.h"
```
② Define the Pin of Sensor
Firstly, define the P23 pin of the main chip as the as the access terminal of the touch sensor.
{lineno-start=10}
```c++
#define sensor_pin 23 // Define touch sensor pin
```
③ Initialization Setting
Initialize the driver library and set the pin of sensor as pull-up mode.
{lineno-start=12}
```c++
void setup(){
// Initialize libraries
Buzzer_init();
ESPMax_init();
Nozzle_init();
PWMServo_init();
pinMode(sensor_pin, INPUT_PULLUP); // Set sensor pin to internal pull-up mode
Serial.begin(9600);
Serial.println("start...");
setBuzzer(100); // Set buzzer to sound for 100 ms
go_home(2000); // Move robotic arm to initial position
SetPWMServo(1,1500,2000); // Set suction nozzle servo to initial position
```
④ Touch detection
When touching the metal surface of the sensor, the signal terminal will output low level and the buzzer will sound for 100ms.
{lineno-start=36}
```c++
if(sensor_state == 0.0){ // Touch sensor sets pin LOW when detecting target
Serial.print("num: ");
Serial.println(num+1);
setBuzzer(100); //Set buzzer to sound for 100 ms
```
The buzzer is controlled by `buzzer.setBuzze()` function. Take the code `buzzer.setBuzzer(100)` as example.
The parameter **"100"** represents the sounding time of buzzer and the unit is ms.
⑤ Placement Setting
By setting the position parameter, MaxArm will transport the block to the corresponding position.
{lineno-start=41}
```c++
set_position(pos,1500); //Move above the block
delay(1500);
pos[0] = 0;pos[1] = -160;pos[2] = 85;
set_position(pos,800); //Suction the color block
Pump_on(); //Turn on pump
delay(1000);
pos[0] = 0;pos[1] = -160;pos[2] = 180;
set_position(pos,1000); //Lift the arm
delay(1000);
pos[0] = 120;pos[1] = (-20-60*num);pos[2] = 180;
set_position(pos,1500); //Move above placement area
Serial.println(angle_pul[num]);
delay(100);
SetPWMServo(1,angle_pul[num],1000); // Angle compensation to align block
delay(500);
pos[0] = 120;pos[1] = (-20-60*num);pos[2] = (83+num);
set_position(pos,1000); //Move to placement area
delay(1200);
Valve_on(); //Turn off pump, open valve
pos[0] = 120;pos[1] = (-20-60*num);pos[2] = 200;
set_position(pos,1000); //Lift the arm
delay(1000);
Valve_off(); //Close valve
```
This section uses `arm.set_position()` function to control the robotic arm to move on the set axes. Take the code `set_position(pos,1500)` as example.
The first parameter **"pos"** represents the position of the robotic arm on x, y and z axes. Among them, `pos[0]` represents the coordinate of x axis, `pos[1]` represents the coordinate of y axis, and `pos[2]` represents the coordinate of z-axis.
The second parameter **"1500"** represents the running time and its unit is ms.
The `Pump_on()` function is used to turn on the air pump, and the `Valve_on()` function is used to turn off the air pump.
### 6.1.6 Infrared Detection and Control
* **Working Principle**
Infrared obstacle avoidance is a photoelectric sensor integrating IR transmitter and IR receiver. Featuring long detection distance and low interference from visible light , it is widely used in robot and assembly line piecework, etc.
This sensor detects obstacle by transmitting and receiving infrared. When the infrared transmitted by the sensor meets the obstacle ahead, the infrared will be reflected to the receiving terminal.
The path of the program file: [6.Secondary Development--Arduino Development--Sensor-extension Game--Program Files--Infrared Detection and Control--InfraredSensor_contro--InfraredSensor_control.ino](../_static/source_code/Secondary_Development.zip)
{lineno-start=34}
```c++
if(sensor_state == 0.0){ // Infrared sensor detects target, pin goes low
setBuzzer(100); //Set buzzer to sound for 100ms
pos[0] = 0;pos[1] = -160;pos[2] = 100;
set_position(pos,1500); //Move above the color block
delay(1500);
pos[0] = 0;pos[1] = -160;pos[2] = 85;
set_position(pos,800); //Suction the color block
Pump_on(); //Turn on the pump
delay(1000);
pos[0] = 0;pos[1] = -160;pos[2] = 200;
set_position(pos,1000); //Lift the arm
delay(1000);
pos[0] = 70;pos[1] = -150;pos[2] = 200;
set_position(pos,800); //Move above the placement area
delay(800);
SetPWMServo(1, 2200, 500);
delay(200);
pos[0] = 70;pos[1] = -150;pos[2] = 90;
set_position(pos,800); //Move to placement area
delay(800);
pos[0] = 130;pos[1] = -150;pos[2] = 88;
set_position(pos,500); //Push slightly to the left
delay(500);
Valve_on(); //Close the pump, open the solenoid valve
pos[0] = 130;pos[1] = -150;pos[2] = 200;
set_position(pos,1000); //Lift the arm
delay(1000);
Valve_off(); //Close the solenoid valve
go_home(1500);
```
When the sensor detects this signal, it will send it to the microcontroller for processing. The closer the obstacle is, the stronger the reflection intensity; the farther the obstacle is, the weaker the reflection intensity. Different surface color has different reflection intensity. White is the strongest and black is the weakest.
Then, the object is detected by the infrared sensor and buzzer will make sound. MaxArm will perform the corresponding action.
Finally, execute the function for controlling action, buzzer, air pump to suck and place the object.
(1) Preparation
① Hardware
Please assemble the infrared sensor to the corresponding position on MaxArm according to the tutorial in folder ["**Lesson 1 Sensor Assembly**"](https://drive.google.com/drive/folders/1t1lAAC1WoEwiIFtmzEJD88fvmnsiiKd8?usp=sharing) under the same directory.
② Software
Please connect MaxArm to **"Arduino IDE"** according to the tutorial in folder ["**4. Underlying Program Learning--Arduino Development--Lesson 1 Set Development Environment**"](4.Underlying_Program_Learning_checked.md#anchor_4_2).
(2) Program Download
[Source Code](../_static/source_code/Secondary_Development.zip)
① Click on
icon to open **"Arduino IDE"**.
② Click **"File"--"Open"** in turn.
③ Select the program **"InfraredSensor_control.ino"** in the folder ["**6.Secondary Development--Arduino Development--Sensor-extension Game--Program Files--Infrared Detection and Control--InfraredSensor_control**"](../_static/source_code/Secondary_Development.zip).
④ Select the model of the development board. Click **"Tools"--" Board"** and select **"ESP 32 Dev Module"** (If the model of the development board has been configured when setting the development environment, you can skip this step).
⑤ Select the corresponding port of Arduino controller in **"Tools"--"Port"**. (Here take the port **"COM5"** as example. Please select the port based on your computer. If COM1 appears, please do not select because it is the system communication port but not the actual port of the development port.)
⑥ If you’re not sure about the port number, please open the **"This PC"** and click **"Properties"--"Device Manger"** in turns to check the corresponding port number (the device is with CH340). Then select the correct port on **"Arduino IDE"**.
⑦ After selecting, confirm the board **"ESP32 Dev Module"** in the lower right corner and the port number **"COM5"** (it is an example here, please refer to the actual situation).
⑧ Then click on
icon to verify the program. If no error, the status area will display **"Compiling"--"Compile complete"** in turn. After compiling, the information such as the current used bytes, and occupied program storage space will be displayed.
⑨ After compiling, click on
icon to upload the program to the development board. The status area will display **"Compiling"--"Uploading"--"Complete"** in turn. After uploading, the status area will stop printing the uploading information.
(3) Project Outcome
When the colored block is detected by infrared sensor, the robotic arm will move to the block and suck it, then transfer and place the block to the placement area. Finally, turn off the air pump.
(4) Program Instruction
① Import and Initialize
The path to the source code of the program is [6.Secondary Development--Arduino Development--Sensor-extension Game--Program Files--Infrared Detection and Control--InfraredSensor_contro--InfraredSensor_control.ino](../_static/source_code/Secondary_Development.zip) (The source code of the library files can be found under the same path).
If the program is modified, you can find the backup files in Appendix.
Before running the program, the buzzer, kinematics, kinematics encapsulation library, PWM servo, suction nozzle and other related library files need to be imported.
{lineno-start=1}
```c++
#include "Buzzer.h"
#include "ESPMax.h"
#include "_espmax.h"
#include "ESP32PWMServo.h"
#include "SuctionNozzle.h"
#include "LobotSerialServoControl.h"
```
Then, initialize the library file and the robotic arm.
{lineno-start=10}
```c++
#define sensor_pin 23 // Define the infrared sensor pin
void setup(){
// Initialize driver libraries
Buzzer_init();
ESPMax_init();
Nozzle_init();
PWMServo_init();
pinMode(sensor_pin, INPUT_PULLUP); // Set sensor pin to internal pull-up mode
Serial.begin(115200);
Serial.println("start...");
setBuzzer(100); // Set buzzer to sound for 100ms
go_home(2000); // Move the arm to the initial position
SetPWMServo(1,1500,2000); // Set suction nozzle servo to initial position
}
```
② Infrared Detection
Use the `digitalRead()` function to read the detected value of the infrared sensor and then use the `for()` function to detect several times.
When the object is detected by infrared sensor, `sensor_pin` is 0, otherwise, it is 1. Then the value of the detected value plus `sensor_state` is assigned to `sensor_state`. If the `sensor_state` is equal to 0.0 after five rounds, the object is detected, otherwise, no object is detected.
{lineno-start=26}
```c++
void loop(){
float pos[3];
// Multiple detections
float sensor_state = 0.0;
for(int i=0; i<5; i++){
sensor_state += digitalRead(sensor_pin);
delay(50); // Delay 50ms
}
```
③ Control Robotic Arm
When the object is detected by infrared sensor, MaxArm will perform the corresponding action.
{lineno-start=34}
```c++
if(sensor_state == 0.0){ // Infrared sensor detects target, pin goes low
setBuzzer(100); //Set buzzer to sound for 100ms
pos[0] = 0;pos[1] = -160;pos[2] = 100;
set_position(pos,1500); //Move above the color block
delay(1500);
pos[0] = 0;pos[1] = -160;pos[2] = 85;
set_position(pos,800); //Suction the color block
Pump_on(); //Turn on the pump
delay(1000);
pos[0] = 0;pos[1] = -160;pos[2] = 200;
set_position(pos,1000); //Lift the arm
delay(1000);
pos[0] = 70;pos[1] = -150;pos[2] = 200;
set_position(pos,800); //Move above the placement area
delay(800);
SetPWMServo(1, 2200, 500);
delay(200);
pos[0] = 70;pos[1] = -150;pos[2] = 90;
set_position(pos,800); //Move to placement area
delay(800);
pos[0] = 130;pos[1] = -150;pos[2] = 88;
set_position(pos,500); //Push slightly to the left
delay(500);
Valve_on(); //Close the pump, open the solenoid valve
pos[0] = 130;pos[1] = -150;pos[2] = 200;
set_position(pos,1000); //Lift the arm
delay(1000);
Valve_off(); //Close the solenoid valve
go_home(1500); //Reset the arm to initial position
```
The buzzer is controlled by `setBuzze()` function. Take the code `setBuzzer(100)` as example.
The parameter **"100"** is the sounding time of the buzzer and the unit is ms.
The robotic arm is controller by `set_position()` function. Take the code `set_position(pos,1500)` as example.
The first parameter **"pos"** represents the position of the robotic arm on x, y and z axes. Among them, `pos[0]` represents the coordinate of x axis, `pos[1]` represents the coordinate of y axis, and `pos[2]` represents the coordinate of z-axis.
The second parameter **"1500"** is the running time and the unit is ms.
Use `Pump_on()` function to turn on the air pump, `Valve_on()` function to turn off the air pump,and `Valve_off()` function to turn off the solenoid valve.
Finally, use `go_home()` function to make robotic arm return to the initial posture. Take the code `go_home(1500)` as example.
The parameter **"1500"** is the time for the robotic arm to reset and the unit is ms.
### 6.1.7 Dual Infrared Detection and Sorting
* **Working Principle**
Infrared obstacle avoidance is a photoelectric sensor integrating IR transmitter and IR receiver. Featuring long detection distance and low interference from visible light , it is widely used in robot and assembly line piecework, etc.
This sensor detects obstacle by transmitting and receiving infrared. When the infrared transmitted by the sensor meets the obstacle ahead, the infrared will be reflected to the receiving terminal.
The path of the program file: ["**6.Secondary Development--Sensor-extension Game--Arduino Development--Program Files--Dual Infrared Detection and Sorting--InfraredSensor_sorting--InfraredSensor_sorting.ino**"](../_static/source_code/Secondary_Development.zip)
{lineno-start=34}
```c++
if (sensor_left == 0.0) { // Left sensor detects target, pin goes low
Serial.println("infrared_left");
setBuzzer(100); //Set buzzer to sound for 100ms
pos[0] = 70;
pos[1] = -165;
pos[2] = 120;
set_position(pos, 1500); //Move above the color block
delay(1500);
pos[0] = 70;
pos[1] = -165;
pos[2] = 86;
set_position(pos, 800); //Suction the color block
Pump_on(); //Turn on the pump
delay(1000);
pos[0] = 70;
pos[1] = -165;
pos[2] = 200;
set_position(pos, 1000); //Lift the arm
delay(1000);
pos[0] = 150;
pos[1] = -35;
pos[2] = 200;
set_position(pos, 800); //Move above placement area
delay(800);
SetPWMServo(1, 1800, 500);
```
When the signal is detected by infrared sensors, it will travel to microcontroller for processing. The closer the obstacle is, the stronger the reflection intensity; the farther the obstacle is, the weaker the reflection intensity. Different surface color has different reflection intensity. White is the strongest and black is the weakest.
Then, the object is detected by the infrared sensor and buzzer will make sound. MaxArm will perform the corresponding action.
Finally, execute the function for controlling action, buzzer, air pump to pick up and place the object.
:::{Note}
* For better recognition effect, the sensitive of infrared sensor will be adjusted high, but also more susceptible to the impact of objective factors such as ambient light. If you need to adjust the sensitivity, you can refer to the content in **"6. Sensitivity Adjustment"** in this lesson.
:::
(1) Preparation
① Hardware
Please refer to ["**Lesson 1 Sensor Assembly**"](https://drive.google.com/drive/folders/1Lbevt8HJlGXFVZKr797nfBonQkSB-0Kg?usp=sharing) to assemble infrared sensors to the corresponding position on MaxArm.
② Software
Please connect MaxArm to **"Arduino IDE"** according to the tutorial in folder ["**4. Underlying Program Learning--Arduino Development--Lesson 1 Set Development Environment**"](4.Underlying_Program_Learning_checked.md#anchor_4_2).
(2) Program Download
[Source Code](../_static/source_code/Secondary_Development.zip)
① Click on
icon to open **"Arduino IDE"**.
② Click **"File"--"Open"** in turn.
③ Open the program **"InfraredSensor_sorting.ino"** in the folder ["**6.Secondary Development--Arduino Development--Sensor-extension Game--Program Files--Dual Infrared Detection and Sorting--InfraredSensor_sorting**."](../_static/source_code/Secondary_Development.zip)
④ Select the model of the development board. Click **"Tools"--" Board"** and select **"ESP 32 Dev Module"** (If the model of the development board has been configured when setting the development environment, you can skip this step).
⑤ Select the corresponding port of Arduino controller in **"Tools"--"Port"**. (Here take the port **"COM5"** as example. Please select the port based on your computer. If COM1 appears, please do not select because it is the system communication port but not the actual port of the development port.)
⑥ If you’re not sure about the port number, please open the **"This PC"** and click **"Properties"--"Device Manger"** in turns to check the corresponding port number (the device is with CH340). Then select the correct port on **"Arduino IDE"**.
⑦ After selecting, confirm the board **"ESP32 Dev Module"** in the lower right corner and the port number **"COM5"** (it is an example here, please refer to the actual situation).
⑧ Then click on
icon to verify the program. If no error, the status area will display **"Compiling"--"Compile complete"** in turn. After compiling, the information such as the current used bytes, and occupied program storage space will be displayed.
⑨ After compiling, click on
icon to upload the program to the development board. The status area will display **"Compiling"--"Uploading"--"Complete"** in turn. After uploading, the status area will stop printing the uploading information.
(3) Project Outcome
When the block is detected, MaxArm will rotate to the corresponding position and turn on air pump to pick up the block, and then place it to placement area in the same side. After the whole process is done, turn off the air pump.
:::{Note}
* If there are blocks placed in front of the two infrared sensors, according to the program setting, MaxArm will first pick up the color block on the left side (Take robot arm as the first person view).
:::
(4) Program Instruction
① Import function library and Initialize
The path of the program file: ["**6. Secondary Development--Arduino Development--Program Files--Dual Infrared Detection and Sorting--InfraredSensor_sorting--InfraredSensor_sorting.ino**"](../_static/source_code/Secondary_Development.zip). If the program is modified, you can find a backup file in Appendix.
Before running the program, the buzzer, kinematics, kinematics encapsulation library, PWM servo, suction nozzle and other related library files need to be imported first.
{lineno-start=1}
```c++
#include "Buzzer.h"
#include "ESPMax.h"
#include "_espmax.h"
#include "ESP32PWMServo.h"
#include "SuctionNozzle.h"
#include "LobotSerialServoControl.h"
```
Then, initialize the library file and the robotic arm.
{lineno-start=10}
```c++
#define infrared_left 23 // Define left infrared sensor pin
#define infrared_right 32 // Define right infrared sensor pin
void setup() {
// Initialize driver libraries
Buzzer_init();
ESPMax_init();
Nozzle_init();
PWMServo_init();
pinMode(infrared_left, INPUT_PULLUP); // Set sensor pin to internal pull-up mode
pinMode(infrared_right, INPUT_PULLUP);
Serial.begin(115200);
Serial.println("start...");
setBuzzer(100); // Set buzzer to sound for 100ms
go_home(2000); // Move the arm to initial position
SetPWMServo(1, 1500, 2000); // Set suction nozzle servo to initial position
}
```
② Infrared Detection
Use the `digitalRead()` function to read the detected value and use the `for()` function to detect several times to get accurate result. Take the left infrared sensor as example. When object is detected by the left infrared sensor, `infrared_left` is 0, otherwise, it is 1. Then the detected value plus `sensor_left` is assigned to `sensor_left`. If the `sensor_left` is equal to 0.0 after five rounds, the object is detected, otherwise, no object is detected.
{lineno-start=28}
```c++
void loop() {
float pos[3];
// Multiple detections
float sensor_left = 0.0;
float sensor_right = 0.0;
for (int i = 0; i < 5; i++) {
sensor_left += digitalRead(infrared_left); //Read left sensor value
sensor_right += digitalRead(infrared_right);
delay(50); // Delay 50ms
}
```
③ Infrared Detection Feedback
When an object is detected by infrared sensor, MaxArm will execute the corresponding action. Here take the left infrared sensor for example.
{lineno-start=40}
```c++
if (sensor_left == 0.0) { // Left sensor detects target, pin goes low
Serial.println("infrared_left");
setBuzzer(100); //Set buzzer to sound for 100ms
pos[0] = 70;
pos[1] = -165;
pos[2] = 120;
set_position(pos, 1500); //Move above the color block
delay(1500);
pos[0] = 70;
pos[1] = -165;
pos[2] = 86;
set_position(pos, 800); //Suction the color block
Pump_on(); //Turn on the pump
delay(1000);
pos[0] = 70;
pos[1] = -165;
pos[2] = 200;
set_position(pos, 1000); //Lift the arm
delay(1000);
pos[0] = 150;
pos[1] = -35;
pos[2] = 200;
set_position(pos, 800); //Move above placement area
delay(800);
SetPWMServo(1, 1800, 500);
delay(200);
pos[0] = 150;
pos[1] = -35;
pos[2] = 90;
set_position(pos, 800); //Move to placement area
delay(800);
pos[0] = 150;
pos[1] = 10;
pos[2] = 88;
set_position(pos, 500); //Move slightly to place
delay(500);
Valve_on(); //Close pump, open solenoid valve
pos[0] = 150;
pos[1] = 10;
pos[2] = 200;
set_position(pos, 1000); //Lift the arm
delay(1000);
Valve_off(); //Close solenoid valve
go_home(1500); //Reset arm to initial position
delay(200);
SetPWMServo(1, 1500, 500);
delay(1500);
```
Take `setBuzze()` function, `set_position()` function, `Pump_on()` function and `go_home()` for example.
The `setBuzze()` is a function to control buzzer. Call **"Buzzer.h"** function in the same directory as **"InfraredSensor_sorting.ino"** program. Fill in the parentheses with the duration time of buzzer, and the unit is ms. The code `setBuzzer(100)` means that the buzzer will respond for 100ms after the infrared sensor detects an object, and then the next `set_potision()` function will be executed.
{lineno-start=42}
```c++
setBuzzer(100); //Set buzzer to sound for 100ms
```
The `set_position()` is a function to call robotic arm. Call **"ESPMax.h"** function in the same folder as **"InfraredSensor_sorting.ino"** program. Fill in the parentheses with the coordinate values and duration time. Take the code `set_position(pos,1500)` for example, `pos[0]`, `pos[1]`, `pos[2]` is the representative of the robot arm corresponding to the position on the XYZ axis, 1500 is the running time, the unit is milliseconds (ms). After that, the `Pump_on()` function is executed in the next step.
{lineno-start=43}
```c++
pos[0] = 70;
pos[1] = -165;
pos[2] = 120;
set_position(pos, 1500); //Move above the color block
```
The `Pump_on()` is a function to control air pump. `Pump_on()` function is to control the air pump on; `Valve_on()` function is used to turn off air pump and open solenoid valve; `Valve_off()` function to turn off the solenoid valve. Call **"InfraredSensor_sorting.ino"** function in the same folder as the **"SuctionNozzle.h"** function, after the implementation of the next `go_home()` function.
{lineno-start=52}
```c++
Pump_on(); //Turn on the pump
```
{lineno-start=76}
```c++
Valve_on(); //Close pump, open solenoid valve
```
{lineno-start=82}
```c++
Valve_off(); //Close solenoid valve
```
The `go_home()` is a function to reset robotic arm. Cal **"ESPMax.h"** function in the same folder as **"InfraredSensor_sorting.ino"** function.Fill in the parentheses with the action duration time, and the unit is ms. Take the code `go_home(1500)` for example. The parameter "1500" is the time it takes to complete the reset action. When this function is finished, the program will execute 1500ms delay function and then end this recognition and sorting actions and wait for the next recognition signal.
{lineno-start=83}
```c++
go_home(1500); //Reset arm to initial position
```
(5) Adjust Sensitivity
There is an adjustable potentiometer knob on infrared obstacle avoidance sensor for adjusting the measuring distance. When performing the related games, if the measurement effect it not good enough, the measurement sensitivity of sensor can be adjusted by adjusting the knob.
It is recommended to use phillips screwdriver. Rotate the knob clockwise, as the figure shown below, to increase the infrared emission intensity and the measurement distance; rotate it counterclockwise to weaken the infrared emission intensity and decrease the measurement distance.
Please take notice of the following two tips:
① Since the warm light (incandescent light, sunlight, etc) contains more infrared component, there will be a certain interference between infrared to affect the detection outcome. When using it, special attention should be paid to the surrounding environment. Therefore, you can not adjust the sensitivity alone.
② The sensitivity adjustment has is set a threshold, which you can regard it as a critical point. If the sensitivity exceeds the critical point, its value will return to the initial state.
③ Sensitivity adjustment needs to be based on the actual needs of the project. It is better to be adjusted to the most suitable conditions.
### 6.1.8 Color Recognition
* **Working Principle**
The color sensor is a sensor with various functions such as recognizing the color of objects, detecting the brightness of the surrounding environment, realizing object proximity detection and non-contact gesture detection, etc.
This lesson will use the color sensor for recognizing and comparing the RGB value of object. These sensors generally determine whether the detected color is consistent with the set one by using RGB (red, green, and blue) LED light sources and the ratio of R, G, and B wavelengths in the reflected light of an object.
The path of the program file: ["**6.Secondary Development--Sensor-extension Game--Arduino Development--Program Files--Color Recognition--Color_Detect--Color_Detect.ino**"](../_static/source_code/Secondary_Development.zip)
{lineno-start=66}
```c++
void loop() {
if (ColorDetect()) { // Check if the color sensor detects a color
float color_num = 0.0;
for (int i = 0; i < 5; i++) {
color_num += ColorDetect(); // Multiple detections to avoid misreading
delay(80);
}
color_num = color_num / 5.0; // Take the average of the results; if not integer, detection is unstable
if (color_num == 1.0) {
Serial.println("Red"); // Red detected, print 'Red'
ultrasound.Color(255, 0, 0, 255, 0, 0); // Turn ultrasound module red
}
else if (color_num == 2.0) {
Serial.println("Green"); // Green detected, print 'Green'
ultrasound.Color(0, 255, 0, 0, 255, 0); // Turn ultrasound module green
}
else if (color_num == 3.0) {
Serial.println("Blue"); // Blue detected, print 'Blue'
ultrasound.Color(0, 0, 255, 0, 0, 255); // Turn ultrasound module blue
}
else { // If result is not an integer, do nothing
ultrasound.Color(255, 255, 255, 255, 255, 255);
}
}
```
Firstly, import the corresponding libraries and initialize ultrasonic sensor and color sensor.
Then read and calculate the RGB value of the object, and print out the color result.
Finally, the ultrasonic sensor emits light of the corresponding color.
(1) Preparation
① Hardware
Please assemble the color sensor and ultrasonic sensor to the corresponding position on MaxArm according to the tutorial in folder ["**Lesson 1 Sensor Assembly**"](https://drive.google.com/drive/folders/1Vh8iTJdAVLZHvT1g2vKul3au7pNEhoFW?usp=sharing) under the same directory.
② Software
Please connect MaxArm to **"Arduino IDE"** according to the tutorial in folder ["**4. Underlying Program Learning--Arduino Development--Lesson 1 Set Development Environment**"](4.Underlying_Program_Learning_checked.md#anchor_4_2).
(2) Program Download
[Source Code](../_static/source_code/Secondary_Development.zip)
① Click on
icon to open **"Arduino IDE"**.
② Click **"File"--"Open"** in turn.
③ Select the program **"InfraredSensor_control.ino"** in the folder ["**6.Secondary Development--Sensor-extension Game--Arduino Development--Program Files--Infrared Detection and Control--InfraredSensor_control**"](../_static/source_code/Secondary_Development.zip).
④ Select the model of the development board. Click **"Tools"**--**" Board"**and select **"ESP 32 Dev Module"** (If the model of the development board has been configured when setting the development environment, you can skip this step).
⑤ Select the corresponding port of Arduino controller in **"Tools"--"Port"**. (Here take the port **"COM5"** as example. Please select the port based on your computer. If COM1 appears, please do not select because it is the system communication port but not the actual port of the development port.)
⑥ If you’re not sure about the port number, please open the **"This PC"** and click **"Properties"**--**"Device Manger"** in turns to check the corresponding port number (the device is with CH340). Then select the correct port on **"Arduino IDE"**.
⑦ After selecting, confirm the board **"ESP32 Dev Module"** in the lower right corner and the port number **"COM5"** (it is an example here, please refer to the actual situation).
⑧ Then click on
icon to verify the program. If no error, the status area will display **"Compiling"**--**"Compile complete"** in turn. After compiling, the information such as the current used bytes, and occupied program storage space will be displayed.
⑨ After compiling, click on
icon to upload the program to the development board. The status area will display **"Compiling"**--**"Uploading"**--**"Complete"** in turn. After uploading, the status area will stop printing the uploading information.
⑩ Then click on the serial port monitor icon in the upper right corner.
⑪ Select the baud rate to **"115200"** in the pop-up window.
(3) Project Outcome
After the colored block is detected by the color sensor, the glowing ultrasonic sensor will emit the corresponding color light.
(4) Program Instruction
① Import Function Library
Before executing the program, the I2C protocol, ultrasonic sensor, color sensor, buzzer, PWM servo, bus servo, infrared sensor and air pump and other related Python function libraries need to be imported.
{lineno-start=1}
```python
import time
from machine import Pin, I2C
from Ultrasonic import ULTRASONIC
from Color_sensor import COLOR
from Buzzer import Buzzer
from espmax import ESPMaX
from PWMServo import PwMServo
from BusServo import BusServo
from RobotControl import RobotControl
from SuctionNozzle import SuctionNozzle
```
② Color detection
Use `apds.readRedLight()`, `apds.readGreenLight()` and `apds.readBlueLight()` functions to detect the value of RGB channel of object, and calculate.
{lineno-start=51}
```python
# Analyze the data from the color sensor
c = apds.readAmbientLight()
r = apds.readRedLight()
g = apds.resdGreenLight()
b = apds.readBlueLight()
r = int(255 * (r - r_f) / (R_F - r_f))
g = int(255 * (g - g_f) / (G_F - g_f))
b = int(255 * (b - b_f) / (B_F - b_f))
```
③ Control the LED of Ultrasonic Sensor
After calculating the value of RGB channel of object color, determine the color of the object.
{lineno-start=59}
```python
if r > 25 and r > g and r > b:
color = RED
print('color: red')
```
Then, the ultrasonic sensor will emit the corresponding light.
{lineno-start=60}
```python
color = RED
print('color: red')
hwsr06.setRGBValue(bytes([255,0,0,255,0,0]))
elif g >25 andg > r andg > b:
color = GREEN
print('color: green')
hwsr06.setRGBValue(bytes([0,255,0,0,255,0]))
elif b > 25 and b > g and b > r:
color = BLUE
print('color: blue')
hwsr06.setRGBValue(bytes([0,0,255,0,0,255]))
else:
color = 0
print('')
hwsr06.setRGBValue(bytes([255,255,255,255,255,255]))
```
Use `hwsr06.setRGBValue(bytes())` function to control the LED of the ultrasonic sensor. Take the code `hwsr06.setRGBValue(bytes([255,0,0, 255,0,0]))` as example.
The first three parameters **"255,0,0"** are the color thresholds for the LED on the right side of the senor.
The last three parameters **"255,0,0"** are the color thresholds for the left LED of the sensor.
At this time, the LED emits red light.
### 6.1.9 Color Sorting
* **Working Principle**
The color sensor is a sensor with various functions such as recognizing the color of objects, detecting the brightness of the surrounding environment, realizing object proximity detection and non-contact gesture detection, etc.
This lesson will use the color sensor for recognizing and comparing the RGB value of object. These sensors generally determine whether the detected color is consistent with the set one by using RGB (red, green, and blue) LED light sources and the ratio of R, G, and B wavelengths in the reflected light of an object.
The path of the program file: ["**6.Secondary Development--Sensor-extension Game--Arduino Development--Program Files--Color Sorting--Color_Sorting--Color_Sorting.ino**"](../_static/source_code/Secondary_Development.zip)
{lineno-start=136}
```c++
if (60 < dis & dis < 80) { //Check if distance is within 60~80mm
if (detect_color) {
setBuzzer(100); //Buzzer on 100ms
delay(1000);
pos[0] = 0; pos[1] = -160; pos[2] = 100;
set_position(pos, 1500); //Move above block
delay(1500);
pos[0] = 0; pos[1] = -160; pos[2] = 85;
set_position(pos, 800); //Suction the color block
Pump_on(); //Turn on the pump
delay(1000);
pos[0] = 0; pos[1] = -160; pos[2] = 180;
set_position(pos, 1000); //Lift the robotic arm
delay(1000);
pos[0] = x; pos[1] = y; pos[2] = 180;
set_position(pos, 1500); //Move above the placement area
delay(1500);
SetPWMServo(1, angle_pul, 800); //Set angle compensation
delay(200);
pos[0] = x; pos[1] = y; pos[2] = z;
set_position(pos, 1000); //Move to the placement area
delay(1000);
Valve_on(); //Turn off the pump and open solenoid valve
pos[0] = x; pos[1] = y; pos[2] = 200;
set_position(pos, 1000); // Lift the robotic arm
delay(1000);
```
Firstly, import the corresponding libraries and initialize ultrasonic sensor and color sensor.
Then read and calculate the RGB value of the object, and print out the color result.
Finally, the ultrasonic sensor emits corresponding light, and the functions for controlling servo and air pump are executed. MaxArm will suck and place the object to the corresponding position according to the color.
(1) Preparation
① Hardware
Please assemble the color sensor and the ultrasonic sensor to the corresponding position on MaxArm according to the tutorial in folder ["**Lesson 1 Infrared Sensor Assembly**"](https://drive.google.com/drive/folders/14M0CnRQe3gW9m5uAB3L4Z2MG7iSl2Vct?usp=sharing) under the same directory.
② Software
Please connect MaxArm to **"Arduino IDE"** according to the tutorial in folder ["**4. Underlying Program Learning--Arduino Development--Lesson 1 Set Development Environment**"](4.Underlying_Program_Learning_checked.md#anchor_4_2).
(2) Program Download
[Source Code](../_static/source_code/Secondary_Development.zip)
① Click on
icon to open **"Arduino IDE"**.
② Click **"File"--"Open"** in turn.
③ Select the program **"InfraredSensor_control.ino"** in the folder ["**6.Secondary Development--Sensor-extension Game--Arduino Development--Program Files--Infrared Detection and Control--InfraredSensor_control**"](../_static/source_code/Secondary_Development.zip)
④ Select the model of the development board. Click **"Tools"--" Board"** and select **"ESP 32 Dev Module"** (If the model of the development board has been configured when setting the development environment, you can skip this step).
⑤ Select the corresponding port of Arduino controller in **"Tools"--"Port"**. (Here take the port **"COM5"** as example. Please select the port based on your computer. If COM1 appears, please do not select because it is the system communication port but not the actual port of the development port.)
⑥ If you’re not sure about the port number, please open the **"This PC"** and click **"Properties"--"Device Manger"** in turns to check the corresponding port number (the device is with CH340). Then select the correct port on **"Arduino IDE"**.
⑦ After selecting, confirm the board **"ESP32 Dev Module"** in the lower right corner and the port number **"COM5"** (it is an example here, please refer to the actual situation).
⑧ Then click on
icon to verify the program. If no error, the status area will display **"Compiling"**--**"Compile complete"** in turn. After compiling, the information such as the current used bytes, and occupied program storage space will be displayed.
⑨ After compiling, click on
icon to upload the program to the development board. The status area will display **"Compiling"**--**"Uploading"**--**"Complete"** in turn. After uploading, the status area will stop printing the uploading information.
(3) Project Outcome
After the color sensor recognizes the color of the block and the ultrasonic sensor detects that the block is placed in the placement area, MaxArm will sort the block based on the recognized color, and suck and transport the block to the corresponding position.
(4) Program Instruction
① Import Function Library
Before executing the program, the I2C protocol, ultrasonic sensor, color sensor, buzzer, PWM servo, bus servo, infrared sensor, air pump and other ralated Python function libraries need to be imported.
{lineno-start=1}
```python
import time
from machine import Pin, I2C
from Ultrasonic import ULTRASONIC
from Color_sensor import COLOR
from Buzzer import Buzzer
from espmax import ESPMaX
from PWMServo import PwMServo
from BusServo import BusServo
from RobotControl import RobotControl
from SuctionNozzle import SuctionNozzle
```
② Color Detection
Use `apds.readRedLight()`, `apds.readGreenLight()` and `apds.readBlueLight()` functions of color sensor to detect the value of RGB channel of object, and then calculate the value.
{lineno-start=52}
```python
# Analyze the data from the color sensor
c = apds.readAmbientLight()
r = apds.readRedLight()
g = apds.resdGreenLight()
b = apds.readBlueLight()
r = int(255 * (r - r_f) / (R_F - r_f))
g = int(255 * (g - g_f) / (G_F - g_f))
b = int(255 * (b - b_f) / (B_F - b_f))
```
③ Control the LED Light of Ultrasonic Sensor
After calculating the value of RGB channel of object color, determine the color of the object.
{lineno-start=60}
```python
if r > 25 and r > g and r > b:t = RED # Output the detected results
elif g >25 and g > r and g > b:t = GREEN
elif b >25 and b > g and b > r:t = BLUE
else:t =0
```
And the block with different color is set to place in the different position.
{lineno-start=65}
```python
if t > 0:
buzzer.setBuzzer(100)
color =t
print('color:',color)
ifcolor =1:
angle =-45
(x,y,2) =·(120,-140,85)
```
Then, the ultrasonic sensor emits the corresponding color light.
{lineno-start=69}
```python
if color == 1:
angle =-45
(x,Y,z) =:(120,-140,85)
hwsr06.setRGBValue(bytes([255,0,0,255,0,0]))
elif color =2:
angle = -25
(x,Y,z) =:(120,-80,85)
hwsr06.setRGBValue(bytes([0,255,0,0,255,0]))
elif color == 3:
angle =.0
(x,Y,z) = (120,-20,82)
hwsr06.setRGBValue(bytes([0,0,255,0,0,255]))
```
Use `hwsr06.setRGBValue(bytes())` function to control the LED light of the ultrasonic sensor. Take the code `hwsr06.setRGBValue(bytes([255,0,0, 255,0,0]))` as example.
The first three parameters **"255,0,0"** are the color thresholds for the LED on the right side of the senor.
The last three parameters **"255,0,0"** are the color thresholds for the left LED of the sensor.
At this time, the LED emits red light.
④ Ultrasonic detection
If the block is detected, use `hwsr06.getDistance()` function to measure distance. Then use `print()` function to print out the measured distance.
{lineno-start=82}
```python
if color >0:
Distance = hwsr06.getDistance()
print('distance:',Distance)
```
⑤ Control Robotic Arm
Determine whether there are objects at the distance between 70 and 80, and then execute the corresponding action.
{lineno-start=85}
```python
if 70
Then execute the functions for controlling action, buzzer, air pump to pick up and place object to the corresponding position in the left side (Take robotic arm as the first person view).
:::{Note}
* If you knock on table over three times, object will be placed in the third position.
* The interval between the knocks must be within 1s. If the interval is over 1.5s, program will re-calculate and execute the following process.
* Due to the swing of the robot arm, the specific object landing point may be deviated, but the overall range will be as shown above.
:::
(1) Preparation
① Hardware
Please assemble sound sensor to the corresponding position on MaxArm according to the tutorial in folder ["**Lesson 1 Sensor Assembly**"](https://drive.google.com/drive/folders/1owKTj8ywXW7HN-xluQkIT78C2TgP4Uuz?usp=sharing) under the same directory.
② Software
Please connect MaxArm to **"Arduino IDE"** according to the tutorial in folder ["**4. Underlying Program Learning--Arduino Development--Lesson 1 Set Development Environment**"](4.Underlying_Program_Learning_checked.md#anchor_4_2).
(2) Program Download
[Source Code](../_static/source_code/Secondary_Development.zip)
① Click on
icon to open **"Arduino IDE"**.
② Click **"File"--"Open"** in turn.
③ Open the program **"SoundSensor_put.ino"** in the folder ["**6.Secondary Development--Sensor-extension Game--Arduino Development--Program Files--Sound Detection and Placement--SoundSensor_put**"](../_static/source_code/Secondary_Development.zip).
④ Select the model of development board. Click **"Tools"--" Board"** and select **"ESP 32 Dev Module"** (If the model of the development board has been configured when setting the development environment, you can skip this step).
⑤ Select the corresponding port of Arduino controller in **"Tools"--"Port"**. (Here take the port **"COM5"** as example. Please select the port based on your computer. If COM1 appears, please do not select because it is the system communication port but not the actual port of the development port.)
⑥ If you’re not sure about the port number, please open the **"This PC"** and click **"Properties"--"Device Manger"** in turns to check the corresponding port number (the device is with CH340). Then select the correct port on **"Arduino IDE"**.
⑦ After selecting, confirm the board **"ESP32 Dev Module"** in the lower right corner and the port number **"COM5"** (it is an example here, please refer to the actual situation).
⑧ Then click on
icon to verify the program. If no error, the status area will display **"Compiling"--"Compile complete"** in turn. After compiling, the information such as the current used bytes, and occupied program storage space will be displayed.
⑨ After compiling, click on
icon to upload the program to the development board. The status area will display **"Compiling"--"Uploading"--"Complete"** in turn. After uploading, the status area will stop printing the uploading information.
(3) Project Outcome
After the knock sound is detected, the blue LED light on sensor will flash corresponding to the number of knocks, then the robot arm rotates to the front and turns on the air pump to suck the block, moves and paces it to the position 1, 2, 3 of the placement area corresponding to the number of knocks. After that, turn off the air pump, reset and wait for the next command.
(4) Program Instruction
① Import function library and Initialize
The path of the program file: ["**6. Secondary Development--Sensor-extension Game--Arduino Development--Program Files--Sound Detection and Placement--SoundSensor_put\SoundSensor_put.ino**"](../_static/source_code/Secondary_Development.zip). If the program is modified, you can find a backup file in Appendix.
Before running the program, the buzzer, kinematics, kinematics encapsulation library, PWM servo, suction nozzle and other related library files need to be imported first.
{lineno-start=1}
```c++
#include "Buzzer.h"
#include "ESPMax.h"
#include "_espmax.h"
#include "ESP32PWMServo.h"
#include "SuctionNozzle.h"
#include "LobotSerialServoControl.h"
```
Then, initialize the library file and robotic arm.
{lineno-start=10}
```c++
#define sensor_pin 32 // Define sound sensor pin
void setup() {
// Initialize libraries
Buzzer_init();
ESPMax_init();
Nozzle_init();
PWMServo_init();
analogReadResolution(10);
analogSetClockDiv(ADC_11db);
Serial.begin(115200);
Serial.println("start...");
setBuzzer(100); // Turn on buzzer for 100ms
go_home(2000); // Move robotic arm to home position
SetPWMServo(1, 1500, 2000); // Set suction nozzle to initial position
}
```
② Sound Detection
Use `analogRead()` function to read the analog amount of detected knocks, and `millis()` function to read the sound interval time. if the analog amount reaches the set threshold and the knock interval is less than 1000ms, then the number of knocks plus one. If the number of detected knocks is greater than 3, then it will also be determined as only three knocks.
{lineno-start=28}
```c++
void loop() {
int num = 0;
float pos[3];
bool num_st = false;
long int time_ms = millis();
int angle_pul[3] = { 1800, 2000, 2200 };
while (true) {
float soundValue = analogRead(sensor_pin);
if (soundValue > 50) {
if (num == 0 | (millis() - time_ms) < 1000) {
time_ms = millis();
delay(80);
num += 1;
}
Serial.println(soundValue);
}
if (num > 0 & (millis() - time_ms) > 1500) {
if (num > 3) num = 3;
num_st = true;
Serial.println(num);
}
```
③ Sound Detection Feedback
When the knock sound is detected by sensor, the blue LED will flash corresponding times, and then MaxArm will execute the corresponding action.
When the sensor detects a knock, the blue LED will flash the corresponding number of times, and then MaxArm will perform the corresponding action.
{lineno-start=52}
```c++
if (num_st) {
setBuzzer(100); //Turn on buzzer for 100ms
pos[0] = 0;
pos[1] = -160;
pos[2] = 100;
set_position(pos, 1500); //Move above the color block
delay(1500);
pos[0] = 0;
pos[1] = -160;
pos[2] = 86;
set_position(pos, 800); //Suction the color block
Pump_on(); // Turn on the pump
delay(1000);
pos[0] = 0;
pos[1] = -160;
pos[2] = 180;
set_position(pos, 1000); //Lift the robotic arm
delay(1000);
pos[0] = 120;
pos[1] = (-20 - 60 * (num - 1));
pos[2] = 180;
set_position(pos, 1500); // Move above the placement area
delay(100);
```
{lineno-start=75}
```c++
SetPWMServo(1, angle_pul[(num - 1)], 1000); // Angle compensation for proper placement
delay(500);
pos[0] = 120;
pos[1] = (-20 - 60 * (num - 1));
pos[2] = (88);
set_position(pos, 1000); //Move to placement area
delay(1200);
Valve_on(); //Turn off pump and open solenoid valve
pos[0] = 120;
pos[1] = (-20 - 60 * (num - 1));
pos[2] = 200;
set_position(pos, 1000); //Lift the robotic arm
delay(1000);
Valve_off(); //Turn off solenoid valve
go_home(1500); // Return to home position
delay(100);
SetPWMServo(1, 1500, 1500); // Reset suction nozzle angle
num_st = false;
num = 0;
```
Take `setBuzze()` function, `set_position()` function, `Pump_on()` function and `go_home()` for example.
The `setBuzze()` is a function to control buzzer. Call **"Buzzer.h"** function in the same directory as **"InfraredSensor_sorting.ino"** program. Fill in the parentheses with the duration time of buzzer, and the unit is ms. The code `setBuzzer(100)` means that the buzzer will respond for 100ms after the infrared sensor detects an object, and then the next `set_potision()` function will be executed.
{lineno-start=53}
```c++
setBuzzer(100); //Turn on buzzer for 100ms
```
The `set_position()` is a function to call robotic arm. Call **"ESPMax.h"** function in the same folder as **"SoundSensor_put.ino"** program. Fill in the parentheses with the coordinate values and duration time. Take the code `set_position(pos,1500)` for example, `pos[0]`, `pos[1]`, `pos[2]` is the representative of the robot arm corresponding to the position on the XYZ axis, 1500 is the running time, the unit is milliseconds (ms). After that, the `Pump_on()` function is executed in the next step.
{lineno-start=54}
```c++
pos[0] = 0;
pos[1] = -160;
pos[2] = 100;
set_position(pos, 1500); //Move above the color block
```
The `Pump_on()` is a function to control air pump. `Pump_on()` function is to control the air pump on; `Valve_on()` function is used to turn off air pump and open solenoid valve; `Valve_off()` function to turn off the solenoid valve. Call **"SoundSensor_put.ino"** function in the same folder as the **"SuctionNozzle.h"** function, after the implementation of the next `go_home()` function.
{lineno-start=63}
```c++
Pump_on(); // Turn on the pump
```
{lineno-start=82}
```c++
Valve_on(); //Turn off pump and open solenoid valve
```
{lineno-start=88}
```c++
Valve_off(); //Turn off solenoid valve
```
The `go_home()` is a function to reset robotic arm. Cal **"ESPMax.h"** function in the same folder as **"SoundSensor_put.ino"** function.Fill in the parentheses with the action duration time, and the unit is ms. Take the code `go_home(1500)` for example. The parameter **"1500"** is the time it takes to complete the reset action. When this function is finished, the program will execute 1500ms delay function and then end this recognition and sorting actions and wait for the next recognition signal.
{lineno-start=89}
```c++
go_home(1500); // Return to home position
```
### 6.1.11 Light Detection and Placement
Please prepare a light-blocking prop for this game. You can use 3D printer to print a prop shown in the following image or use hard material to make one.
* **Project Principle**
This game uses light sensor to sense the ambient light intensity to judge if it is covered by object. Then robot arm is controlled to place object in the corresponding area.
A photosensitive sensor is a sensitive device that responds or converts to external light signals or light radiation. The sensor mainly contains a QT523C (photodiode) and an LM358 chip (voltage comparator).
When it works, sensor uses QT523C to convert light signal to an electrical signal output, which is then converted to a voltage ranging 0 to 5V and received by the data collector after A/D conversion in the range of 0-1023. The greater the external brightness intensity, the smaller the output voltage, so the brightness is inversely proportional to the output voltage.
The path of the program file: ["**6. Secondary Development--Sensor-extension Game--Arduino Development--Program Files--Light Detection and Placement--LightSensor_put--LightSensor_put.ino** "](../_static/source_code/Secondary_Development.zip)
{lineno-start=33}
```c++
while (true) {
float lightValue = analogRead(sensor_pin); // Read light sensor value, stronger light → smaller value
Serial.println(lightValue); // Print sensor value via serial
if (lightValue > 950) { // Sensor is blocked
Serial.print("num: ");
Serial.println(num + 1);
setBuzzer(100); //Turn on buzzer for 100ms
pos[0] = 0;
pos[1] = -160;
pos[2] = 100;
set_position(pos, 1500); //Move above the color block
delay(1500);
pos[0] = 0;
pos[1] = -160;
pos[2] = 86;
set_position(pos, 800); //Suction the color block
Pump_on(); //Turn on the pump
delay(1000);
pos[0] = 0;
pos[1] = -160;
pos[2] = 180;
set_position(pos, 1000); //Lift the robotic arm
delay(1000);
pos[0] = 120;
pos[1] = (-20 - 60 * num);
pos[2] = 180;
set_position(pos, 1500); //Move above the placement area
Serial.println(angle_pul[num]);
delay(100);
SetPWMServo(1, angle_pul[num], 1000); // Angle compensation for proper placement
```
Use light sensor to detect the light intensity, and then send the signal to microcontroller for processing. When the light intensity is lower than the set threshold in program, buzzer will sound for responding, and MaxArm will perform the corresponding action.
The first detected object will be placed at position 1. The second detected object will be placed at position 2. The third detected object will be place at position 3. As the figure shown below:
Then, execute the functions for controlling action, buzzer and air pump to control robot arm to move object and place it to the corresponding position on the left side. (Take robotic arm as the first person view)
:::{Note}
* Since light sensor is susceptible to the ambient light, you may need to adjust the potentiometer of sensor based on the actual situation.
* Due to the swing of the robot arm, the specific object landing point may be deviated, but the overall range will be as shown above.
* When strong light is detected, the blue LED light on sensor will keep on. As the light becomes weak, the blue LED light will be off. Please note that this has nothing to do with the brightness of the sensor being covered by the object.
:::
(1) Preparation
① Hardware
Please assemble light sensor to the corresponding position on MaxArm according to the tutorial in folder ["**Lesson 1 Sensor Assembly**"](https://drive.google.com/drive/folders/1zjZOX2x2zZoGA6B9lB50lg2Ov3_vLaIm?usp=sharing) in the same directory.
② Software
Please connect MaxArm to **"Arduino IDE"** according to the tutorial in folder ["**4. Underlying Program Learning--Arduino Development--Lesson 1 Set Development Environment**"](4.Underlying_Program_Learning_checked.md#anchor_4_2).
(2) Program Download
[Source Code](../_static/source_code/Secondary_Development.zip)
① Click on
icon to open **"Arduino IDE"**.
② Click **"File"**--**"Open"** in turn.
③ Open the program **"LightSensor_put.ino"** in the folder ["**6.Secondary Development--Sensor-extension Game--Arduino Development--Program Files--Light Detection and Placement--LightSensor_put**"](../_static/source_code/Secondary_Development.zip).
④ Select the model of development board. Click **"Tools"**--**" Board"** and select **"ESP 32 Dev Module"** (If the model of the development board has been configured when setting the development environment, you can skip this step).
⑤ Select the corresponding port of Arduino controller in **"Tools"**--**"Port"**. (Here take the port **"COM5"** as example. Please select the port based on your computer. If COM1 appears, please do not select because it is the system communication port but not the actual port of the development port.)
⑥ If you’re not sure about the port number, please open the **"This PC"** and click **"Properties"--"Device Manger"** in turns to check the corresponding port number (the device is with CH340). Then select the correct port on **"Arduino IDE"**.
⑦ After selecting, confirm the board **"ESP32 Dev Module"** in the lower right corner and the port number **"COM5"** (it is an example here, please refer to the actual situation).
⑧ Then click on
icon to verify the program. If no error, the status area will display **"Compiling"--"Compile complete"** in turn. After compiling, the information such as the current used bytes, and occupied program storage space will be displayed.
⑨ After compiling, click on
icon to upload the program to the development board. The status area will display **"Compiling"--"Uploading"--"Complete"** in turn. After uploading, the status area will stop printing the uploading information.
(3) Project Outcome
When light sensor starts to detecting light, it covered by object resulting in the light intensity is lower than the threshold set in program. At this time, microcontroller will receive a command, and then robot arm will turn on air pump and suck the object and place it to corresponding position. After that, turn off the air pump, reset and wait for the next command.
(4) Program Instruction
① Import function library and Initialize
The path of the program file: ["**6. Secondary Development--Sensor-extension Game--Arduino Development--Program Files--light Detection and Placement--LightSensor_put--LightSensor_put.ino**"](../_static/source_code/Secondary_Development.zip). If the program is modified, you can find the backup file in Appendix.
Before running the program, the buzzer, kinematics, kinematics encapsulation library, PWM servo, suction nozzle and other related library files need to be imported first.
{lineno-start=1}
```c++
#include "Buzzer.h"
#include "ESPMax.h"
#include "_espmax.h"
#include "ESP32PWMServo.h"
#include "SuctionNozzle.h"
#include "LobotSerialServoControl.h"
```
Then, initialize the library files and robotic arm.
{lineno-start=10}
```c++
#define sensor_pin 32 // Define light sensor pin
void setup() {
// Initialize libraries
Buzzer_init();
ESPMax_init();
Nozzle_init();
PWMServo_init();
analogReadResolution(10);
analogSetClockDiv(ADC_11db);
Serial.begin(115200);
Serial.println("start...");
setBuzzer(100); // Turn on buzzer for 100ms
go_home(2000); // Move robotic arm to initial position
SetPWMServo(1, 1500, 2000); // Set suction nozzle to initial position
}
```
② Light Detection
Use `analogRead()` function to read the analog amount of detected light intensity. When the analog amount reaches the set threshold, the program will place object at position 1. When the next object is detected, it will be placed at position 2. After recognizing and placing three time, game will enter the next round.
{lineno-start=28}
```c++
void loop() {
int num = 0;
float pos[3];
int angle_pul[3] = { 1600, 1800, 2000 };
while (true) {
float lightValue = analogRead(sensor_pin); // Read light sensor value, stronger light → smaller value
Serial.println(lightValue); // Print sensor value via serial
if (lightValue > 950) { // Sensor is blocked
Serial.print("num: ");
Serial.println(num + 1);
```
{lineno-start=81}
```c++
if (num >= 3) {
num = 0;
setBuzzer(100); //Turn on buzzer for 100ms
delay(100);
setBuzzer(100); //Turn on buzzer for 100ms
}
```
③ Light Detection Feedback
When cover is detected by sensor, MaxArm will execute the corresponding action.
{lineno-start=37}
```c++
if (lightValue > 950) { // Sensor is blocked
Serial.print("num: ");
Serial.println(num + 1);
setBuzzer(100); //Turn on buzzer for 100ms
pos[0] = 0;
pos[1] = -160;
pos[2] = 100;
set_position(pos, 1500); //Move above the color block
delay(1500);
pos[0] = 0;
pos[1] = -160;
pos[2] = 86;
set_position(pos, 800); //Suction the color block
Pump_on(); //Turn on the pump
delay(1000);
pos[0] = 0;
pos[1] = -160;
pos[2] = 180;
set_position(pos, 1000); //Lift the robotic arm
delay(1000);
pos[0] = 120;
pos[1] = (-20 - 60 * num);
pos[2] = 180;
set_position(pos, 1500); //Move above the placement area
Serial.println(angle_pul[num]);
delay(100);
SetPWMServo(1, angle_pul[num], 1000); // Angle compensation for proper placement
delay(500);
pos[0] = 120;
pos[1] = (-20 - 60 * num);
pos[2] = 88;
set_position(pos, 1000); //Move to placement area
delay(1200);
Valve_on(); //Turn off pump and open solenoid valve
pos[0] = 120;
pos[1] = (-20 - 60 * num);
pos[2] = 200;
set_position(pos, 1000); //Lift the robotic arm
delay(1000);
Valve_off(); //Turn off solenoid valve
go_home(1500); //Return to home position
delay(100);
SetPWMServo(1, 1500, 1500); // Reset suction nozzle angle
```
Take `setBuzze()` function, `set_position()` function, `Pump_on()` function and `go_home()` for example.
The `setBuzze()` is a function to control buzzer. Call **"Buzzer.h"** function in the same directory as **"InfraredSensor_sorting.ino"** program. Fill in the parentheses with the duration time of buzzer, and the unit is ms. The code `setBuzzer(100)` means that the buzzer will respond for 100ms after the infrared sensor detects an object, and then the next `set_potision()` function will be executed.
{lineno-start=40}
```c++
setBuzzer(100); //Turn on buzzer for 100ms
```
The `set_position()` is a function to call robotic arm. Call **"ESPMax.h"** function in the same folder as **"LightSensor_put.ino"** program. Fill in the parentheses with the coordinate values and duration time. Take the code `set_position(pos,1500)` for example, `pos[0]`, `pos[1]`, `pos[2]` is the representative of the robot arm corresponding to the position on the XYZ axis, 1500 is the running time, the unit is milliseconds (ms). After that, the `Pump_on()` function is executed in the next step.
{lineno-start=41}
```c++
pos[0] = 0;
pos[1] = -160;
pos[2] = 100;
set_position(pos, 1500); //Move above the color block
```
The `Pump_on()` is a function to control air pump. `Pump_on()` function is to control the air pump on; `Valve_on()` function is used to turn off air pump and open solenoid valve; `Valve_off()` function to turn off the solenoid valve. Call **"LightSensor_put.ino"** function in the same folder as the **"SuctionNozzle.h"** function, after the implementation of the next `go_home()` function.
{lineno-start=50}
```c++
Pump_on(); //Turn on the pump
```
{lineno-start=70}
```c++
Valve_on(); //Turn off pump and open solenoid valve
```
{lineno-start=76}
```c++
Valve_off(); //Turn off solenoid valve
```
The `go_home()` is a function to reset robotic arm. Call **"ESPMax.h"** function in the same folder as **"LightSensor_put.ino"** function.Fill in the parentheses with the action duration time, and the unit is ms. Take the code `go_home(1500)` for example. The parameter **"1500"** is the time it takes to complete the reset action. When this function is finished, the program will execute 1500ms delay function and then end the game and wait for the next recognition signal.
{lineno-start=77}
```c++
go_home(1500); //Return to home position
```
(5) Adjust Sensitivity
There is an adjustable potentiometer knob on light sensor for adjusting the measuring distance. When performing the related games, if the measurement effect it not good enough, the measurement sensitivity of sensor can be adjusted by adjusting the knob.
It is recommended to use phillips screwdriver. Rotate the knob clockwise, as the figure shown below, to increase the measurement distance; rotate it counterclockwise to decrease the measurement distance.
Please take notice of the following two tips:
① Since the warm light (incandescent light, sunlight, etc) contains more infrared component, there will be a certain interference the detection result. When using it, special attention should be paid to the surrounding environment. Therefore, you can not adjust the sensitivity alone.
② The sensitivity adjustment has is set a threshold, which you can regard it as a critical point. If the sensitivity exceeds the critical point, its value will return to the initial state.
③ Sensitivity adjustment needs to be based on the actual needs of the project. It is better to be adjusted to the most suitable conditions.
## 6.2 Python Development
### 6.2.1 What is the Inverse Kinematics
This lesson aims at helping users basically learning about the principle of inverse kinematics. The further learning and practical application of the inverse kinematics of robotic arm is available in the folder **"7. Inverse Kinematics Lesson"**
* **What is it?**
Forward kinematics refers to process of obtaining position and velocity of end effector, given the known joint angles and angular velocities. In other word, the position information of end effector can be obtained when then joint angle and linkages parameters are known.
Inverse Kinematics is the inverse function or algorithm of Forward Kinematics. According to the position and post of the end effector along with linkages parameters, the joint position can be calculated, i.e., Given the robot’s end-effector positions, inverse kinematics can determine an appropriate joint configuration.
(1) Establish Coordinate System
A coordinate system must be established to describe the motion of an object. MaxArm uses x-y-z axes coordinate system (unit:mm) and takes the the base centre of robotic arm as original point (0,0,0), as the figure shown below.
The correspondence relationship between the movement orientation of end effector and the values of x-y-z axes is shown below (user per se as reference):
| **Coordinate axis** | **control orientation** |
| :---: | :---: |
| x | Control the end effector of robotic arm to move left or right (As the x value is positive, it moves to the right. As the x value is negative, it moves to the left. ) |
| y | Control the end effector of robotic arm to move forward and backward. (As the y value is negative,it moves backward. As the y value is positive, it moves forward.) |
| z | Control the end effector of robotic arm to move up and down (As the z value is negative, it moves up. As the z value is positive, it moves down.) |
(2) Project Operation
After learning about the principle and spatial concept of inverse kinematics, the control method of inverse kinematics can be mastered by a simple routine. You can follow the steps below to run the game.
① Install and connect Arduino. (Please refer to the tutorial in folder ["**4. Underlying Files Learning--Arduino Development--Lesson 1 Set Development Environment**"](4.Underlying_Program_Learning_checked.md#anchor_4_2))
② Double click to open **"Arduino IDE"**
.
③ Click **"File"--"Open"**.
④ Select the program **"kinematics_demo.ino"** in the folder ["5.MaxArm Hardware Basics Learning--Arduino Development--Game Programs--Program Files--kinematics_demo"](Appendix.md), and click "**Open**".
⑤ Check the board model. Click **"Tools"--"Board"** and select **"ESP 32 Dev Module"**. (If the model of development board has been configured when setting the development environment, you can skip this step.)
⑥ Select the corresponding port of ESP32 controller in **"Tools"--"Port"**. (Here take the port **"COM5"** as example. Please select the port based on your computer. If COM1 appears, please do not select because it is the system communication port but not the actual port of the development port.)
⑦ If you are not sure the port number, please open the **"This PC"** and click **"Properties"--"Device Manger"** in turns to check the corresponding port number (the device is with CH340).
⑧ After selecting, confirm the board **"ESP32 Dev Module"** in the lower right corner and the port number **"COM5"** (it is an example here, please refer to the actual situation).
⑨ Then click on
icon to verify the program. If no error, the status area will display **"Compiling"--"Compile complete"** in turn. After compiling, the information such as the current used bytes, and occupied program storage space will be displayed.
⑩ After compiling, click on
icon to upload the program to the development board. The status area will display **"Compiling"-"Uploading"-"Complete"** in turn. After uploading, the status area will stop printing the uploading information.
(3) Project Analysis
[Source Code](../_static/source_code/Secondary_Development.zip)
The complete program is as follow:
{lineno-start=1}
```c++
#include "ESPMax.h"
#include "_espmax.h"
// Inverse kinematics basic example
void setup(){
ESPMax_init();
go_home(2000); // Move the robotic arm back to the initial position
Serial.begin(9600);
Serial.println("start...");
}
bool start_en = true;
void loop(){
if(start_en){
float x,y,z;
float pos[3];
// XYZ position of the robotic arm’s initial pose
x = 0;
y = -(L1 + L3 + L4);
z = (L0 + L2);
// Print XYZ position via serial, unit: millimeter
Serial.print(x);
Serial.print("; ");
Serial.print(y);
Serial.print("; ");
Serial.println(z);
// Since the initial position of the robotic arm is already at the edge of its reachable workspace, it must first move downward along the Z-axis. Otherwise, the arm will not be able to
// move along the X or Y axes.
// set_position(pos,t), pos={x,y,z}; x: X-axis coordinate, y: Y-axis coordinate, z: Z-axis coordinate, t: total movement time (the longer the time, the slower the speed)
pos[0] = x; pos[1] = y; pos[2] = z-100;
set_position(pos,2000); // Move Z-axis 100mm down relative to the initial position
delay(2000);
pos[0] = x; pos[1] = y; pos[2] = z;
set_position(pos,2000); // Reset robotic arm to initial pose
delay(1000);
start_en = false;
}
else{
delay(500); // Delay 500 ms
}
```
① Import function library
Before the robotic arm starts to move, the encapsulation library and underlying library of inverse kinematics need to be imported.
{lineno-start=1}
```c++
#include "ESPMax.h"
#include "_espmax.h"
```
② Calculate the initial position of robotic arm
According to the linkage parameters of L0-L4 defined in kinematics underlying library.
{lineno-start=1}
```c++
#ifndef _ESPMAX_H
#define _ESPMAX_H
#define L0 84.4
#define L1 8.14
#define L2 128.4
#define L3 138.0
#define L4 16.8
```
Calculate the initial position of the end effector. (Use the L0-L4 values to get x=0, y=162.94, z=212.8)
{lineno-start=18}
```c++
// XYZ position of the robotic arm’s initial pose
x = 0;
y = -(L1 + L3 + L4);
z = (L0 + L2);
```
③ Control robotic arm
Use the function `set_position()` to control the end effector to move.
Take the code `set_position(pos,2000)` as example.
{lineno-start=34}
```c++
pos[0] = x; pos[1] = y; pos[2] = z-100;
set_position(pos,2000); // Move Z-axis 100mm down relative to the initial position
delay(2000);
pos[0] = x; pos[1] = y; pos[2] = z;
set_position(pos,2000); // Reset robotic arm to initial pose
delay(1000);
```
The first parameter **"pos"** is a set of valuea representing the position values of the end effector on x-y-z axis.
Among them, `pos[0]` represents the x-axis value of the initial position of the end-effector.
`pos[1]` represents the the y-axis value of the initial position of the end-effector.
**"pos[2]"** represents the end-effector moves down to 100mm. And the position of the end effector can be set by modifying the x,y and z values.
For example, if want to control the end-effector to move 200mm to the left. (its position relative to the original moves to 200mm to the left), set x value plus 200. If want to move to 200 to the right, set x-200.
If want to directly move to the set position, for example, move to 200mm on x axis, you just need to set x=200.
The second parameter **"2000"** is the running time and the unit is ms.
(4) Inverse kinematics library analysis
The path to the inverse kinematics library: [Appendix--8. Controller Underlying Files--Arduino Development--espmax.py](Appendix.md)
① Import head file and define pin
{lineno-start=1}
```c++
#include "ESPMax.h"
#include "_espmax.h"
#include "LobotSerialServoControl.h"
```
Import the inverse kinematics and servo head files.
{lineno-start=5}
```c++
#define SERVO_SERIAL_RX 35
#define SERVO_SERIAL_TX 12
#define receiveEnablePin 13
#define transmitEnablePin 14
HardwareSerial HardwareSerial(2);
LobotSerialServoControl BusServo(HardwareSerial,receiveEnablePin,transmitEnablePin);
```
Define the serial communication pin.
② Initialization
{lineno-start=12}
```c++
float ORIGIN[3] ={ 0, -(L1 + L3 + L4), (L0 + L2)};
float positions[3];
void ESPMax_init(){
BusServo.OnInit();
HardwareSerial.begin(115200,SERIAL_8N1,SERVO_SERIAL_RX,SERVO_SERIAL_TX);
}
```
`ORIGIN[3]` is the initial position of the end effector calculating from the linkage length.
The function `ESPMax_init()` is used for initialization
The function `BusServo.OnInit()` is the servo configuration initialization. `HardwareSerial.begin()` is serial communication configuration. **"115200"** is the baud rate. **"SERIAL_8N1"** refers to the working mode. `SERVO_SERIAL_RX` is the pin number of RX port. `SERVO_SERIAL_TX` is the pin number of TX port.
③ Control a single servo
{lineno-start=20}
```c++
int set_servo_in_range(int servo_id, int p, int duration){
if(servo_id == 3 & p < 470) p = 470;
if(servo_id == 2 & p > 700) p = 700;
BusServo.LobotSerialServoMove(servo_id, p, duration);
return int(1);
}
```
The function `set_servo_in_range()` is used to control the movement of a single servo, and limit the position of servo ID2 and ID3. The ID3 Servo can not be less than 470 impulse and the No.4 can not be less than 700. The parameter `servo_id` is servo ID number and the parameter **"p"** is servo impulse. The parameter **"duration"** is the running time.
The function `BusServo.LobotSerialServoMove()` in BusServo library controls a single servo to move.
④ Calculate servo pulse
{lineno-start=27}
```c++
float* position_to_pulses(float pos[3], float* pul){
float angles[3];
inverse(pos,angles);
deg_to_pulse(angles,pul);
return pul;
}
```
The function `position_to_pulses()` is used to calculate the servo pulse. The parameter **"position"** is position coordinate. **"angles"** is servo angle. **"pulse"** is servo pulse. Then the value of servo pulse will be returned.
The function `inverse()` is used to calculate the servo angle according to the coordinates.
The function `deg_to_pulse()` is used to calculate the servo pulse according to the servo angle.
⑤ Calculate robotic arm position
{lineno-start=34}
```c++
float* pulses_to_position(float pul[3], float* pos){
float joints[3];
pulse_to_deg(pul,joints);
forward(joints,pos);
return pos;
}
```
The function `pulses_to_position()` is used to calculate the coordinate of robotic arm position. The parameter `pul[3]` is servo pulse. The coordinate of robotic arm is calculated according to the servo pulses, and then the coordinate value is returned.
⑥ The movement of robotic arm
{lineno-start=41}
```c++
int set_position(float pos[3], int duration){
float x = pos[0];
float y = pos[1];
float z = pos[2];
if(z > 255) z = 255;
if(sqrt(x*x + y*y) < 50) return int(0);
float angles[3];
inverse(pos,angles);
float pul[3];
deg_to_pulse(angles,pul);
for(int i=0; i<3; i++){
positions[i] = pul[i];
BusServo.LobotSerialServoMove(i+1,pul[i],duration);
delay(2);
}
return int(1);
}
```
The function `set_position()` is used to control the robotic arm to move, and add the position limit. The parameter **"position"** is the position coordinate and the **"duration"** is the running time.
Use judgement statement to limit the robotic arm position. The coordinate of z-axis can not be greater than 225. The root of the sum of the squares of the x and y axes coordinates should be greater than 50, which means the end effector should be outside the circle with the coordinate origin as the center and the radius of 50. The unit is millimeter.
Then use **"for"** to control the ID1, ID2 and ID3 servos to rotate.
⑦ Back to the initial position
{lineno-start=83}
```c++
void go_home(int duration){
set_position(ORIGIN, duration);
}
```
The function `go_home()` is used to get robotic arm back to the initial position. The parameter "duration" is the running time and the parameter `self.set_position()` is to control robotic arm to move. The parameter `ORIGIN` is the coordinate of the initial position set in program.
⑧ Read position coordinate
{lineno-start=93}
```c++
float* read_position(float* pos){
float pul[3];
for(int i=0; i<3; i++){
pul[i] = BusServo.LobotSerialServoReadPosition(i+1);
}
pulses_to_position(pul,pos);
}
```
Use the function `self.bus_servo.get_position()` to get the pulse value of servo ID1, ID2, and ID3.
Get the x,y,z position coordinate by calculating the robotic arm position function `pulses_to_position()`. Then the x, y and z values are obtained.
### 6.2.2 Ultrasonic Detection and Digital Tube Display
* **Project Principle**
In this lesson, ultrasonic sensor will be used to detect object and the detection result will be displayed on digital tube.
The used glowing ultrasonic ranging module integrates ultrasonic transmitting circuits, ultrasonic receiving circuits, digital processing circuits, etc. inside the ranging chip. The module adopts IIC communication interface, and can read the measured distance through IIC communication.
Ultrasonic sensors have two main components: the transmitter and the receiver.
The module will automatically send eight 40khz square waves and detect if there are signals are sent back. If there are signals back, output a high level. Then the duration time is time when the ultrasonic waves are sent and returns.
Measured distance(L) =(high level time* the speed of time(340M/S))/2.
The ultrasonic probes integrates two RGB lights, not only can adjust the light brightness, but also through the red (R), green (G), blue (B) three color channel changes and their superposition on each other to achieve colorful color changes.
The digital tube has a 4-digit red LED for displaying numbers, decimal points and some special characters. This module is compact and easy to use, you can apply this module in robotics projects for displaying sensor values such as speed, time, fraction, temperature, distance, etc.
Firstly, import corresponding libraries and initialize ultrasonic sensor, buzzer, servo and digital tube module.
Then set the distance measurement conditions,three threshold intervals are set in program. Different intervals is distinguished with different colors.
(1) Preparation
① Hardware
Please assemble the ultrasonic sensor to the corresponding position on MaxArm according to the tutorial in folder ["**Lesson 1 Sensor Assembly**"](https://drive.google.com/drive/folders/1wZ3ZBwYMszj6OsFdBazLZQ3ZO0WjgfBG?usp=sharing) under the same directory.
② Software
Please connect MaxArm to Python editor according to the tutorial in folder ["**4. Underlying Program Learning--Python Development--Lesson 1 Set Development Environment**"](4.Underlying_Program_Learning_checked.md#anchor_4_3).
(2) Program Download
[Source Code](../_static/source_code/Secondary_Development.zip)
① After connecting, change the path of Workspace to ["**6. Secondary Development--Python Development--Sensor-extension Game**"](Appendix.md), and select **"Program Files"**.
② Click the folder **"Ultrasonic Detection and Digital Tube Display"**, and then select all the program files in the folder.
③ Then right click to download all the program files to the controller.
④ When the terminal prints the prompt as shown in the image below, it means download completed.
⑤ After downloading, click on the reset icon or press the reset button on ESP32 controller to run program.
(3) Project Outcome
Place a block or other objects in front of ultrasonic sensor, and then the corresponding distance will be displayed on digital tube. If the distance between sensor and object is less than 50cm, red light is on. If the distant is between 50cm and 100cm, green light is on. When the distance is farther than 100cm, blue light is on.
(4) Program Instruction
① Import library file
The path of program file: ["../_static/source_code/Secondary_Development.zip"](../_static/source_code/Secondary_Development.zip)
Before the program is executed, I2C protocol, ultrasonic sensor, buzzer, PWM servo, bus servo, air pump and other related Python function libraries are imported.
{lineno-start=1}
```python
import time
import TM1640
from machine import Pin, I2C
from Buzzer import Buzzer
from espmax import ESPMax
from PWMServo import PWMServo
from BusServo import BusServo
from Ultrasonic import ULTRASONIC
from RobotControl import RobotControl
from SuctionNozzle import SuctionNozzle
```
② Ultrasonic detection
The variables is set to read the distance measured by ultrasonic sensor.
{lineno-start=36}
```python
while True:
Distance = hwsr06.getDistance() # Get the ultrasonic detection distance
print("Distance =", Distance, "mm") # Print distance to the serial monitor
```
③ LED Display
Display the distance value on digital tube.
{lineno-start=39}
```python
tm.tube_display_int(Distance) # Display distance on the digital tube
```
④ Light Color Setting
If the distance between sensor and object is less than 50cm, green light is on.
If the distant is between 50cm and 100cm, red light is on.
When the distance is farther than 100cm, blue light is on.
{lineno-start=40}
```python
if Distance <= 50: # Distance ≤ 50mm
hwsr06.setRGBValue(bytes([0,255,0, 0,255,0])) # Ultrasonic lights green
elif 50 < Distance and Distance <= 100: # Distance > 50mm and ≤ 100mm
hwsr06.setRGBValue(bytes([255,0,0, 255,0,0])) # Ultrasonic lights red
elif 100 < Distance: # Distance > 100mm
hwsr06.setRGBValue(bytes([0,0,255, 0,0,255])) # Ultrasonic lights blue
time.sleep(0.2) # Delay 200ms
```
### 6.2.3 Ultrasonic Detection and Suction
* **Working Principle**
Ultrasonic sensors is a sensor that converts ultrasonic signals into other energy signals (usually electrical signals). There are two probes on ultrasonic sensor for receiving and transmitting ultrasound.
Firstly, import the corresponding library and initialize ultrasonic sensor, buzzer, servo and action groups.
Next, the object is detected by ultrasonic sensor and the measured distance is read by I2C protocol. After determining the distance, MaxArm will perform the corresponding action based on the determined result.
Then, execute the functions for controlling action group, starting buzzer and air pump to suck the object to the side.
The path to the program of the source code is ["**6. Secondary Development--Sensor-extension Game--Python Development--Program Files--Ultrasonic Detection and Suction--main.py**"](../_static/source_code/Secondary_Development.zip).
(1) Preparation
① Hardware
Please assemble the ultrasonic sensor to the corresponding position on MaxArm according to the tutorial in folder ["**Lesson 1 Sensor Assembly**"](https://drive.google.com/drive/folders/1l1luC9smegiyJS5e2p_QFHBP_IxJ9mu8?usp=sharing) under the same directory.
② Software
Please connect MaxArm to Python editor according to the tutorial in folder ["**4. Underlying Program Learning--Python Development--Lesson 1 Set Development Environment**"](4.Underlying_Program_Learning_checked.md#anchor_4_3).
(2) Program Download
[Source Code](../_static/source_code/Secondary_Development.zip)
After connecting, change the path of Workspace to ["**6. Secondary Development--Sensor-extension Game--Python Development--**"](../_static/source_code/Secondary_Development.zip), and select **"Program Files"**.
① Click the folder **"Ultrasonic Detection and Suction"**, and then select all the program files in the folder.
② Then right click to download all the program files to the controller.
When the terminal prints the prompt as shown in the image below, it means download completed.
③ After downloading, click on the reset icon or press the reset button on ESP32 controller to run program.
(3) Project Outcome
After the object is detected by ultrasonic sensor, the buzzer will make **"Di"** sound, and the robotic arm will move to the object. Then suck and place the object to the right. After the air pump stops, MaxArm will return to the initial posture.
(4) Program Instruction
① Import library file
Before carrying out detection and suction, the I2C protocol, ultrasonic sensor, buzzer, PWM servo, bus servo, air pump and other related Python function libraries are imported.
The path to the program of the source code is ["**6. Secondary Development--Python Development--Sensor-extension Game--Sensor Programs--Ultrasonic Detection and Suction--mian.py**"](../_static/source_code/Secondary_Development.zip)
{lineno-start=1}
```python
import time
import TM1640
from machine import Pin, I2C
from Buzzer import Buzzer
from espmax import ESPMax
from PWMServo import PWMServo
from BusServo import BusServo
from Ultrasonic import ULTRASONIC
from RobotControl import RobotControl
```
② Ultrasonic detection
The distance is measured by suing `hwsr06.getDistance()` function, and then use `print()` function to print out the measured distance.
{lineno-start=38}
```python
Distance = hwsr06.getDistance() # Get the ultrasonic detection distance
```
③ Control robotic arm
Determine the distance of the front object first. If the object is between 60 and 80mm, MaxArm will perform the corresponding action.
{lineno-start=40}
```python
if 70 < Distance < 80:
buzzer.setBuzzer(100) #Set buzzer on for 100ms
arm.set_position((0,-160,100),1500)
time.sleep_ms(1000) #Wait for 1000ms
arm.set_position((0,-160,85),800) #Suction the color block
nozzle.on() #Turn on the pump
time.sleep_ms(1000)
arm.set_position((0,-160,200),1000) #Lift up
time.sleep_ms(1000)
arm.set_position((70,-150,200),800) #Move above placement area
nozzle.set_angle(30,600)
time.sleep_ms(1000)
nozzle.set_angle(35,300)
arm.set_position((70,-150,90),800) #Move to placement area
time.sleep_ms(800)
arm.set_position((130,-150,88),500) #Move left slightly to place
time.sleep_ms(500)
nozzle.off() #Turn off suction pump
arm.set_position((130,-150,200),1000) #Lift up
time.sleep_ms(1000)
arm.go_home() #Reset arm to initial position
nozzle.set_angle(0,2000)
time.sleep_ms(2000)
```
Use the `buzzer.setBuzze()` function to control buzzer. Take the code `buzzer.setBuzzer(100)` as example:
The first parameter **"(0,-160,100)"** is the position of the suction nozzle on x, y and z axes.
The second parameter **"1500"** is the running time and the unit is ms.
Use the `nozzle.set_angle()` function to control the rotation of the suction nozzle. Take the code `nozzle.set_angle(30,600)` as example:
The first parameter **"30"** is the angle of PWM servo.
The second parameter **"600"** is the running time and the unit is ms.
### 6.2.4 Ultrasonic Detecting and Stacking
* **Working Principle**
Ultrasonic sensor can convert ultrasonic signals into other energy signals (usually electrical signals). There are two probes on ultrasonic sensor for receiving and transmitting ultrasound.
Firstly, import the corresponding library and initialize ultrasonic sensor, buzzer, servo and action groups.
Next, the object is detected by ultrasonic sensor and the measured distance is read by I2C protocol. After determining the distance, MaxArm will perform the corresponding action based on the determined result.
Then, execute the functions for controlling action group, buzzer and air pump to suck the detected object to the side and stack it.
The path of the program file: ["6. Secondary Development--Python Development--Sensor-extension Game--Program Files--Ultrasonic Detecting and stacking--main.py"](../_static/source_code/Secondary_Development.zip).
{lineno-start=1}
```python
import time
from machine import Pin, I2C
from Ultrasonic import ULTRASONIC
from Buzzer import Buzzer
from espmax import ESPMax
from PWMServo import PWMServo
from BusServo import BusServo
from RobotControl import RobotControl
from SuctionNozzle import SuctionNozzle
```
(1) Preparation
① Hardware
Please assemble the ultrasonic sensor to the corresponding position on MaxArm according to the tutorial in folder ["**Lesson 1 Sensor Assembly**"](https://drive.google.com/drive/folders/1Wy5PkdK3uG1AthsK0rR3UPCdKTBZsaq0?usp=sharing) under the same directory.
② Software
Please connect MaxArm to Python editor according to the tutorial in folder ["**4. Underlying Program Learning--Python Development--Lesson 1 Set Development Environment**"](4.Underlying_Program_Learning_checked.md#anchor_4_3).
(2) Program Download
[Source Code](../_static/source_code/Secondary_Development.zip)
① After connecting, change the path of Workspace to ["**6. Secondary Development--Python Development--Sensor-extension Game**"](Appendix.md), and select **"Program Files"**.
② Click the folder **"Ultrasonic Detecting and Stacking"**, and then select all the program files in the folder.
③ Then right click and select **"Download"** to download all the program files to the controller.
④ When the terminal prints the prompt as shown in the image below, it means download completed.
⑤ After downloading, click on the reset icon or press the reset button on ESP32 controller to run program.
(3) Project Outcome
After putting the block on the fixed detection position, the buzzer will beep. Then MaxArm will suck the block to the left and stack it. The program will be repeated after stacking the three blocks.
(4) Program Instruction
① Import library file
The path of the program file: ["**6. Secondary Development--Python Development--Sensor-extension Game--Program Files--Ultrasonic Detecting and stacking--main.py**"](../_static/source_code/Secondary_Development.zip).
Before carrying out detection and suction, the Python function libraries related to I2C protocol, ultrasonic sensor, buzzer, PWM servo, bus servo, air pump and other related Python function libraries are imported.
{lineno-start=1}
```python
import time
from machine import Pin, I2C
from Ultrasonic import ULTRASONIC
from Buzzer import Buzzer
from espmax import ESPMax
from PWMServo import PWMServo
from BusServo import BusServo
from RobotControl import RobotControl
from SuctionNozzle import SuctionNozzle
```
② Ultrasonic detection
Use the `hwsr06.getDistance()` function to measure distance. Then use `print()` function to print out the measured distance.
{lineno-start=40}
```python
Distance = hwsr06.getDistance() # Get ultrasonic detection distance
print("distance = ", Distance)
```
③ Control robotic arm
Determine whether there are objects at the distance between 70 and 80, and then perform the corresponding action.
{lineno-start=42}
```python
if 70 < Distance < 80:
buzzer.setBuzzer(100) #Set buzzer to sound for 100ms
time.sleep_ms(1000) #Wait 1000ms
arm.set_position((0,-160,85),1500) #Suction the color block
nozzle.on() #Turn on the pump
time.sleep_ms(1600)
arm.set_position((0,-160,200),1000) #Lift up
time.sleep_ms(1000)
arm.set_position((160,0,200),1500) #Move above placement area
time.sleep_ms(1500)
arm.set_position((160,0,(88+overlay*40)),1000) #Adjust placement height based on stacked count
time.sleep_ms(1200)
nozzle.off() #Turn off the pump
arm.set_position((160,0,200),1000) #Lift up
time.sleep_ms(1000)
arm.go_home() #Reset arm to initial position
time.sleep_ms(2000)
overlay += 1 # Increase stacked count by 1
if overlay >= 3: overlay = 0
```
Use the `buzzer.setBuzze()` function to control the buzzer. Take the code `buzzer.setBuzze()` as example.
The first parameter **"100"** represents the sounding time of the buzzer and the unit is ms.
Use the `arm.set_position()` function to control robotic arm. Take the code `arm.set_position((0,-160,85),1500)` as example.
The first parameter **"(0,-160,85)"** is the position of the suction nozzle on x, y and z axes.
The second parameter **"1500"** represents the running time and the unit is ms.
### 6.2.5 Touch Detection and Placement
* **Working Principle**
This lesson uses touch sensor based on the principle of capacitive sensing. After supplying the touch sensor power, the touching will be sensed when our fingers or metal touch the metal sensing plate. In the meantime, the signal terminal OUT will output low level signal, vice verse. According to this characteristics, the robotic arm can be controlled to perform the corresponding action.
The path of the program file is ["**6. Secondary Development--Python Development--Sensor-extension Game--Program Files--Touch Detection and Placement--main.py**"](../_static/source_code/Secondary_Development.zip).
{lineno-start=1}
```python
import time
from Buzzer import Buzzer
from espmax import ESPMax
from PWMServo import PWMServo
from BusServo import BusServo
from Touch_sensor import TOUCH
from RobotControl import RobotControl
from SuctionNozzle import SuctionNozzle
# Touch placement
touch = TOUCH()
pwm = PWMServo()
buzzer = Buzzer()
bus_servo = BusServo()
arm = ESPMax(bus_servo)
robot = RobotControl()
nozzle = SuctionNozzle()
```
Firstly, import the corresponding libraries and initialize buzzer, servo and action group.
Next, create the functions of buzzer and touch control. Set the buzzer to make sound feedback and the robotic arm to perform the corresponding action when short press the touch sensor.
Then, execute the function for controlling action, buzzer, and air pump to suck the detected object to the side and place it.
(1) Preparation
① Hardware
Please assemble the touch sensor to the corresponding position on MaxArm according to the tutorial in folder ["**Lesson 1 Sensor Assembly**"](https://drive.google.com/drive/folders/1KGpk_DRFmh2e1T_yGDQj8qsX9Bb9xATQ?usp=sharing) under the same directory.
② Software
Please connect MaxArm to Python editor according to the tutorial in folder ["**4. Underlying Program Learning--Python Development--Lesson 1 Set Development Environment**"](4.Underlying_Program_Learning_checked.md#anchor_4_3)
(2) Program Download
[Source Code](../_static/source_code/Secondary_Development.zip)
① After connecting, change the path of Workspace to ["**6. Secondary Development--Python Development--Sensor-extension Game**"](Appendix.md), and select **"Program Files"**.
② Click the folder **"Touch Detection and Placement"**, and then select all the program files in the folder.
③ Then right click to download all the program files to the controller.
④ When the terminal prints the prompt as shown in the image below, it means download completed.
⑤ After downloading, click on the reset icon or press the reset button on ESP32 controller to run program.
(3) Project Outcome
After the buzzer beeps once, the robotic arm will suck and place the blocks in a line. When three blocks are placed completely, the buzzer will make **"DiDi"** sound as a feedback, and then a round of placement is finished.
(4) Program Instruction
① Import Function library
The path to the program of the source code is ["**6. Secondary Development Application--Python Development--Sensor Related Game--Game Programs--Touch Detection and Placement--main.py**"](../_static/source_code/Secondary_Development.zip).
Before executing the program, the buzzer, PWM servo, bus servo and air pump and other related Python function libraries need to be imported.
{lineno-start=1}
```python
import time
from Buzzer import Buzzer
from espmax import ESPMax
from PWMServo import PWMServo
from BusServo import BusServo
from Touch_sensor import TOUCH
from RobotControl import RobotControl
from SuctionNozzle import SuctionNozzle
```
② Touch detection
Use the `touch.run_loop()` function to detect whether the touch is sensed.
{lineno-start=28}
```python
if touch.down_up(): #Short press on touch sensor
print('num:',num+1)
buzzer.setBuzzer(100) #Buzzer beeps once
arm.set_position((0,-160,100),1200) #Move arm above pickup position, wait 2s before suction
time.sleep_ms(2000)
arm.set_position((0,-160,85),600) #Suction the color block
nozzle.on() # Turn on the pump
time.sleep_ms(1000)
arm.set_position((0,-160,180),1000) #Lift the arm
time.sleep_ms(1000)
arm.set_position((120,-20-60*num,180),1500) # Move above placement position
nozzle.set_angle(angle[num],1500) #Apply angle compensation to align block
time.sleep_ms(1500)
arm.set_position((120,-20-60*num,83+num),1000) #Place the block
time.sleep_ms(1200)
nozzle.off() # Turn off pump
arm.set_position((120,-20-60*num,200),1000) # Lift the arm
time.sleep_ms(1000)
arm.go_home() #Reset arm to initial position
nozzle.set_angle(0,1800) #Reset suction nozzle angle to
time.sleep_ms(2000)
```
③ Control robotic arm
After sensing the touch, MaxArm will execute the corresponding action.
{lineno-start=28}
```python
if touch.down_up(): #Short press on touch sensor
print('num:',num+1)
buzzer.setBuzzer(100) #Buzzer beeps once
arm.set_position((0,-160,100),1200) #Move arm above pickup position, wait 2s before suction
time.sleep_ms(2000)
arm.set_position((0,-160,85),600) #Suction the color block
nozzle.on() # Turn on the pump
time.sleep_ms(1000)
arm.set_position((0,-160,180),1000) #Lift the arm
time.sleep_ms(1000)
arm.set_position((120,-20-60*num,180),1500) # Move above placement position
nozzle.set_angle(angle[num],1500) #Apply angle compensation to align block
time.sleep_ms(1500)
arm.set_position((120,-20-60*num,83+num),1000) #Place the block
time.sleep_ms(1200)
nozzle.off() # Turn off pump
arm.set_position((120,-20-60*num,200),1000) # Lift the arm
time.sleep_ms(1000)
arm.go_home() #Reset arm to initial position
nozzle.set_angle(0,1800) #Reset suction nozzle angle to 0
time.sleep_ms(2000)
```
Use the `buzzer.setBuzze()` function to control the buzzer. Take the code `buzzer.setBuzzer(100)` as example.
The first parameter **"100"** represents the sounding time and the unit is ms.
Use the `arm.set_position()` function to control the robotic arm. Take the code `arm.set_position((0,-160,100),1200)` as example.
The first parameter **"(0,-160,100)"** is the position of the suction nozzle on x, y and z axes.
The second parameter **"1200"** is the running time and the unit is ms.
Use the `nozzle.set_angle()` function to control the rotation of the suction nozzle. Take the code `nozzle.set_angle(0,1800)` as example.
The first parameter **"0"** represents the angle of PWM servo.
The second parameter **"1800"** represents the running time and the unit is ms.
### 6.2.6 Infrared Detection and Control
* **Working Principle**
Infrared obstacle avoidance is a photoelectric sensor integrating IR transmitter and IR receiver. Featuring long detection distance and low interference from visible light , it is widely used in robot and assembly line piecework, etc.
This sensor detects obstacle by transmitting and receiving infrared. When the infrared transmitted by the sensor meets the obstacle ahead, the infrared will be reflected to the receiving terminal. When the sensor detects this signal, it will send it to the microcontroller for processing.
The closer the obstacle is, the stronger the reflection intensity; the farther the obstacle is, the weaker the reflection intensity. Different surface color has different reflection intensity. White is the strongest and black is the weakest.
The path of the program file: ["**6. Secondary Development--Python Development--Sensor-extension Game--Program Files--Infrared Detection and Control--main.py**"](../_static/source_code/Secondary_Development.zip).
{lineno-start=1}
```python
import time
from Buzzer import Buzzer
from espmax import ESPMax
from PWMServo import PWMServo
from BusServo import BusServo
from Infrared_sensor import INFRARED
from RobotControl import RobotControl
from SuctionNozzle import SuctionNozzle
#Infrared detection control
pwm = PWMServo()
buzzer = Buzzer()
infrared = INFRARED()
bus_servo = BusServo()
arm = ESPMax(bus_servo)
robot = RobotControl()
nozzle = SuctionNozzle()
```
Firstly, import the corresponding libraries and initialize buzzer, servo and action group.
Next, detect the object by the infrared sensor and buzzer will make sound. MaxArm will perform the corresponding action.
Then, execute the function for controlling action, buzzer, air pump to suck and place the object.
(1) Preparation
① Hardware
Please assemble the infrared sensor to the corresponding position on MaxArm according to the tutorial in folder ["**Lesson 1 Sensor Assembly**"](https://drive.google.com/drive/folders/1EVmnhK-811IWFNIEoJufnu1-sM-wE1Yi?usp=sharing) under the same directory.
② Software
Please connect MaxArm to Python editor according to the tutorial in folder ["**4. Underlying Program Learning--Python Development--Lesson 1 Set Development Environment**"](4.Underlying_Program_Learning_checked.md#anchor_4_3).
(2) Program Download
[Source Code](../_static/source_code/Secondary_Development.zip)
① After connecting, change the path of Workspace to ["**6. Secondary Development--Python Development--Sensor-extension Game**"](Appendix.md), and select **"Program Files"**.
② Click the folder **"Infrared Detection and Control"**, and then select all the program files in the folder.
③ Then right click to download all the program files to the controller.
④ When the terminal prints the prompt as shown in the image below, it means download completed.
⑤ After downloading, click on the reset icon or press the reset button on ESP32 controller to run program.
(3) Project Outcome
After the buzzer make **"Di"** sound, MaxArm will suck and move the block to the placement area. Finally, the air pump will be turned off and MaxArm will return to the initial posture
(4) Program Instruction
① Import Function Library
The path of the program file: ["**6. Secondary Development--Python Development--Sensor-extension Game--Program Files--Infrared Detection and Control--main.py**"](../_static/source_code/Secondary_Development.zip).
Before executing the program, the buzzer, PWM servo, bus servo, infrared sensor, air pump and other related Python function libraries need to be imported.
{lineno-start=1}
```python
import time
from Buzzer import Buzzer
from espmax import ESPMax
from PWMServo import PWMServo
from BusServo import BusServo
from Infrared_sensor import INFRARED
from RobotControl import RobotControl
from SuctionNozzle import SuctionNozzle
```
② Infrared Detection
Use the `infrared.run_loop()` function to detect whether there is a object.
{lineno-start=27}
```python
while True:
infrared.run_loop()
```
③ Control robotic arm
After object is detected by the infrared sensor, MaxArm will execute the corresponding action.
{lineno-start=30}
```python
if infrared.close_long():
buzzer.setBuzzer(100) #Set buzzer on for 100 ms
arm.set_position((0,-160,100),1500)
time.sleep_ms(1000) #Wait for 1000 ms
arm.set_position((0,-160,85),800) #Suction the color block
nozzle.on() #Turn on the pump
time.sleep_ms(1000)
arm.set_position((0,-160,200),1000) #Lift up
time.sleep_ms(1000)
arm.set_position((70,-150,200),800) #Move above placing area
nozzle.set_angle(30,600)
time.sleep_ms(1000)
nozzle.set_angle(35,300)
arm.set_position((70,-150,90),800) #Move to placing area
time.sleep_ms(800)
arm.set_position((130,-150,88),500) #Shift left to place
time.sleep_ms(500)
nozzle.off() #Turn off vacuum pump
```
Use the `buzzer.setBuzze()` function to control the buzzer. Take the code `buzzer.setBuzzer(100)` as example.
The first parameter **"100"** is the sounding time of buzzer and the unit is ms.
Use the `arm.set_position()` function to control the robotic arm. Take the code `arm.set_position((0,-160,100),1500)` as example.
The first parameter **"(0,-160,100)"** is the position of the suction nozzle on x, y and z axes.
The second parameter **"1500"** is the running time and the unit is ms.
Use the `nozzle.set_angle()` function to control the rotation of the suction nozzle. Take the code `nozzle.set_angle(30,600)` as example.
The first parameter **"30"** represents the angle of PWM servo.
The second parameter **"600"** represents the running time and the unit is ms.
### 6.2.7 Dual Infrared Detection and Sorting
* **Project Principle**
Infrared obstacle avoidance is a photoelectric sensor integrating IR transmitter and IR receiver. Featuring long detection distance and low interference from visible light , it is widely used in robot and assembly line piecework, etc.
This sensor detects obstacle by transmitting and receiving infrared. When the infrared transmitted by the sensor meets the obstacle ahead, the infrared will be reflected to the receiving terminal. After the signal is detected, it will travel to microcontroller for processing.
The closer the obstacle is, the stronger the reflection intensity; the farther the obstacle is, the weaker the reflection intensity. Different surface color has different reflection intensity. White is the strongest and black is the weakest.
The path of program file: ["**6. Sensor-extension game--Python Development--Program Files--Dual Infrared Sorting--main.py**"](../_static/source_code/Secondary_Development.zip)
{lineno-start=1}
```python
import time
from Buzzer import Buzzer
from espmax import ESPMax
from PWMServo import PWMServo
from BusServo import BusServo
from Infrared_sensor import INFRARED
from RobotControl import RobotControl
from SuctionNozzle import SuctionNozzle
#Dual infrared detection and sorting
pwm = PWMServo()
buzzer = Buzzer()
bus_servo = BusServo()
arm = ESPMax(bus_servo)
robot = RobotControl()
nozzle = SuctionNozzle()
infrared_left = INFRARED(23)
infrared_right = INFRARED(32)
infrared_left.set_long_close_time(500)
infrared_right.set_long_close_time(500)
if __name__ == '__main__':
arm.go_home() # Arm reset to home position
nozzle.set_angle(0,1000) #Set nozzle angle to 0
time.sleep_ms(2000)
time_ = time.time()
while True:
infrared_left.run_loop() # Run sensor detection function
time.sleep(0.05)
infrared_right.run_loop()
if infrared_left.close_long(): # Left sensor detects block
print("infrared_left")
buzzer.setBuzzer(100) #Set buzzer on for 100 ms
arm.set_position((70,-165,120),1500)
time.sleep_ms(1000) # Wait for 1000 ms
arm.set_position((70,-165,86),800) #Suction the color block
nozzle.on() #Turn on the pump
time.sleep_ms(1000)
```
Firstly, import the required libraries and reset robotic arm and suction nozzle.
Then call infrared detection function to detect object. When a object is detected, buzzer will sound for responding and robotic arm will suck the object and move it to the corresponding position.
(1) Preparation
① Hardware
Please assemble infrared sensor to the corresponding position on MaxArm according to the tutorial in folder ["**Lesson 1 Sensor Assembly**"](https://drive.google.com/drive/folders/10qSPO3omd9oN8F-IsRNMNgt_1YBeaY2i?usp=sharing) under the same directory.
② Software
Please connect MaxArm to Python editor according to the tutorial in folder ["**4. Underlying Program Learning--Python Development--Lesson 1 Set Development Environment**"](4.Underlying_Program_Learning_checked.md#anchor_4_3).
(2) Program Download
[Source Code](../_static/source_code/Secondary_Development.zip)
After connecting, change the path of Workspace to ["**6. Secondary Development--Python Development--Sensor-extension Game**"](Appendix.md), and select **"Program Files"**.
① Click the folder **"Dual Infrared Detection and Sorting"**, and then select all the program files in the folder.Then right click to download all the program files to the controller.
After downloading, click on the reset icon or press the reset button on ESP32 controller to run program.
(3) Project Outcome
Place a block in front of the right side of robot arm. When the block is detected by sensor, the buzzer will sound for a while and robotic arm will suck and place the block in the right side.
(4) Program Instruction
The path of program file: ["**6. Secondary Development--Python Development--Program Files--Dual Infrared Sorting--main.py**"](../_static/source_code/Secondary_Development.zip)
① Initialization Configuration
**Import function library**
Firstly, import buzzer, kinematics, kinematics encapsulation library, PWM servo, suction nozzle and other related library files.
{lineno-start=1}
```python
import time
from Buzzer import Buzzer
from espmax import ESPMax
from PWMServo import PWMServo
from BusServo import BusServo
from Infrared_sensor import INFRARED
from RobotControl import RobotControl
from SuctionNozzle import SuctionNozzle
```
**Reset**
Call the related function to reset robotic arm and suction nozzle.
{lineno-start=25}
```python
arm.go_home() # Arm reset to home position
nozzle.set_angle(0,1000) #Set nozzle angle to 0
```
The `nozzle.set_angle()` function is used to control the rotation angle of suction nozzle, that is, control the corresponding PWM servo. The meaning of parameters in parentheses are as follow:
The first parameter **"0"** refers to the rotation angle of PWM servo.
The second parameter **"1000"** is the running time, that is, the time for the servo to rotate the specified angle, and the unit is milliseconds (ms).
② Infrared Detection
Call infrared sensor to detect object. The `infrared_left.run_loop()` function is the detection function corresponding to the left sensor, and the `infrared_right.run_loop()` function is the detection function corresponding to the right sensor.
{lineno-start=30}
```python
infrared_left.run_loop()
time.sleep(0.05)
infrared_right.run_loop()
```
③ Robotic Arm Control
Take the left infrared sensor for example to analyze its source code. The realization principle is the same with the right infrared sensor.
{lineno-start=34}
```python
if infrared_left.close_long(): # Left sensor detects block
print("infrared_left")
buzzer.setBuzzer(100) #Set buzzer on for 100 ms
arm.set_position((70,-165,120),1500)
time.sleep_ms(1000) # Wait for 1000 ms
arm.set_position((70,-165,86),800) #Suction the color block
nozzle.on() #Turn on the pump
time.sleep_ms(1000)
arm.set_position((70,-165,200),1000) #Lift up
time.sleep_ms(1000)
arm.set_position((150,-35,200),800) #Move above placing area
nozzle.set_angle(15,500)
time.sleep_ms(500)
arm.set_position((150,-35,90),800) #Move to placing area
time.sleep_ms(800)
arm.set_position((150,10,88),500) #Shift to place
time.sleep_ms(500)
nozzle.off() #Turn off the pump
arm.set_position((150,10,200),1000) #Lift up
time.sleep_ms(1000)
arm.go_home() #Arm reset to home position
nozzle.set_angle(0,2000)
time.sleep_ms(2000)
```
**Buzzer Feedback**
When a block is detected by infrared sensor, the buzzer alarms by calling `buzzer.setBuzzer()` function. The parameter in parenthesis refers to the duration of alarming and the unit is ms.
{lineno-start=36}
```python
buzzer.setBuzzer(100) #Set buzzer on for 100 ms
```
**Suck & Place Block**
By calling `arm.set_position()` function, robotic arm is controlled to rotate to the specific position. Combing this function and air pump control function to execute sorting function.
{lineno-start=37}
```python
arm.set_position((70,-165,120),1500)
time.sleep_ms(1000) # Wait for 1000 ms
arm.set_position((70,-165,86),800) #Suction the color block
nozzle.on() #Turn on the pump
time.sleep_ms(1000)
arm.set_position((70,-165,200),1000) #Lift up
time.sleep_ms(1000)
arm.set_position((150,-35,200),800) #Move above placing area
nozzle.set_angle(15,500)
time.sleep_ms(500)
arm.set_position((150,-35,90),800) #Move to placing area
time.sleep_ms(800)
arm.set_position((150,10,88),500) #Shift to place
time.sleep_ms(500)
nozzle.off() #Turn off the pump
arm.set_position((150,10,200),1000) #Lift up
time.sleep_ms(1000)
arm.go_home() #Arm reset to home position
nozzle.set_angle(0,2000)
time.sleep_ms(2000)
```
Take the code `arm.set_position((70,-165,120),1500)` for example. The meaning of the parameters in parenthesis is as follow:
The first parameter **"(70,-165,120)"** represents the target position, i.e., the target coordinate position of end effector. Three parameters are the value of x,y and z axes.
The second parameter **"1500"** is the running time, e.i., the time for the nozzle to move to the target position and the unit is ms.
### 6.2.8 Color Recognition
* **Working Principle**
The color sensor is a sensor with various functions such as recognizing the color of objects, detecting the brightness of the surrounding environment, realizing object proximity detection and non-contact gesture detection, etc.
This lesson will use the color sensor for recognizing and comparing the RGB value of object. These sensors generally determine whether the detected color is consistent with the set one by using RGB (red, green, and blue) LED light sources and the ratio of R, G, and B wavelengths in the reflected light of an object.
The path of the program file: ["**6. Secondary Development--Sensor-extension Game--Python Development--Color Recognition--Program Files--Color Recognition--main.py**"](../_static/source_code/Secondary_Development.zip).
{lineno-start=1}
```python
import time
from machine import Pin, I2C
from Ultrasonic import ULTRASONIC
from Color_sensor import COLOR
from Buzzer import Buzzer
from espmax import ESPMax
from PWMServo import PWMServo
from BusServo import BusServo
from RobotControl import RobotControl
from SuctionNozzle import SuctionNozzle
# Color recognition
pwm = PWMServo()
buzzer = Buzzer()
bus_servo = BusServo()
arm = ESPMax(bus_servo)
robot = RobotControl()
nozzle = SuctionNozzle()
```
Firstly, import the corresponding libraries and initialize ultrasonic sensor and color sensor.
Then read and calculate the RGB value of the object, and print out the color result.
Finally, the ultrasonic sensor emits light of the corresponding color.
(1) Preparation
① Hardware
Please assemble the color sensor and ultrasonic sensor to the corresponding position on MaxArm according to the tutorial in folder ["**Lesson 1 Sensor Assembly**"](https://drive.google.com/drive/folders/1NTJRLOOuC70Y2K6H0J1QdzSy8wpUMgcx?usp=sharing) under the same directory.
② Software
Please connect MaxArm to Python editor according to the tutorial in folder ["**4. Underlying Program Learning--Python Development--Lesson 1 Set Development Environment**"](4.Underlying_Program_Learning_checked.md#anchor_4_3).
(2) Program Download
[Source Code](../_static/source_code/Secondary_Development.zip)
① After connecting, change the path of Workspace to ["**6. Secondary Development--Sensor-extension Game--Python Development--**"](Appendix.md), and select **"Program Files"**.
② Click the folder **"Color Recognition"**, and then select all the program files in the folder.
③ Then right click to download all the program files to the controller.
When the terminal prints the prompt as shown in the image below, it means download completed.
④ After downloading, click on the reset icon or press the reset button on ESP32 controller to run program.
(3) Project Outcome
After the colored block is detected by the color sensor, the glowing ultrasonic sensor will emit the corresponding color light.
(4) Program Instruction
① Import Function Library
Before executing the program, the I2C protocol, ultrasonic sensor, color sensor, buzzer, PWM servo, bus servo, infrared sensor and air pump and other related Python function libraries need to be imported.
The path of the program file ["**6. Secondary Development--Python Development--Color Recognition--Program Files--Color Recognition--main.py**"](../_static/source_code/Secondary_Development.zip).
{lineno-start=1}
```python
import time
from machine import Pin, I2C
from Ultrasonic import ULTRASONIC
from Color_sensor import COLOR
from Buzzer import Buzzer
from espmax import ESPMax
from PWMServo import PWMServo
from BusServo import BusServo
from RobotControl import RobotControl
from SuctionNozzle import SuctionNozzle
```
② Color Detection
Use `apds.readRedLight()`, `apds.readGreenLight()` and `apds.readBlueLight()` functions to detect the value of RGB channel of object, and calculate.
{lineno-start=51}
```python
# Parse color sensor data
c = apds.readAmbientLight()
r = apds.readRedLight()
g = apds.readGreenLight()
b = apds.readBlueLight()
r = int(255 * (r - r_f) / (R_F - r_f))
g = int(255 * (g - g_f) / (G_F - g_f))
b = int(255 * (b - b_f) / (B_F - b_f))
```
③ Control the LED of Ultrasonic Sensor
After calculating the value of RGB channel of object color, determine the color of the object.
{lineno-start=59}
```python
if r > 25 and r > g and r > b: # Output color detection result, set ultrasonic RGB accordingly
color = RED # Detected red
print('color: red')
```
Then, the ultrasonic sensor will emit the corresponding light.
{lineno-start=60}
```python
color = RED # Detected red
print('color: red')
hwsr06.setRGBValue(bytes([255,0,0, 255,0,0]))
elif g > 25 and g > r and g > b:
color = GREEN # Detected green
print('color: green')
hwsr06.setRGBValue(bytes([0,255,0, 0,255,0]))
elif b > 25 and b > g and b > r:
color = BLUE # Detected blue
print('color: blue')
hwsr06.setRGBValue(bytes([0,0,255, 0,0,255]))
else: # No color detected
color = 0
print('')
hwsr06.setRGBValue(bytes([255,255,255, 255,255,255]))
```
Use `hwsr06.setRGBValue(bytes())` function to control the LED of the ultrasonic sensor. Take the code `hwsr06.setRGBValue(bytes([255,0,0, 255,0,0]))` as example.
The first three parameters **"255,0,0"** are the color thresholds for the LED on the right side of the senor.
The last three parameters **"255,0,0"** are the color thresholds for the left LED of the sensor.
At this time, the LED emits red light.
### 6.2.9 Color Sorting
* **Working Principle**
The color sensor is a sensor with various functions such as recognizing the color of objects, detecting the brightness of the surrounding environment, realizing object proximity detection and non-contact gesture detection, etc.
This lesson will use the color sensor for recognizing and comparing the RGB value of object. These sensors generally determine whether the detected color is consistent with the set one by using RGB (red, green, and blue) LED light sources and the ratio of R, G, and B wavelengths in the reflected light of an object.
The path of the program file: ["**6. Secondary Development--Python Development--Sensor-extension Game--Color Sorting--Program Files--Color Sorting--main.py**"](../_static/source_code/Secondary_Development.zip).
{lineno-start=1}
```python
import time
from machine import Pin, I2C
from Ultrasonic import ULTRASONIC
from Color_sensor import COLOR
from Buzzer import Buzzer
from espmax import ESPMax
from PWMServo import PWMServo
from BusServo import BusServo
from RobotControl import RobotControl
from SuctionNozzle import SuctionNozzle
# Color sorting
pwm = PWMServo()
buzzer = Buzzer()
bus_servo = BusServo()
arm = ESPMax(bus_servo)
robot = RobotControl()
nozzle = SuctionNozzle()
```
Firstly, import the corresponding libraries and initialize ultrasonic sensor and color sensor.
Then read and calculate the RGB value of the object, and print out the color result.
Finally, the ultrasonic sensor emits corresponding light, and the functions for controlling servo and air pump are executed. MaxArm will suck and place the object to the corresponding position according to the color.
(1) Preparation
① Hardware
Please assemble the color sensor and the ultrasonic sensor to the corresponding position on MaxArm according to the tutorial in folder ["**Lesson 1 Sensor Assembly**"](https://drive.google.com/drive/folders/1eW30jAdV-Q0I2gFY5-r64fkdLKRL5YlU?usp=sharing) under the same directory.
② Software
Please connect MaxArm to Python editor according to the tutorial in folder ["**4. Underlying Program--Python Development--Lesson 1 Set Development Environment**"](4.Underlying_Program_Learning_checked.md#anchor_4_3).
(2) Program Download
[Source Code](../_static/source_code/Secondary_Development.zip)
① After connecting, change the path of Workspace to ["**Appendix--7. Sensor-extension Game--Python Development**"](Appendix.md) and select the folder "Program Files".
② Click the folder **"Color Sorting"**, and then select all the program files in the folder.
③ Then right click to download all the program files to the controller.
④ When the terminal prints the prompt as shown in the image below, it means download completed.
⑤ After downloading, click on the reset icon or press the reset button on ESP32 controller to run program.
(3) Project Outcome
After the color sensor recognizes the color of the block and the ultrasonic sensor detects that the block is placed in the placement area, MaxArm will sort the block based on the recognized color, and suck and transport the block to the corresponding position.
(4) Program Instruction
① Import function library
The path of the program file: ["**6. Secondary Development--Sensor-extension Game--Python Development--Color Sorting--Program Files--Color Sorting--main.py**"](../_static/source_code/Secondary_Development.zip).
Before executing the program, the I2C protocol, ultrasonic sensor, color sensor, buzzer, PWM servo, bus servo, infrared sensor, air pump and other related Python function libraries need to be imported.
{lineno-start=1}
```python
import time
from machine import Pin, I2C
from Ultrasonic import ULTRASONIC
from Color_sensor import COLOR
from Buzzer import Buzzer
from espmax import ESPMax
from PWMServo import PWMServo
from BusServo import BusServo
from RobotControl import RobotControl
from SuctionNozzle import SuctionNozzle
```
② Color Detection
Use `apds.readRedLight()`, `apds.readGreenLight()` and `apds.readBlueLight()` functions of color sensor to detect the value of RGB channel of object, and then calculate the value.
{lineno-start=52}
```python
# Parse color sensor data
c = apds.readAmbientLight()
r = apds.readRedLight()
g = apds.readGreenLight()
b = apds.readBlueLight()
r = int(255 * (r - r_f) / (R_F - r_f))
g = int(255 * (g - g_f) / (G_F - g_f))
b = int(255 * (b - b_f) / (B_F - b_f))
```
③ Control the LED Light of Ultrasonic Sensor
After calculating the value of RGB channel of object color, determine the color of the object.
{lineno-start=60}
```python
if r > 25 and r > g and r > b:t = RED # Output color detection result
elif g > 25 and g > r and g > b:t = GREEN
elif b > 25 and b > g and b > r:t = BLUE
else:t = 0
```
And the block with different color is set to place in the different position.
{lineno-start=65}
```python
if t > 0:
buzzer.setBuzzer(100)
color = t # Get the detected color
print('color:',color)
if color == 1: # Set ultrasonic RGB and placement coordinates based on color
angle = -45
(x,y,z) = (120,-140,85)
```
Then, the ultrasonic sensor emits the corresponding color light.
{lineno-start=69}
```python
if color == 1: # Set ultrasonic RGB and placement coordinates based on color
angle = -45
(x,y,z) = (120,-140,85)
hwsr06.setRGBValue(bytes([255,0,0, 255,0,0]))
elif color == 2:
angle = -25
(x,y,z) = (120,-80,85)
hwsr06.setRGBValue(bytes([0,255,0, 0,255,0]))
elif color == 3:
angle = 0
(x,y,z) = (120,-20,82)
hwsr06.setRGBValue(bytes([0,0,255, 0,0,255]))
```
Use `hwsr06.setRGBValue(bytes())` function to control the LED light of the ultrasonic sensor. Take the code `hwsr06.setRGBValue(bytes([255,0,0, 255,0,0]))` as example.
The first three parameters **"255,0,0"** are the color thresholds for the LED on the right side of the senor.
The last three parameters **"255,0,0"** are the color thresholds for the left LED of the sensor.
At this time, the LED emits red light.
④ Ultrasonic Detection
If the block is detected, use `hwsr06.getDistance()` function to measure distance. Then use `print()` function to print out the measured distance.
{lineno-start=82}
```python
if color > 0: # Color detected
Distance = hwsr06.getDistance() # Get distance from ultrasonic sensor
print('distance:', Distance)
```
⑤ Control Robotic Arm
Determine whether there are objects at the distance between 70 and 80, and then execute the corresponding action.
{lineno-start=85}
```python
if 70 < Distance < 80: # Block distance satisfies picking condition, proceed to sorting
buzzer.setBuzzer(100) #Buzz for 100ms
time.sleep_ms(1000)
arm.set_position((0,-160,85),1500) #Suction the color block
nozzle.on() #Turn on the pump
time.sleep_ms(1600)
arm.set_position((0,-160,180),1000) #Lift arm
time.sleep_ms(1000)
arm.set_position((x,y,180),1000) #Move above corresponding placement area
time.sleep_ms(1000)
nozzle.set_angle(angle,800) # Set angle compensation
arm.set_position((x,y,z),800) # Place block
time.sleep_ms(1000)
nozzle.off() #Turn off the pump
arm.set_position((x,y,200),1000) #Lift arm
time.sleep_ms(1000)
arm.go_home() #Reset arm to home
```
Use `buzzer.setBuzze()` function to control the buzzer. Take the code `buzzer.setBuzze(100)` as example.
The first parameter **"100"** represents the sounding time of buzzer and the unit is ms.
Use `arm.set_position()` function to control robotic arm. Take the code `arm.set_position((0,-160,85),1500)` as example.
The first parameter **"(0,-160,85)"** represents is the position of the suction nozzle on x, y and z axes.
The second parameter **"1500"** is the running time and the unit is ms.
Use `nozzle.set_angle()` function to control the rotation of the suction nozzle. Take the code `nozzle.set_angle(0,800)` as example.
The first parameter **"0"** is the angle of PWM servo.
The second parameter **"800"** is the running time and the unit is ms.
### 6.2.10 Sound Detection and Placement
* **Project Principle**
Sound sensor has a in-built capacitive microphone. Sound waves cause the diaphragm in the microphone to vibrate, resulting in capacitance change, which in turn produces a correspondingly small change in voltage. This voltage is then converted into a voltage in the range of 0-5 V and compared with an adjustable voltage with adjusted sensitivity by means of a comparator.
Then it is received by the data collector through the A/D conversion of module, and the range is 0-1023. The value is higher as the sound intensity increases, so the detected sound is proportional to the output analog quantity.
The path of program file: ["**6. Secondary Development--Sensor-extension Game--Python Development--Program Files--Light Detection and Placement--main.py**"](../_static/source_code/Secondary_Development.zip)
{lineno-start=19}
```python
# Initialize light sensor
light_sendor = ADC(Pin(32))
light_sendor.atten(ADC.ATTN_11DB)
light_sendor.width(ADC.WIDTH_10BIT)
if __name__ == '__main__':
arm.go_home() #Reset arm to home position
nozzle.set_angle(0,1000) #Set nozzle angle to 0
time.sleep_ms(2000)
num = 0 #Block count variable
angle = [12, 35, 55] #Angle compensation
while True:
light = light_sendor.read() #Read light sensor
print(light)
if light > 900: # Light sensor blocked
print('num:',num+1)
buzzer.setBuzzer(100) #Beep buzzer once
time.sleep_ms(500)
arm.set_position((0,-165,100),1200) #Move arm above pickup position and wait 2 seconds before picking up
time.sleep_ms(2000)
arm.set_position((0,-165,86),600) #Suction the color block
```
Firstly, import sensor library files and initialize sensor.
Then create sound detection function to detect sound. After the sound is detected, buzzer will sound once for responding.
Then use kinematics to control robotic arm and place block to the corresponding position.
(1) Preparation
① Hardware
Please assemble sound sensor to the corresponding position on MaxArm according to the tutorial in folder ["**Lesson 1 Sensor Assembly**"](https://drive.google.com/drive/folders/1blLJls84JH_JCfTiMEm0u--p8iOVFKox?usp=sharing) under the same directory.
② Software
Please connect MaxArm to Python editor according to the tutorial in folder ["**4. MaxArm Underlying Program Learning--Python Development--Lesson 1 Set Development Environment**"](4.Underlying_Program_Learning_checked.md#anchor_4_3).
(2) Program Download
[Source Code](../_static/source_code/Secondary_Development.zip)
① After connecting, change the path of Workspace to ["**6. Secondary Development--Python Development--Sensor-extension Game**"](../_static/source_code/Secondary_Development.zip), and select "**Program Files**".
② Click the folder **"Sound Detection and Placement"**, and then select all the program files in the folder. Then right click to download all the program files to the controller.
When the terminal prints the prompt as shown in the image below, it means download completed.
③ After downloading, click on the reset icon or press the reset button on ESP32 controller to run program.
(3) Project Outcome
When a knock sound is detected by sensor, the buzzer will sound once. According to the number of knocks, robot arm will place object to the corresponding position in the right side (take robot arm as the first person view) . You can view the demo video for the specific effect.
(4) Program Instruction
① Import Function Library
The path of program file: ["**6. Secondary Development--Sensor-extension Game--Python Development--Program Files--Light Detection and Placement--main.py**"](../_static/source_code/Secondary_Development.zip)
Before the program is executed, the related Python function libraries including buzzer, PWM servo, bus servo, air pump and other related Python function libraries are required to import.
{lineno-start=1}
```python
import time
from machine import Pin,ADC
from Buzzer import Buzzer
from espmax import ESPMax
from PWMServo import PWMServo
from BusServo import BusServo
from RobotControl import RobotControl
from SuctionNozzle import SuctionNozzle
```
② Initialization
Initialize sound sensor and robotic arm, which makes robotic arm back to the initial posture.
{lineno-start=19}
```python
# Initialize sound sensor
sound_sendor = ADC(Pin(32))
sound_sendor.atten(ADC.ATTN_11DB)
sound_sendor.width(ADC.WIDTH_10BIT)
if __name__ == '__main__':
arm.go_home() #Reset arm to home position
nozzle.set_angle(0,1000) #Set nozzle angle to 0
time.sleep_ms(2000)
angle = [12, 35, 55] #Angle compensation for placement
time_ms = time.ticks_ms()
num_st = False
num = 0
```
③ Sound Detection
When the sound is detected, the number of knocks plus one. If the number of detected knocks is greater than 3, then game will start from a new round.
{lineno-start=33}
```python
while True:
sound = sound_sendor.read() #Read sound sensor value
if sound > 50:
if num == 0 or (time.ticks_ms()-time_ms) < 1000:
time_ms = time.ticks_ms()
time.sleep_ms(80)
num += 1
if num and (time.ticks_ms()-time_ms) > 1500:
num = 3 if num > 3 else num
num_st = True
print(num)
```
④ Control Robotic Arm
When sound is detected, robotic arm will suck up block and place it to the corresponding position according to the number of knocks.
{lineno-start=47}
```python
if num_st:
buzzer.setBuzzer(100) # Buzz once
arm.set_position((0,-160,100),1200) # Move arm above pickup position and wait 2 seconds before picking up
time.sleep_ms(2000)
arm.set_position((0,-160,86),600) # Suction the color block
nozzle.on() # Turn on the pump
time.sleep_ms(1000)
arm.set_position((0,-160,180),1000) # Lift arm
time.sleep_ms(1000)
arm.set_position((120,-20-60*(num-1),180),1500) # Reset arm to home position
nozzle.set_angle(angle[(num-1)],1500) # Set angle compensation
time.sleep_ms(1500)
arm.set_position((120,-20-60*(num-1),88),1000) # Place block
time.sleep_ms(1200)
nozzle.off() # Turn off the pump
arm.set_position((120,-20-60*(num-1),200),1000) # Lift arm
time.sleep_ms(1000)
arm.go_home() # Reset arm to home position
nozzle.set_angle(0,1800) # Reset nozzle angle to 0
time.sleep_ms(2000)
num_st = False
num = 0
```
The specific program for block placement control is as follow:
The program use the `buzzer.setBuzze()` function to control buzzer, as the figure shown below:
{lineno-start=48}
```python
buzzer.setBuzzer(100) # Buzz once
```
Take the code `buzzer.setBuzzer(100)` for example:
The parameter "100" represent the sounding duration of buzzer and the unit is ms.
The use the `arm.set_position()` function to control robot arm to locate above the block, as the figure shown below:
{lineno-start=49}
```python
arm.set_position((0,-160,100),1200) # Move arm above pickup position and wait 2 seconds before picking up
time.sleep_ms(2000)
```
Take the code `arm.set_position((0,-160,100),1200)` for example:
The first parameter **"(0,-160,100)"** represents the coordinate of end effector. (You can read "**Basic Kinematics Learning (must read!!!)**" in folder ["**6. Secondary Development--6. Sensor-extension Game--Python Development**"](../_static/source_code/Secondary_Development.zip)) to learn about space coordinate system.
The second parameter "1200" is the running time and the unit is ms.
Next, use the `nozzle.on()` function to turn on air pump. If it is `nozzle.off()` function, air pump will be off.
{lineno-start=52}
```python
nozzle.on() # Turn on the pump
```
Then, use the `nozzle.set_angle()` function to control the rotation angle of suction nozzle, as the figure shown below:
{lineno-start=56}
```python
arm.set_position((120,-20-60*(num-1),180),1500) # Reset arm to home position
```
Take the code `arm.set_position((120,-20-60*(num-1),180),1500)` for example.
The first parameter **"120"** represents the x-axis value of suction nozzle.
The second parameter `-20-60*(num-1)` represents the y-axis of suction nozzle. The value of y-axis is calculated according to the number of detected knocks.
The third parameter **"1500"** is the running time and the unit is ms.
After block moves to the corresponding position, use the `nozzle.set_angle()`function to adjust the angle of suction nozzle to place block in a neat direction.
{lineno-start=57}
```python
nozzle.set_angle(angle[(num-1)],1500) # Set angle compensation
time.sleep_ms(1500)
```
Take the code `nozzle.set_angle(angle[(num-1)],1500)` as example:
The first parameter **"angle[(num-1)"** is the angle setting. The different angles corresponding to three detection results are 12°, 35°and 55°individually, as the figure shown below:
{lineno-start=28}
```python
gle = [12, 35, 55] #Angle compensation for placement
```
Finally, robotic arm will be place block to the corresponding position and turn off air pump. Robot arm will return to initial position and suction nozzle restore to the initial position.
{lineno-start=59}
```python
arm.set_position((120,-20-60*(num-1),88),1000) # Place block
time.sleep_ms(1200)
nozzle.off() # Turn off the pump
arm.set_position((120,-20-60*(num-1),200),1000) # Lift arm
time.sleep_ms(1000)
arm.go_home() # Reset arm to home position
nozzle.set_angle(0,1800) # Reset nozzle angle to 0
```
### 6.2.11 Light Detection and Placement
Please prepare a light-blocking prop for this game. You can use 3D printer to print a prop shown in the following image or use hard material to make one.
* **Project Principle**
This game uses light sensor to sense the ambient light intensity to judge if it is covered by object. Then robot arm is controlled to place object in the corresponding area.
A photosensitive sensor is a sensitive device that responds or converts to external light signals or light radiation. The sensor mainly contains a QT523C (photodiode) and an LM358 chip (voltage comparator).
When it works, sensor uses QT523C to convert light signal to an electrical signal output, which is then converted to a voltage ranging 0 to 5V and received by the data collector after A/D conversion in the range of 0-1023. The greater the external brightness intensity, the smaller the output voltage, so the brightness is inversely proportional to the output voltage.
The path of the program file: ["**6. Secondary Devlopment--Sensor-extension Game--Python Development--Program Files--Sound Detection and Placement--main.py**"](../_static/source_code/Secondary_Development.zip)
{lineno-start=24}
```python
if __name__ == '__main__':
arm.go_home() #Reset arm to home position
nozzle.set_angle(0,1000) #Set nozzle angle to 0
time.sleep_ms(2000)
num = 0 #Block count variable
angle = [12, 35, 55] #Angle compensation
while True:
light = light_sendor.read() #Read light sensor
print(light)
if light > 900: # Light sensor blocked
print('num:',num+1)
buzzer.setBuzzer(100) #Beep buzzer once
time.sleep_ms(500)
arm.set_position((0,-165,100),1200) #Move arm above pickup position and wait 2 seconds before picking up
time.sleep_ms(2000)
arm.set_position((0,-165,86),600) #Suction the color block
nozzle.on() # Turn on the pump
time.sleep_ms(1000)
arm.set_position((0,-165,180),1000) #Lift arm
time.sleep_ms(1000)
arm.set_position((120,-20-60*num,180),1500) # Move above placement position
nozzle.set_angle(angle[num],1500) #Set angle compensation to place block straight
time.sleep_ms(1500)
arm.set_position((120,-20-60*num,88),1000) #Place block
time.sleep_ms(1200)
nozzle.off() # Turn off the pump
arm.set_position((120,-20-60*num,200),1000) # Lift arm
time.sleep_ms(1000)
arm.go_home() #Reset arm to home position
nozzle.set_angle(0,1800) #Set nozzle angle to 0
time.sleep_ms(2000)
num += 1 #Increment block count
if num >= 3:
num = 0
buzzer.setBuzzer(80) #Beep buzzer once
time.sleep_ms(100)
buzzer.setBuzzer(80) #Beep buzzer once
```
Use light sensor to detect the light intensity, and then send the signal to microcontroller for processing. When the light intensity is lower than the set threshold in program, buzzer will sound for responding, and MaxArm will perform the corresponding action.
The first detected object will be placed at position 1. The second detected object will be placed at position 2. The third detected object will be place at position 3. As the figure shown below:
Then, execute the functions for controlling action, buzzer and air pump to control robot arm to move object and place it to the corresponding position on the left side. (Take robotic arm as the first person view)
:::{Note}
* Since light sensor is susceptible to the ambient light, you may need to adjust the potentiometer of sensor based on the actual situation.
* Due to the swing of the robot arm, the specific object landing point may be deviated, but the overall range will be as shown above.
* When strong light is detected, the blue LED light on sensor will keep on. As the light becomes weak, the blue LED light will be off. Please note that this has nothing to do with the brightness of the sensor being covered by the object.
:::
(1) Preparation
① Hardware
Please assemble sound sensor to the corresponding position on MaxArm according to the tutorial in folder ["**Lesson 1 Sensor Assembly**"](https://drive.google.com/drive/folders/1Ge_PjswOoJDyNpPAkAfQOe_DtsI3MHxH?usp=sharing) under the same directory.
② Software
Please connect MaxArm to Python editor according to the tutorial in folder ["**4. MaxArm Underlying Program Learning--Python Development--Lesson 1 Set Development Environment**"](4.Underlying_Program_Learning_checked.md#anchor_4_3).
(2) Program Download
[Source Code](../_static/source_code/Secondary_Development.zip)
① After connecting, change the path of Workspace to ["**6. Secondary Development--Python Development--Sensor-extension Game**"](Appendix.md), and select **"Program Files"**.
② Click the folder **"Sound Detection and Placement"** and select all the program files.
③ Then right click to download all the program files to the controller.
When the terminal prints the prompt as shown in the image below, it means download completed.
④ After downloading, click on the reset icon or press the reset button on ESP32 controller to run program.
(3) Project Outcome
When light sensor starts to detecting light, it covered by object resulting in the light intensity is lower than the threshold set in program. At this time, microcontroller will receive a command, and then robot arm will turn on air pump and suck the object and place it to corresponding position. After that, turn off the air pump, reset and wait for the next command.
(4) Program Instruction
① Import function library and Initialize
The path of the program file: ["**6. Secondary Development--Sensor-extension Game--Python Development--Program Files--light Detection and Placement--LightSensor_put--LightSensor_put.ino**"](../_static/source_code/Secondary_Development.zip). If the program is modified, you can find a backup file in Appendix.
Before running the program, the related function libraries including buzzer, PWM servo, bus servo, infrared sensor, and air pump are required to imported first.
{lineno-start=1}
```python
import time
from machine import Pin,ADC
from Buzzer import Buzzer
from espmax import ESPMax
from PWMServo import PWMServo
from BusServo import BusServo
from RobotControl import RobotControl
from SuctionNozzle import SuctionNozzle
```
Then, initialize the library files and robotic arm.
{lineno-start=12}
```python
pwm = PWMServo()
buzzer = Buzzer()
bus_servo = BusServo()
arm = ESPMax(bus_servo)
robot = RobotControl()
nozzle = SuctionNozzle()
# Initialize light sensor
light_sendor = ADC(Pin(32))
light_sendor.atten(ADC.ATTN_11DB)
light_sendor.width(ADC.WIDTH_10BIT)
```
② Light Detection
Use `analogRead()` function to read the analog amount of detected light intensity. When the analog amount reaches the set threshold, the program will place object at position 1. When the next object is detected, it will be placed at position 2. After recognizing and placing three time, game will enter the next round.
{lineno-start=24}
```python
if __name__ == '__main__':
arm.go_home() #Reset arm to home position
nozzle.set_angle(0,1000) #Set nozzle angle to 0
time.sleep_ms(2000)
num = 0 #Block count variable
angle = [12, 35, 55] #Angle compensation
while True:
light = light_sendor.read() #Read light sensor
print(light)
if light > 900: # Light sensor blocked
print('num:',num+1)
buzzer.setBuzzer(100) #Beep buzzer once
time.sleep_ms(500)
arm.set_position((0,-165,100),1200) #Move arm above pickup position and wait 2 seconds before picking up
time.sleep_ms(2000)
arm.set_position((0,-165,86),600) #Suction the color block
nozzle.on() # Turn on the pump
time.sleep_ms(1000)
arm.set_position((0,-165,180),1000) #Lift arm
time.sleep_ms(1000)
arm.set_position((120,-20-60*num,180),1500) # Move above placement position
nozzle.set_angle(angle[num],1500) #Set angle compensation to place block straight
time.sleep_ms(1500)
arm.set_position((120,-20-60*num,88),1000) #Place block
time.sleep_ms(1200)
nozzle.off() # Turn off the pump
arm.set_position((120,-20-60*num,200),1000) # Lift arm
time.sleep_ms(1000)
arm.go_home() #Reset arm to home position
nozzle.set_angle(0,1800) #Set nozzle angle to 0
time.sleep_ms(2000)
num += 1 #Increment block count
if num >= 3:
num = 0
buzzer.setBuzzer(80) #Beep buzzer once
time.sleep_ms(100)
buzzer.setBuzzer(80) #Beep buzzer once
```
③ Light Detection Feedback
When cover is detected by sensor, MaxArm will execute the corresponding action.
{lineno-start=24}
```python
if __name__ == '__main__':
arm.go_home() #Reset arm to home position
nozzle.set_angle(0,1000) #Set nozzle angle to 0
time.sleep_ms(2000)
num = 0 #Block count variable
angle = [12, 35, 55] #Angle compensation
while True:
light = light_sendor.read() #Read light sensor
print(light)
if light > 900: # Light sensor blocked
print('num:',num+1)
buzzer.setBuzzer(100) #Beep buzzer once
time.sleep_ms(500)
arm.set_position((0,-165,100),1200) #Move arm above pickup position and wait 2 seconds before picking up
time.sleep_ms(2000)
arm.set_position((0,-165,86),600) #Suction the color block
nozzle.on() # Turn on the pump
time.sleep_ms(1000)
arm.set_position((0,-165,180),1000) #Lift arm
time.sleep_ms(1000)
arm.set_position((120,-20-60*num,180),1500) # Move above placement position
nozzle.set_angle(angle[num],1500) #Set angle compensation to place block straight
time.sleep_ms(1500)
arm.set_position((120,-20-60*num,88),1000) #Place block
time.sleep_ms(1200)
nozzle.off() # Turn off the pump
arm.set_position((120,-20-60*num,200),1000) # Lift arm
time.sleep_ms(1000)
arm.go_home() #Reset arm to home position
nozzle.set_angle(0,1800) #Set nozzle angle to 0
time.sleep_ms(2000)
num += 1 #Increment block count
```
Take `setBuzze()` function, `set_position()` function, `Pump_on()` function and `go_home()` for example.
The `setBuzze()` is a function to control buzzer. Call "Buzzer.h" function in the same directory as "InfraredSensor_sorting.ino" program. Fill in the parentheses with the duration time of buzzer, and the unit is ms. The code `setBuzzer(100)` means that the buzzer will respond for 100ms after the infrared sensor detects an object, and then the next `set_potision()` function will be executed.
{lineno-start=35}
```python
buzzer.setBuzzer(100) #Beep buzzer once
```
The `set_position()` is a function to call robotic arm. Call **"ESPMax.h"** function in the same folder as **"LightSensor_put.ino"** program. Fill in the parentheses with the coordinate values and duration time. Take the code `set_position(pos,1500)` for example, `pos[0]`, `pos[1]`, `pos[2]` is the representative of the robot arm corresponding to the position on the XYZ axis, 1500 is the running time, the unit is milliseconds (ms). After that, the `Pump_on()` function is executed in the next step.
{lineno-start=}
```python
arm.set_position((0,-165,100),1200) #Move arm above pickup position and wait 2 seconds before picking up
```
The `nozzle.on()` function is used to turn on air pump while the `nozzle.off()` function to turn off air pump. Then proceed to execute `arm.go_home()` function.
{lineno-start=40}
```python
nozzle.on() # Turn on the pump
```
{lineno-start=49}
```python
nozzle.off() # Turn off the pump
```
{lineno-start=52}
```python
arm.go_home() #Reset arm to home position
```
The `go_home()` is a function to reset robotic arm. After turning off air pump, this function will be executed to get robot arm back to initial position. After that, the program will execute a function for 2000ms delay and then end the game and wait for the next recognition signal.
(5) Adjust Sensitivity
There is an adjustable potentiometer knob on light sensor for adjusting the measuring distance. When performing the related games, if the measurement effect it not good enough, the measurement sensitivity of sensor can be adjusted by adjusting the knob.
It is recommended to use phillips screwdriver. Rotate the knob clockwise, as the figure shown below, to increase the measurement distance; rotate it counterclockwise to decrease the measurement distance.
Please take notice of the following two tips:
① Since the warm light (incandescent light, sunlight, etc) contains more infrared component, there will be a certain interference the detection result. When using it, special attention should be paid to the surrounding environment. Therefore, you can not adjust the sensitivity alone.
② The sensitivity adjustment has is set a threshold, which you can regard it as a critical point. If the sensitivity exceeds the critical point, its value will return to the initial state.
③ Sensitivity adjustment needs to be based on the actual needs of the project. It is better to be adjusted to the most suitable conditions.