0

Soccer A robot - programming

Motors

Find

#define MOTOR_GROUP 0
program line where the number can be 0 but can also be some other. Change it into 0. That will define motors' usage for soccer. Run the MRMS_ESP32 Arduino program. After the menu is displayed, enter "mot" to test the motors. If You connected the motors according to the instructions, the motors will start in the clockwise order, starting from the first right (45 degrees) of the front of the robot. The front is identified by the ball's slot. If so, no action will be needed in this step. If not, You will have either to reconnect the motors or change this program line:
motorGroupStar = new MotorGroupStar(&mrm_bldc2x50, 0, &mrm_bldc2x50, 1, &mrm_bldc2x50, 2, &mrm_bldc2x50, 3);
Look at the parameters 0, 1, 2, and 3. They indicate motors' ordinal numbers. First (0) must be 45 degrees motor, second (1) 135 degrees motor, then -135 degrees, and finally -45 degrees. Change the numbers. For example, if You switched the controllers and now the first controller controls motors -135 and -45 degrees, instead 45 and 135 degrees, instead of parameters 0, 1, 2, and 3, write: 2, 3, 0, 1. If You chose the controllers' ordinal numbers correctly, but mixed up motors' outputs of the first controller, You will have to correct this by using parameters 2, 3, 1, and 2. It may be easier to change these numbers than to reconnect the motors as the wires hold tightly.

Check that all the motors in the "mot" test rotate first anticlockwise and then clockwise, looking from outside of the robot. If a motor rotates first clockwise and then anticlockwise, You will have to change its direction. Locate lines where directions are defined by identifying name of the motor controller and changing all the "-" characters into "_". For example, if Your driver is mrm-bldc2x50, the result will be mrm_bldc2x50. That is the program name for the board. Now find function

void initialize(){
...
}
and its lines where the board name is used. It will be something like

void initialize(){
...
	// Motors mrm-bldc2x50
	mrm_bldc2x50.add(false, "Mot2x50-1");
	mrm_bldc2x50.add(false, "Mot2x50-2");
	mrm_bldc2x50.add(false, "Mot2x50-3");
	mrm_bldc2x50.add(false, "Mot2x50-4");
...
}
The first argument "false" indicates if the rotation should be reversed. Change this parameter into "true" for all the motors You wish to change the rotation direction.

It is time to move the robot. Find function

void loop(){
...
}
and change it into
void loop(){
	go(20, 0);
}
Upload the program and start it with menu command "loo". The robot should be moving forwards. First argument of the function (20) is speed, second (0) heading. Change speed into 25 and heading into 90. Start the robot again. Now it should go to the right.

Lidars

If there is an obstacle on the way, the robot will hit it. That may not be desirable. Let's correct the behaviour. In menu choose command "li4" to test lidars. Put an obstacle in front of each lidar and watch measured distances in order to detect the one pointing to the right of the robot. The distances are displayed in 4 columns. First column is sensor number 0, second number 1, etc. Remember the ordinal number of the 90-degrees sensor. In this example, the number is 0. To get the distance from sensor 0, use function "front()". The result is in mm. If You wish the robot to stop moving 100 mm in front of the 90-degrees obstacle, use this program:

void loop(){
	if (front() ˃ 100)
		go(20, 0);
	else
		stop();
}

Reflectance sensors

You may also wish to stop the robot when it encounters a white stripe beneath. The program is similar to the one above. First start reflectance sensors test by entering "ref" command. The result will be something like

973 979 977 329 264 349 424 450 457 | 973 979 976 974 978 978 595 497 470 
974 979 977 329 263 348 425 450 458 | 973 979 976 974 977 978 595 497 471 
And so on. Before "|" is sensor number 0, after sensor number 1. Only first 5 numbers are significant as the same library is used for longer reflectance sensors. A bigger number means more reflected light. Check the number when there is a white stripe below and also when it is a dark surface. Find an average of the 2 values. For example the first column may read 400 for dark surface and 800 for a white stripe. In that case average is 600. Change the program again:
void loop(){
	if (brightness(0, 0) < 600)
		go(20, 0);
	else
		stop();
}
As there are more photo transistors in mrm-ref-can6 sensor, there are 2 arguments for brightness() function. First is sensor's ordinal number, the second transistor's. So, we used sensor number 0 and transistor number 0. If its value is smaller than 600 (dar), the robot will continue its motion. If not, it will stop.

Ball

Soccer robot should be able to go towards an active RCJ ball so lets do that. Locate the line

mrm_ir_finder2.add(34, 33);
First argument (34) is angle pin, second (33) distance pin. Angle pin should be connected to "DEG" output of MRMS IR ball finder 2, direction + distance (mrm-ir-finder2), distance to "CM"pin. Look at the schematics of the MRMS ESP32: Arduino, IMU, eFuse, BT, WiFi, CAN Bus (mrm-esp32) to find the mentioned pins ("IO34" and "IO35").

Turn an active RCJ ball on and check the sensor. If You do not have a ball, use a TV remote controller. Issue command "irf". The output should look like

Angle:  -79º, distance: 1702.
Angle:  -91º, distance: 1776.
Angle:  -65º, distance: 1712.
Angle:  -27º, distance: 1703.

Change our function loop() into

void loop(){
	if (mrm_ir_finder2->anyIRSource())
		go(15, mrm_ir_finder2->irSource().angle);
	else
		stop();
}
mrm_ir_finder2 is our sensor. mrm_ir_finder2->anyIRSource() tells the program if any IR ball is detected. If it is, the command in the next line will be executed and that one will move robot towards the ball. As we learned above, second argument of function go() is heading. In this case it will be mrm_ir_finder2->irSource().angle, the direction of the detected ball. If no IR source is detected, the robot will stop.

Line

In RCJ Soccer, the most important quality of the robot is its ability to avoid crossing white lines. If You do not achieve this goal, all the other efforts will be in vain.

How to recognize that Your program is not good in the first place? There are 2 reliable signs:

  1. Usage of delay() function. This evil function deprives Your robot of all the valuable sensory information for a long time. Many things can and do happen. For example, a naive strategy would be to go in the opposite direction of the input one for delay(500) time. What if there is another robot in the escape direction? Your robot will not be moving (and no sensor will tell You that). After delay(500) expires, the robot will sense the line again and start moving in the opposite direction. However, the direction now may well be right out of the playfield. As there is no obstacle in that direction, the robot will happily be moving delay(500), successfully exiting the playfield, and making You sad.
  2. A stress test fails: put a single robot in the arena, position a ball in various points out of the field bounds, and let it stay there for 10 seconds. If the robot exits the playfield even once, Your program is no good. In this ideal conditions no mistakes are allowed. In a real game the conditions will be much harsher so passing this test is not sufficient but it is mandatory.

Some strategy hints:

  • Use 4 distance sensors.
    1. If 4 distance sensors read more than some limit, say 30 cm, do not avoid line. There was an error reading the line as there has to be some obstacle otherwise.
    2. If 3 sensors show more than 30 cm (and the others not), go in the direction of the middle one.
    3. If 2 adjacent sensors show free space, go diagonally between them.
    4. If 2 opposite sensors show free space, stay where You are.
    5. If 1 side sensor reads more than 30 cm, go in that direction.
    6. If 1 front or back sensor reads more than 30 cm, this strategy alone will not help You.
  • Extract as many information from line sensors as possible. This is a preferred solution. Track the movements: if the outermost transistor of the left line sensor notices the line first, this must be the last sensor sensing it, and only that concludes a successful end of the maneuver. Therefore, the sequence could be: first the left, 2nd, 3rd, 4th, 4th, 3rd, 2nd, 1st, and that is the end. You will have to allow some slack as You may miss some readings. So, 1st, 2nd, 4th, 1st may still be fine. The more slack You allow, the more risk You will be facing. There are some more complicated cases, when more sensors detect the line, like front and left one. Study each possibility.
  • If You tried avoiding the line, without luck, and neither the ball moved, nor the distances changed, do not try avoiding again. Stay put until the situation changes.

Line sensors are extremely fast and report their values to the ARM MCU in, at least, 1 mm resolution. CAN Bus messages are slower. If You send messages (You can change this is ARM firmware!) every 5 ms, and Your robot travels up to 1 m/s, resolution will be 5 mm what may be acceptable. If not, You can put some logic into the firmware. A simpler solution is to have properly calibrated sensors. Write a routine that calibrates all of them before the game. Spin the robot over a white border line once, records maximums and minimums for all the transistors of every line sensor and store them. Now, if You want to know if a transistor detected a white line, ask if its current value is bigger than its (minimumValue + maximumValue) / 2. Never assume that one limit value is valid for all the sensors. Each phototransistor has different characteristics and they are not aligned perfectly.

How about a confirmation that You solved the problem? The only way is to play 2 on 2 as much as possible as only here weaknesses of Your strategy will be exposed. Forget about some fancy features till You pass this test. A kicker is no good if Your robots are out of the game.

Switch

Switches are useful for frequent operations, like starting or calibrating the robot. ML-R offers switches over CAN Bus, by using ML-R 8x8 bicolor display, CAN Bus,UART, 4 switches (mrm-8x8a), or switches connected directly to ESP32 input pins, by using ML-R switch 2x (mrm-switch) or ML-R LEDs Switches (mrm-leds).

An example for ML-R switch 2x (mrm-switch) follows. Connect the switch board to 3.3 V (red pin), GND (black pin), and to ESP32 18 and 19 pins (2 white pins).

Define commands that are to be executed after pressing the 2 switches in function initialize():

void initialize(){
	...
	// Switch
	mrm_switch->add(18, 19, "Switch");
	mrm_switch->actionSet(&commandLoop, 0);
	mrm_switch->actionSet(&commandStop, 1);
	...
}
Therefore, after pressing switch connected to pin 18, new robot's state will be commandLoop and appropriate action will follow (function loop()). By pressing the other switch, connected to pin 19, the new state will be commandStop and its function (commandStopAll()) will stop everything.

Work in progress

This program has not been completed yet.